MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 012732 0ustar000000000 0000000 NOTICE0100644 0000000 0000000 00000042420 13077405420 010515 0ustar000000000 0000000 ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for the Android-specific code. == ========================================================================= Android Code Copyright 2005-2008 The Android Open Source Project This product includes software developed as part of The Android Open Source Project (http://source.android.com). ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for Apache Commons code. == ========================================================================= Apache Commons Copyright 1999-2006 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for Jakarta Commons Logging. == ========================================================================= Jakarta Commons Logging (JCL) Copyright 2005,2006 The Apache Software Foundation. This product includes software developed at The Apache Software Foundation (http://www.apache.org/). ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for the Nuance code. == ========================================================================= These files are Copyright 2007 Nuance Communications, but released under the Apache2 License. ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for the Media Codecs code. == ========================================================================= Media Codecs These files are Copyright 1998 - 2009 PacketVideo, but released under the Apache2 License. ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for the TagSoup code. == ========================================================================= This file is part of TagSoup and is Copyright 2002-2008 by John Cowan. TagSoup is licensed under the Apache License, Version 2.0. You may obtain a copy of this license at http://www.apache.org/licenses/LICENSE-2.0 . You may also have additional legal rights not granted by this license. TagSoup is distributed in the hope that it will be useful, but unless required by applicable law or agreed to in writing, TagSoup is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied; not even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for Additional Codecs code. == ========================================================================= Additional Codecs These files are Copyright 2003-2010 VisualOn, but released under the Apache2 License. ========================================================================= == NOTICE file corresponding to the section 4 d of == == the Apache License, Version 2.0, == == in this case for the Audio Effects code. == ========================================================================= Audio Effects These files are Copyright (C) 2004-2010 NXP Software and Copyright (C) 2010 The Android Open Source Project, but released under the Apache2 License. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/ . Unicode Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. COPYRIGHT AND PERMISSION NOTICE Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. aidl/0040755 0000000 0000000 00000000000 13077405420 010523 5ustar000000000 0000000 aidl/binder/0040755 0000000 0000000 00000000000 13077405420 011766 5ustar000000000 0000000 aidl/binder/android/0040755 0000000 0000000 00000000000 13077405420 013406 5ustar000000000 0000000 aidl/binder/android/os/0040755 0000000 0000000 00000000000 13077405420 014027 5ustar000000000 0000000 aidl/binder/android/os/PersistableBundle.aidl0100644 0000000 0000000 00000001306 13077405420 020266 0ustar000000000 0000000 /* ** ** Copyright 2014, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ package android.os; parcelable PersistableBundle cpp_header "binder/PersistableBundle.h"; aidl/gui/0040755 0000000 0000000 00000000000 13077405420 011307 5ustar000000000 0000000 aidl/gui/android/0040755 0000000 0000000 00000000000 13077405420 012727 5ustar000000000 0000000 aidl/gui/android/view/0040755 0000000 0000000 00000000000 13077405420 013701 5ustar000000000 0000000 aidl/gui/android/view/Surface.aidl0100644 0000000 0000000 00000001341 13077405420 016120 0ustar000000000 0000000 /* //device/java/android/android/view/Surface.aidl ** ** Copyright 2007, 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.view; parcelable Surface cpp_header "gui/Surface.h"; build/0040755 0000000 0000000 00000000000 13077405420 010711 5ustar000000000 0000000 build/phone-hdpi-512-dalvik-heap.mk0100644 0000000 0000000 00000001675 13077405420 015773 0ustar000000000 0000000 # # Copyright (C) 2010 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. # # Provides overrides to configure the Dalvik heap for a standard high density # phone with around 512MB total RAM. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=5m \ dalvik.vm.heapgrowthlimit=48m \ dalvik.vm.heapsize=128m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=2m build/phone-hdpi-dalvik-heap.mk0100644 0000000 0000000 00000001572 13077405420 015462 0ustar000000000 0000000 # # Copyright (C) 2010 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. # # Provides overrides to configure the Dalvik heap for a standard high density phone. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=5m \ dalvik.vm.heapsize=32m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=2m build/phone-xhdpi-1024-dalvik-heap.mk0100644 0000000 0000000 00000001616 13077405420 016235 0ustar000000000 0000000 # # 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. # # Provides overrides to configure the Dalvik heap for a xhdpi phone PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=8m \ dalvik.vm.heapgrowthlimit=96m \ dalvik.vm.heapsize=256m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=8m build/phone-xhdpi-2048-dalvik-heap.mk0100644 0000000 0000000 00000001726 13077405420 016246 0ustar000000000 0000000 # # Copyright (C) 2012 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. # # Provides overrides to configure the Dalvik heap for a 2G phone # 192m of RAM gives enough space for 5 8 megapixel camera bitmaps in RAM. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=8m \ dalvik.vm.heapgrowthlimit=192m \ dalvik.vm.heapsize=512m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=8m build/tablet-10in-xhdpi-2048-dalvik-heap.mk0100644 0000000 0000000 00000001634 13077405420 017153 0ustar000000000 0000000 # # Copyright (C) 2012 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. # # Provides overrides to configure the Dalvik heap for a standard tablet device. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=16m \ dalvik.vm.heapgrowthlimit=192m \ dalvik.vm.heapsize=512m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=8m build/tablet-7in-hdpi-1024-dalvik-heap.mk0100644 0000000 0000000 00000001632 13077405420 016700 0ustar000000000 0000000 # # Copyright (C) 2010 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. # # Provides overrides to configure the Dalvik heap for a standard tablet device. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=8m \ dalvik.vm.heapgrowthlimit=80m \ dalvik.vm.heapsize=384m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=8m build/tablet-7in-xhdpi-2048-dalvik-heap.mk0100644 0000000 0000000 00000001635 13077405420 017102 0ustar000000000 0000000 # # Copyright (C) 2013 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. # # Provides overrides to configure the Dalvik heap for a 320dpi 7" tablet device. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=16m \ dalvik.vm.heapgrowthlimit=192m \ dalvik.vm.heapsize=512m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=8m build/tablet-dalvik-heap.mk0100644 0000000 0000000 00000001632 13077405420 014677 0ustar000000000 0000000 # # Copyright (C) 2010 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. # # Provides overrides to configure the Dalvik heap for a standard tablet device. PRODUCT_PROPERTY_OVERRIDES += \ dalvik.vm.heapstartsize=5m \ dalvik.vm.heapgrowthlimit=48m \ dalvik.vm.heapsize=256m \ dalvik.vm.heaptargetutilization=0.75 \ dalvik.vm.heapminfree=512k \ dalvik.vm.heapmaxfree=2m cmds/0040755 0000000 0000000 00000000000 13077405420 010540 5ustar000000000 0000000 cmds/atrace/0040755 0000000 0000000 00000000000 13077405420 011777 5ustar000000000 0000000 cmds/atrace/Android.mk0100644 0000000 0000000 00000000552 13077405420 013707 0ustar000000000 0000000 # Copyright 2012 The Android Open Source Project LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= atrace.cpp LOCAL_C_INCLUDES += external/zlib LOCAL_MODULE:= atrace LOCAL_MODULE_TAGS:= optional LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libutils \ libz \ LOCAL_INIT_RC := atrace.rc include $(BUILD_EXECUTABLE) cmds/atrace/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 015117 0ustar000000000 0000000 cmds/atrace/NOTICE0100644 0000000 0000000 00000024702 13077405420 012705 0ustar000000000 0000000 Copyright (c) 2012, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS cmds/atrace/atrace.cpp0100644 0000000 0000000 00000114206 13077405420 013743 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "atrace" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #define MAX_SYS_FILES 10 #define MAX_PACKAGES 16 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags"; const char* k_traceAppsNumberProperty = "debug.atrace.app_number"; const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d"; const char* k_coreServiceCategory = "core_services"; const char* k_coreServicesProp = "ro.atrace.core.services"; typedef enum { OPT, REQ } requiredness ; struct TracingCategory { // The name identifying the category. const char* name; // A longer description of the category. const char* longname; // The userland tracing tags that the category enables. uint64_t tags; // The fname==NULL terminated list of /sys/ files that the category // enables. struct { // Whether the file must be writable in order to enable the tracing // category. requiredness required; // The path to the enable file. const char* path; } sysfiles[MAX_SYS_FILES]; }; /* Tracing categories */ static const TracingCategory k_categories[] = { { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } }, { "input", "Input", ATRACE_TAG_INPUT, { } }, { "view", "View System", ATRACE_TAG_VIEW, { } }, { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } }, { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } }, { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } }, { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } }, { "audio", "Audio", ATRACE_TAG_AUDIO, { } }, { "video", "Video", ATRACE_TAG_VIDEO, { } }, { "camera", "Camera", ATRACE_TAG_CAMERA, { } }, { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } }, { "app", "Application", ATRACE_TAG_APP, { } }, { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } }, { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } }, { "rs", "RenderScript", ATRACE_TAG_RS, { } }, { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } }, { "power", "Power Management", ATRACE_TAG_POWER, { } }, { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } }, { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } }, { "database", "Database", ATRACE_TAG_DATABASE, { } }, { k_coreServiceCategory, "Core services", 0, { } }, { "sched", "CPU Scheduling", 0, { { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" }, { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" }, { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" }, { OPT, "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" }, } }, { "irq", "IRQ Events", 0, { { REQ, "/sys/kernel/debug/tracing/events/irq/enable" }, { OPT, "/sys/kernel/debug/tracing/events/ipi/enable" }, } }, { "freq", "CPU Frequency", 0, { { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" }, { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" }, { OPT, "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" }, } }, { "membus", "Memory Bus Utilization", 0, { { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" }, } }, { "idle", "CPU Idle", 0, { { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" }, } }, { "disk", "Disk I/O", 0, { { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" }, { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" }, { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" }, { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" }, { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" }, { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" }, { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" }, { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" }, { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" }, { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" }, } }, { "mmc", "eMMC commands", 0, { { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" }, } }, { "load", "CPU Load", 0, { { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" }, } }, { "sync", "Synchronization", 0, { { REQ, "/sys/kernel/debug/tracing/events/sync/enable" }, } }, { "workq", "Kernel Workqueues", 0, { { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" }, } }, { "memreclaim", "Kernel Memory Reclaim", 0, { { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" }, { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" }, { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" }, { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" }, } }, { "regulators", "Voltage and Current Regulators", 0, { { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" }, } }, { "binder_driver", "Binder Kernel driver", 0, { { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" }, { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" }, } }, { "binder_lock", "Binder global lock trace", 0, { { REQ, "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" }, { REQ, "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" }, { REQ, "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" }, } }, { "pagecache", "Page cache", 0, { { REQ, "/sys/kernel/debug/tracing/events/filemap/enable" }, } }, }; /* Command line options */ static int g_traceDurationSeconds = 5; static bool g_traceOverwrite = false; static int g_traceBufferSizeKB = 2048; static bool g_compress = false; static bool g_nohup = false; static int g_initialSleepSecs = 0; static const char* g_categoriesFile = NULL; static const char* g_kernelTraceFuncs = NULL; static const char* g_debugAppCmdLine = ""; static const char* g_outputFile = nullptr; /* Global state */ static bool g_traceAborted = false; static bool g_categoryEnables[NELEM(k_categories)] = {}; /* Sys file paths */ static const char* k_traceClockPath = "/sys/kernel/debug/tracing/trace_clock"; static const char* k_traceBufferSizePath = "/sys/kernel/debug/tracing/buffer_size_kb"; static const char* k_tracingOverwriteEnablePath = "/sys/kernel/debug/tracing/options/overwrite"; static const char* k_currentTracerPath = "/sys/kernel/debug/tracing/current_tracer"; static const char* k_printTgidPath = "/sys/kernel/debug/tracing/options/print-tgid"; static const char* k_funcgraphAbsTimePath = "/sys/kernel/debug/tracing/options/funcgraph-abstime"; static const char* k_funcgraphCpuPath = "/sys/kernel/debug/tracing/options/funcgraph-cpu"; static const char* k_funcgraphProcPath = "/sys/kernel/debug/tracing/options/funcgraph-proc"; static const char* k_funcgraphFlatPath = "/sys/kernel/debug/tracing/options/funcgraph-flat"; static const char* k_funcgraphDurationPath = "/sys/kernel/debug/tracing/options/funcgraph-duration"; static const char* k_ftraceFilterPath = "/sys/kernel/debug/tracing/set_ftrace_filter"; static const char* k_tracingOnPath = "/sys/kernel/debug/tracing/tracing_on"; static const char* k_tracePath = "/sys/kernel/debug/tracing/trace"; static const char* k_traceStreamPath = "/sys/kernel/debug/tracing/trace_pipe"; static const char* k_traceMarkerPath = "/sys/kernel/debug/tracing/trace_marker"; // Check whether a file exists. static bool fileExists(const char* filename) { return access(filename, F_OK) != -1; } // Check whether a file is writable. static bool fileIsWritable(const char* filename) { return access(filename, W_OK) != -1; } // Truncate a file. static bool truncateFile(const char* path) { // This uses creat rather than truncate because some of the debug kernel // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by // calls to truncate, but they are cleared by calls to creat. int traceFD = creat(path, 0); if (traceFD == -1) { fprintf(stderr, "error truncating %s: %s (%d)\n", path, strerror(errno), errno); return false; } close(traceFD); return true; } static bool _writeStr(const char* filename, const char* str, int flags) { int fd = open(filename, flags); if (fd == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", filename, strerror(errno), errno); return false; } bool ok = true; ssize_t len = strlen(str); if (write(fd, str, len) != len) { fprintf(stderr, "error writing to %s: %s (%d)\n", filename, strerror(errno), errno); ok = false; } close(fd); return ok; } // Write a string to a file, returning true if the write was successful. static bool writeStr(const char* filename, const char* str) { return _writeStr(filename, str, O_WRONLY); } // Append a string to a file, returning true if the write was successful. static bool appendStr(const char* filename, const char* str) { return _writeStr(filename, str, O_APPEND|O_WRONLY); } static void writeClockSyncMarker() { char buffer[128]; int len = 0; int fd = open(k_traceMarkerPath, O_WRONLY); if (fd == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath, strerror(errno), errno); return; } float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f; len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds); if (write(fd, buffer, len) != len) { fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno); } int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000; len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms); if (write(fd, buffer, len) != len) { fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno); } close(fd); } // Enable or disable a kernel option by writing a "1" or a "0" into a /sys // file. static bool setKernelOptionEnable(const char* filename, bool enable) { return writeStr(filename, enable ? "1" : "0"); } // Check whether the category is supported on the device with the current // rootness. A category is supported only if all its required /sys/ files are // writable and if enabling the category will enable one or more tracing tags // or /sys/ files. static bool isCategorySupported(const TracingCategory& category) { if (strcmp(category.name, k_coreServiceCategory) == 0) { char value[PROPERTY_VALUE_MAX]; property_get(k_coreServicesProp, value, ""); return strlen(value) != 0; } bool ok = category.tags != 0; for (int i = 0; i < MAX_SYS_FILES; i++) { const char* path = category.sysfiles[i].path; bool req = category.sysfiles[i].required == REQ; if (path != NULL) { if (req) { if (!fileIsWritable(path)) { return false; } else { ok = true; } } else { ok |= fileIsWritable(path); } } } return ok; } // Check whether the category would be supported on the device if the user // were root. This function assumes that root is able to write to any file // that exists. It performs the same logic as isCategorySupported, but it // uses file existance rather than writability in the /sys/ file checks. static bool isCategorySupportedForRoot(const TracingCategory& category) { bool ok = category.tags != 0; for (int i = 0; i < MAX_SYS_FILES; i++) { const char* path = category.sysfiles[i].path; bool req = category.sysfiles[i].required == REQ; if (path != NULL) { if (req) { if (!fileExists(path)) { return false; } else { ok = true; } } else { ok |= fileExists(path); } } } return ok; } // Enable or disable overwriting of the kernel trace buffers. Disabling this // will cause tracing to stop once the trace buffers have filled up. static bool setTraceOverwriteEnable(bool enable) { return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable); } // Enable or disable kernel tracing. static bool setTracingEnabled(bool enable) { return setKernelOptionEnable(k_tracingOnPath, enable); } // Clear the contents of the kernel trace. static bool clearTrace() { return truncateFile(k_tracePath); } // Set the size of the kernel's trace buffer in kilobytes. static bool setTraceBufferSizeKB(int size) { char str[32] = "1"; int len; if (size < 1) { size = 1; } snprintf(str, 32, "%d", size); return writeStr(k_traceBufferSizePath, str); } // Read the trace_clock sysfs file and return true if it matches the requested // value. The trace_clock file format is: // local [global] counter uptime perf static bool isTraceClock(const char *mode) { int fd = open(k_traceClockPath, O_RDONLY); if (fd == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath, strerror(errno), errno); return false; } char buf[4097]; ssize_t n = read(fd, buf, 4096); close(fd); if (n == -1) { fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath, strerror(errno), errno); return false; } buf[n] = '\0'; char *start = strchr(buf, '['); if (start == NULL) { return false; } start++; char *end = strchr(start, ']'); if (end == NULL) { return false; } *end = '\0'; return strcmp(mode, start) == 0; } // Enable or disable the kernel's use of the global clock. Disabling the global // clock will result in the kernel using a per-CPU local clock. // Any write to the trace_clock sysfs file will reset the buffer, so only // update it if the requested value is not the current value. static bool setGlobalClockEnable(bool enable) { const char *clock = enable ? "global" : "local"; if (isTraceClock(clock)) { return true; } return writeStr(k_traceClockPath, clock); } static bool setPrintTgidEnableIfPresent(bool enable) { if (fileExists(k_printTgidPath)) { return setKernelOptionEnable(k_printTgidPath, enable); } return true; } // Poke all the binder-enabled processes in the system to get them to re-read // their system properties. static bool pokeBinderServices() { sp sm = defaultServiceManager(); Vector services = sm->listServices(); for (size_t i = 0; i < services.size(); i++) { sp obj = sm->checkService(services[i]); if (obj != NULL) { Parcel data; if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data, NULL, 0) != OK) { if (false) { // XXX: For some reason this fails on tablets trying to // poke the "phone" service. It's not clear whether some // are expected to fail. String8 svc(services[i]); fprintf(stderr, "error poking binder service %s\n", svc.string()); return false; } } } } return true; } // Set the trace tags that userland tracing uses, and poke the running // processes to pick up the new value. static bool setTagsProperty(uint64_t tags) { char buf[PROPERTY_VALUE_MAX]; snprintf(buf, sizeof(buf), "%#" PRIx64, tags); if (property_set(k_traceTagsProperty, buf) < 0) { fprintf(stderr, "error setting trace tags system property\n"); return false; } return true; } static void clearAppProperties() { char buf[PROPERTY_KEY_MAX]; for (int i = 0; i < MAX_PACKAGES; i++) { snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i); if (property_set(buf, "") < 0) { fprintf(stderr, "failed to clear system property: %s\n", buf); } } if (property_set(k_traceAppsNumberProperty, "") < 0) { fprintf(stderr, "failed to clear system property: %s", k_traceAppsNumberProperty); } } // Set the system property that indicates which apps should perform // application-level tracing. static bool setAppCmdlineProperty(const char* cmdline) { char buf[PROPERTY_KEY_MAX]; int i = 0; const char* start = cmdline; while (start != NULL) { if (i == MAX_PACKAGES) { fprintf(stderr, "error: only 16 packages could be traced at once\n"); clearAppProperties(); return false; } char* end = strchr(start, ','); if (end != NULL) { *end = '\0'; end++; } snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i); if (property_set(buf, start) < 0) { fprintf(stderr, "error setting trace app %d property to %s\n", i, buf); clearAppProperties(); return false; } start = end; i++; } snprintf(buf, sizeof(buf), "%d", i); if (property_set(k_traceAppsNumberProperty, buf) < 0) { fprintf(stderr, "error setting trace app number property to %s\n", buf); clearAppProperties(); return false; } return true; } // Disable all /sys/ enable files. static bool disableKernelTraceEvents() { bool ok = true; for (int i = 0; i < NELEM(k_categories); i++) { const TracingCategory &c = k_categories[i]; for (int j = 0; j < MAX_SYS_FILES; j++) { const char* path = c.sysfiles[j].path; if (path != NULL && fileIsWritable(path)) { ok &= setKernelOptionEnable(path, false); } } } return ok; } // Verify that the comma separated list of functions are being traced by the // kernel. static bool verifyKernelTraceFuncs(const char* funcs) { int fd = open(k_ftraceFilterPath, O_RDONLY); if (fd == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath, strerror(errno), errno); return false; } char buf[4097]; ssize_t n = read(fd, buf, 4096); close(fd); if (n == -1) { fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath, strerror(errno), errno); return false; } buf[n] = '\0'; String8 funcList = String8::format("\n%s", buf); // Make sure that every function listed in funcs is in the list we just // read from the kernel, except for wildcard inputs. bool ok = true; char* myFuncs = strdup(funcs); char* func = strtok(myFuncs, ","); while (func) { if (!strchr(func, '*')) { String8 fancyFunc = String8::format("\n%s\n", func); bool found = funcList.find(fancyFunc.string(), 0) >= 0; if (!found || func[0] == '\0') { fprintf(stderr, "error: \"%s\" is not a valid kernel function " "to trace.\n", func); ok = false; } } func = strtok(NULL, ","); } free(myFuncs); return ok; } // Set the comma separated list of functions that the kernel is to trace. static bool setKernelTraceFuncs(const char* funcs) { bool ok = true; if (funcs == NULL || funcs[0] == '\0') { // Disable kernel function tracing. if (fileIsWritable(k_currentTracerPath)) { ok &= writeStr(k_currentTracerPath, "nop"); } if (fileIsWritable(k_ftraceFilterPath)) { ok &= truncateFile(k_ftraceFilterPath); } } else { // Enable kernel function tracing. ok &= writeStr(k_currentTracerPath, "function_graph"); ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true); ok &= setKernelOptionEnable(k_funcgraphCpuPath, true); ok &= setKernelOptionEnable(k_funcgraphProcPath, true); ok &= setKernelOptionEnable(k_funcgraphFlatPath, true); // Set the requested filter functions. ok &= truncateFile(k_ftraceFilterPath); char* myFuncs = strdup(funcs); char* func = strtok(myFuncs, ","); while (func) { ok &= appendStr(k_ftraceFilterPath, func); func = strtok(NULL, ","); } free(myFuncs); // Verify that the set functions are being traced. if (ok) { ok &= verifyKernelTraceFuncs(funcs); } } return ok; } static bool setCategoryEnable(const char* name, bool enable) { for (int i = 0; i < NELEM(k_categories); i++) { const TracingCategory& c = k_categories[i]; if (strcmp(name, c.name) == 0) { if (isCategorySupported(c)) { g_categoryEnables[i] = enable; return true; } else { if (isCategorySupportedForRoot(c)) { fprintf(stderr, "error: category \"%s\" requires root " "privileges.\n", name); } else { fprintf(stderr, "error: category \"%s\" is not supported " "on this device.\n", name); } return false; } } } fprintf(stderr, "error: unknown tracing category \"%s\"\n", name); return false; } static bool setCategoriesEnableFromFile(const char* categories_file) { if (!categories_file) { return true; } Tokenizer* tokenizer = NULL; if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) { return false; } bool ok = true; while (!tokenizer->isEol()) { String8 token = tokenizer->nextToken(" "); if (token.isEmpty()) { tokenizer->skipDelimiters(" "); continue; } ok &= setCategoryEnable(token.string(), true); } delete tokenizer; return ok; } // Set all the kernel tracing settings to the desired state for this trace // capture. static bool setUpTrace() { bool ok = true; // Set up the tracing options. ok &= setCategoriesEnableFromFile(g_categoriesFile); ok &= setTraceOverwriteEnable(g_traceOverwrite); ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); ok &= setGlobalClockEnable(true); ok &= setPrintTgidEnableIfPresent(true); ok &= setKernelTraceFuncs(g_kernelTraceFuncs); // Set up the tags property. uint64_t tags = 0; for (int i = 0; i < NELEM(k_categories); i++) { if (g_categoryEnables[i]) { const TracingCategory &c = k_categories[i]; tags |= c.tags; } } ok &= setTagsProperty(tags); bool coreServicesTagEnabled = false; for (int i = 0; i < NELEM(k_categories); i++) { if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) { coreServicesTagEnabled = g_categoryEnables[i]; } } std::string packageList(g_debugAppCmdLine); if (coreServicesTagEnabled) { char value[PROPERTY_VALUE_MAX]; property_get(k_coreServicesProp, value, ""); if (!packageList.empty()) { packageList += ","; } packageList += value; } ok &= setAppCmdlineProperty(packageList.data()); ok &= pokeBinderServices(); // Disable all the sysfs enables. This is done as a separate loop from // the enables to allow the same enable to exist in multiple categories. ok &= disableKernelTraceEvents(); // Enable all the sysfs enables that are in an enabled category. for (int i = 0; i < NELEM(k_categories); i++) { if (g_categoryEnables[i]) { const TracingCategory &c = k_categories[i]; for (int j = 0; j < MAX_SYS_FILES; j++) { const char* path = c.sysfiles[j].path; bool required = c.sysfiles[j].required == REQ; if (path != NULL) { if (fileIsWritable(path)) { ok &= setKernelOptionEnable(path, true); } else if (required) { fprintf(stderr, "error writing file %s\n", path); ok = false; } } } } } return ok; } // Reset all the kernel tracing settings to their default state. static void cleanUpTrace() { // Disable all tracing that we're able to. disableKernelTraceEvents(); // Reset the system properties. setTagsProperty(0); clearAppProperties(); pokeBinderServices(); // Set the options back to their defaults. setTraceOverwriteEnable(true); setTraceBufferSizeKB(1); setGlobalClockEnable(false); setPrintTgidEnableIfPresent(false); setKernelTraceFuncs(NULL); } // Enable tracing in the kernel. static bool startTrace() { return setTracingEnabled(true); } // Disable tracing in the kernel. static void stopTrace() { setTracingEnabled(false); } // Read data from the tracing pipe and forward to stdout static void streamTrace() { char trace_data[4096]; int traceFD = open(k_traceStreamPath, O_RDWR); if (traceFD == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath, strerror(errno), errno); return; } while (!g_traceAborted) { ssize_t bytes_read = read(traceFD, trace_data, 4096); if (bytes_read > 0) { write(STDOUT_FILENO, trace_data, bytes_read); fflush(stdout); } else { if (!g_traceAborted) { fprintf(stderr, "read returned %zd bytes err %d (%s)\n", bytes_read, errno, strerror(errno)); } break; } } } // Read the current kernel trace and write it to stdout. static void dumpTrace(int outFd) { ALOGI("Dumping trace"); int traceFD = open(k_tracePath, O_RDWR); if (traceFD == -1) { fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath, strerror(errno), errno); return; } if (g_compress) { z_stream zs; uint8_t *in, *out; int result, flush; memset(&zs, 0, sizeof(zs)); result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); if (result != Z_OK) { fprintf(stderr, "error initializing zlib: %d\n", result); close(traceFD); return; } const size_t bufSize = 64*1024; in = (uint8_t*)malloc(bufSize); out = (uint8_t*)malloc(bufSize); flush = Z_NO_FLUSH; zs.next_out = out; zs.avail_out = bufSize; do { if (zs.avail_in == 0) { // More input is needed. result = read(traceFD, in, bufSize); if (result < 0) { fprintf(stderr, "error reading trace: %s (%d)\n", strerror(errno), errno); result = Z_STREAM_END; break; } else if (result == 0) { flush = Z_FINISH; } else { zs.next_in = in; zs.avail_in = result; } } if (zs.avail_out == 0) { // Need to write the output. result = write(outFd, out, bufSize); if ((size_t)result < bufSize) { fprintf(stderr, "error writing deflated trace: %s (%d)\n", strerror(errno), errno); result = Z_STREAM_END; // skip deflate error message zs.avail_out = bufSize; // skip the final write break; } zs.next_out = out; zs.avail_out = bufSize; } } while ((result = deflate(&zs, flush)) == Z_OK); if (result != Z_STREAM_END) { fprintf(stderr, "error deflating trace: %s\n", zs.msg); } if (zs.avail_out < bufSize) { size_t bytes = bufSize - zs.avail_out; result = write(outFd, out, bytes); if ((size_t)result < bytes) { fprintf(stderr, "error writing deflated trace: %s (%d)\n", strerror(errno), errno); } } result = deflateEnd(&zs); if (result != Z_OK) { fprintf(stderr, "error cleaning up zlib: %d\n", result); } free(in); free(out); } else { ssize_t sent = 0; while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0); if (sent == -1) { fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno), errno); } } close(traceFD); } static void handleSignal(int /*signo*/) { if (!g_nohup) { g_traceAborted = true; } } static void registerSigHandler() { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handleSignal; sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); } static void listSupportedCategories() { for (int i = 0; i < NELEM(k_categories); i++) { const TracingCategory& c = k_categories[i]; if (isCategorySupported(c)) { printf(" %10s - %s\n", c.name, c.longname); } } } // Print the command usage help to stderr. static void showHelp(const char *cmd) { fprintf(stderr, "usage: %s [options] [categories...]\n", cmd); fprintf(stderr, "options include:\n" " -a appname enable app-level tracing for a comma " "separated list of cmdlines\n" " -b N use a trace buffer size of N KB\n" " -c trace into a circular buffer\n" " -f filename use the categories written in a file as space-separated\n" " values in a line\n" " -k fname,... trace the listed kernel functions\n" " -n ignore signals\n" " -s N sleep for N seconds before tracing [default 0]\n" " -t N trace for N seconds [defualt 5]\n" " -z compress the trace dump\n" " --async_start start circular trace and return immediatly\n" " --async_dump dump the current contents of circular trace buffer\n" " --async_stop stop tracing and dump the current contents of circular\n" " trace buffer\n" " --stream stream trace to stdout as it enters the trace buffer\n" " Note: this can take significant CPU time, and is best\n" " used for measuring things that are not affected by\n" " CPU performance, like pagecache usage.\n" " --list_categories\n" " list the available tracing categories\n" " -o filename write the trace to the specified file instead\n" " of stdout.\n" ); } int main(int argc, char **argv) { bool async = false; bool traceStart = true; bool traceStop = true; bool traceDump = true; bool traceStream = false; if (argc == 2 && 0 == strcmp(argv[1], "--help")) { showHelp(argv[0]); exit(0); } for (;;) { int ret; int option_index = 0; static struct option long_options[] = { {"async_start", no_argument, 0, 0 }, {"async_stop", no_argument, 0, 0 }, {"async_dump", no_argument, 0, 0 }, {"list_categories", no_argument, 0, 0 }, {"stream", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:", long_options, &option_index); if (ret < 0) { for (int i = optind; i < argc; i++) { if (!setCategoryEnable(argv[i], true)) { fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]); exit(1); } } break; } switch(ret) { case 'a': g_debugAppCmdLine = optarg; break; case 'b': g_traceBufferSizeKB = atoi(optarg); break; case 'c': g_traceOverwrite = true; break; case 'f': g_categoriesFile = optarg; break; case 'k': g_kernelTraceFuncs = optarg; break; case 'n': g_nohup = true; break; case 's': g_initialSleepSecs = atoi(optarg); break; case 't': g_traceDurationSeconds = atoi(optarg); break; case 'z': g_compress = true; break; case 'o': g_outputFile = optarg; break; case 0: if (!strcmp(long_options[option_index].name, "async_start")) { async = true; traceStop = false; traceDump = false; g_traceOverwrite = true; } else if (!strcmp(long_options[option_index].name, "async_stop")) { async = true; traceStart = false; } else if (!strcmp(long_options[option_index].name, "async_dump")) { async = true; traceStart = false; traceStop = false; } else if (!strcmp(long_options[option_index].name, "stream")) { traceStream = true; traceDump = false; } else if (!strcmp(long_options[option_index].name, "list_categories")) { listSupportedCategories(); exit(0); } break; default: fprintf(stderr, "\n"); showHelp(argv[0]); exit(-1); break; } } registerSigHandler(); if (g_initialSleepSecs > 0) { sleep(g_initialSleepSecs); } bool ok = true; ok &= setUpTrace(); ok &= startTrace(); if (ok && traceStart) { if (!traceStream) { printf("capturing trace..."); fflush(stdout); } // We clear the trace after starting it because tracing gets enabled for // each CPU individually in the kernel. Having the beginning of the trace // contain entries from only one CPU can cause "begin" entries without a // matching "end" entry to show up if a task gets migrated from one CPU to // another. ok = clearTrace(); writeClockSyncMarker(); if (ok && !async && !traceStream) { // Sleep to allow the trace to be captured. struct timespec timeLeft; timeLeft.tv_sec = g_traceDurationSeconds; timeLeft.tv_nsec = 0; do { if (g_traceAborted) { break; } } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR); } if (traceStream) { streamTrace(); } } // Stop the trace and restore the default settings. if (traceStop) stopTrace(); if (ok && traceDump) { if (!g_traceAborted) { printf(" done\n"); fflush(stdout); int outFd = STDOUT_FILENO; if (g_outputFile) { outFd = open(g_outputFile, O_WRONLY | O_CREAT); } if (outFd == -1) { printf("Failed to open '%s', err=%d", g_outputFile, errno); } else { dprintf(outFd, "TRACE:\n"); dumpTrace(outFd); if (g_outputFile) { close(outFd); } } } else { printf("\ntrace aborted.\n"); fflush(stdout); } clearTrace(); } else if (!ok) { fprintf(stderr, "unable to start tracing\n"); } // Reset the trace buffer size to 1. if (traceStop) cleanUpTrace(); return g_traceAborted ? 1 : 0; } cmds/atrace/atrace.rc0100644 0000000 0000000 00000010305 13077405420 013560 0ustar000000000 0000000 ## Permissions to allow system-wide tracing to the kernel trace buffer. ## on boot # Allow writing to the kernel trace log. chmod 0222 /sys/kernel/debug/tracing/trace_marker # Allow the shell group to enable (some) kernel tracing. chown root shell /sys/kernel/debug/tracing/trace_clock chown root shell /sys/kernel/debug/tracing/buffer_size_kb chown root shell /sys/kernel/debug/tracing/options/overwrite chown root shell /sys/kernel/debug/tracing/options/print-tgid chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable chown root shell /sys/kernel/debug/tracing/tracing_on chmod 0664 /sys/kernel/debug/tracing/trace_clock chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb chmod 0664 /sys/kernel/debug/tracing/options/overwrite chmod 0664 /sys/kernel/debug/tracing/options/print-tgid chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable chmod 0664 /sys/kernel/debug/tracing/tracing_on chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable # Tracing disabled by default write /sys/kernel/debug/tracing/tracing_on 0 # Allow only the shell group to read and truncate the kernel trace. chown root shell /sys/kernel/debug/tracing/trace chmod 0660 /sys/kernel/debug/tracing/trace on property:persist.debug.atrace.boottrace=1 start boottrace # Run atrace with the categories written in a file service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories disabled oneshot cmds/bugreport/0040755 0000000 0000000 00000000000 13077405420 012551 5ustar000000000 0000000 cmds/bugreport/Android.mk0100644 0000000 0000000 00000000306 13077405420 014456 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= bugreport.cpp LOCAL_MODULE:= bugreport LOCAL_CFLAGS := -Wall LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) cmds/bugreport/bugreport.cpp0100644 0000000 0000000 00000006367 13077405420 015277 0ustar000000000 0000000 /* * Copyright (C) 2009 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 #include #include #include #include #include #include // This program will trigger the dumpstate service to start a call to // dumpstate, then connect to the dumpstate local client to read the // output. All of the dumpstate output is written to stdout, including // any errors encountered while reading/writing the output. int main() { fprintf(stderr, "=============================================================================\n"); fprintf(stderr, "WARNING: flat bugreports are deprecated, use adb bugreport instead\n"); fprintf(stderr, "=============================================================================\n\n\n"); // Start the dumpstate service. property_set("ctl.start", "dumpstate"); // Socket will not be available until service starts. int s; for (int i = 0; i < 20; i++) { s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if (s >= 0) break; // Try again in 1 second. sleep(1); } if (s == -1) { printf("Failed to connect to dumpstate service: %s\n", strerror(errno)); return 1; } // Set a timeout so that if nothing is read in 3 minutes, we'll stop // reading and quit. No timeout in dumpstate is longer than 60 seconds, // so this gives lots of leeway in case of unforeseen time outs. struct timeval tv; tv.tv_sec = 3 * 60; tv.tv_usec = 0; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno)); } while (1) { char buffer[65536]; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer))); if (bytes_read == 0) { break; } else if (bytes_read == -1) { // EAGAIN really means time out, so change the errno. if (errno == EAGAIN) { errno = ETIMEDOUT; } printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno)); break; } ssize_t bytes_to_send = bytes_read; ssize_t bytes_written; do { bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send, bytes_to_send)); if (bytes_written == -1) { printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n", bytes_read, bytes_to_send, strerror(errno)); return 1; } bytes_to_send -= bytes_written; } while (bytes_written != 0 && bytes_to_send > 0); } close(s); return 0; } cmds/bugreportz/0040755 0000000 0000000 00000000000 13077405420 012743 5ustar000000000 0000000 cmds/bugreportz/Android.mk0100644 0000000 0000000 00000000310 13077405420 014643 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= bugreportz.cpp LOCAL_MODULE:= bugreportz LOCAL_CFLAGS := -Wall LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) cmds/bugreportz/bugreportz.cpp0100644 0000000 0000000 00000010214 13077405420 015645 0ustar000000000 0000000 /* * Copyright (C) 2016 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 #include #include #include #include #include #include #include static constexpr char VERSION[] = "1.0"; static void show_usage() { fprintf(stderr, "usage: bugreportz [-h | -v]\n" " -h: to display this help message\n" " -v: to display the version\n" " or no arguments to generate a zipped bugreport\n"); } static void show_version() { fprintf(stderr, "%s\n", VERSION); } int main(int argc, char *argv[]) { if (argc > 1) { /* parse arguments */ int c; while ((c = getopt(argc, argv, "vh")) != -1) { switch (c) { case 'h': show_usage(); return EXIT_SUCCESS; case 'v': show_version(); return EXIT_SUCCESS; default: show_usage(); return EXIT_FAILURE; } } // passed an argument not starting with - if (optind > 1 || argv[optind] != nullptr) { show_usage(); return EXIT_FAILURE; } } // TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value); // should be reused instead. // Start the dumpstatez service. property_set("ctl.start", "dumpstatez"); // Socket will not be available until service starts. int s; for (int i = 0; i < 20; i++) { s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if (s >= 0) break; // Try again in 1 second. sleep(1); } if (s == -1) { printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno)); return EXIT_SUCCESS; } // Set a timeout so that if nothing is read in 10 minutes, we'll stop // reading and quit. No timeout in dumpstate is longer than 60 seconds, // so this gives lots of leeway in case of unforeseen time outs. struct timeval tv; tv.tv_sec = 10 * 60; tv.tv_usec = 0; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno)); } while (1) { char buffer[65536]; ssize_t bytes_read = TEMP_FAILURE_RETRY( read(s, buffer, sizeof(buffer))); if (bytes_read == 0) { break; } else if (bytes_read == -1) { // EAGAIN really means time out, so change the errno. if (errno == EAGAIN) { errno = ETIMEDOUT; } printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno)); break; } ssize_t bytes_to_send = bytes_read; ssize_t bytes_written; do { bytes_written = TEMP_FAILURE_RETRY( write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send, bytes_to_send)); if (bytes_written == -1) { fprintf(stderr, "Failed to write data to stdout: read %zd, trying to send %zd (%s)\n", bytes_read, bytes_to_send, strerror(errno)); break; } bytes_to_send -= bytes_written; } while (bytes_written != 0 && bytes_to_send > 0); } if (close(s) == -1) { fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno)); } return EXIT_SUCCESS; } cmds/bugreportz/readme.md0100644 0000000 0000000 00000000641 13077405420 014520 0ustar000000000 0000000 # bugreportz protocol `bugreportz` is used to generate a zippped bugreport whose path is passed back to `adb`, using the simple protocol defined below. ## Version 1.0 On version 1.0, `bugreportz` does not generate any output on `stdout` until the bugreport is finished, when it then prints one line with the result: - `OK:` in case of success. - `FAIL:` in case of failure. cmds/cmd/0040755 0000000 0000000 00000000000 13077405420 011303 5ustar000000000 0000000 cmds/cmd/Android.mk0100644 0000000 0000000 00000000437 13077405420 013215 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ cmd.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libbinder ifeq ($(TARGET_OS),linux) LOCAL_CFLAGS += -DXP_UNIX #LOCAL_SHARED_LIBRARIES += librt endif LOCAL_MODULE:= cmd include $(BUILD_EXECUTABLE) cmds/cmd/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 014423 0ustar000000000 0000000 cmds/cmd/NOTICE0100644 0000000 0000000 00000024707 13077405420 012216 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS cmds/cmd/cmd.cpp0100644 0000000 0000000 00000005230 13077405420 012547 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "cmd" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; static int sort_func(const String16* lhs, const String16* rhs) { return lhs->compare(*rhs); } class MyResultReceiver : public BnResultReceiver { public: virtual void send(int32_t /*resultCode*/) { } }; int main(int argc, char* const argv[]) { signal(SIGPIPE, SIG_IGN); sp proc = ProcessState::self(); proc->startThreadPool(); sp sm = defaultServiceManager(); fflush(stdout); if (sm == NULL) { ALOGE("Unable to get default service manager!"); aerr << "cmd: Unable to get default service manager!" << endl; return 20; } if (argc == 1) { aout << "cmd: no service specified; use -l to list all services" << endl; return 20; } if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) { Vector services = sm->listServices(); services.sort(sort_func); aout << "Currently running services:" << endl; for (size_t i=0; i service = sm->checkService(services[i]); if (service != NULL) { aout << " " << services[i] << endl; } } return 0; } Vector args; for (int i=2; i service = sm->checkService(cmd); if (service == NULL) { aerr << "Can't find service: " << argv[1] << endl; return 20; } // TODO: block until a result is returned to MyResultReceiver. IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args, new MyResultReceiver()); return 0; } cmds/dumpstate/0040755 0000000 0000000 00000000000 13077405420 012546 5ustar000000000 0000000 cmds/dumpstate/Android.mk0100644 0000000 0000000 00000001241 13077405420 014452 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := libdumpstate_default.cpp LOCAL_MODULE := libdumpstate.default include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) ifdef BOARD_WLAN_DEVICE LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE) endif LOCAL_SRC_FILES := dumpstate.cpp utils.cpp LOCAL_MODULE := dumpstate LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux # ZipArchive support, the order matters here to get all symbols. LOCAL_STATIC_LIBRARIES := libziparchive libz libbase libmincrypt LOCAL_HAL_STATIC_LIBRARIES := libdumpstate LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter LOCAL_INIT_RC := dumpstate.rc include $(BUILD_EXECUTABLE) cmds/dumpstate/bugreport-format.md0100644 0000000 0000000 00000007556 13077405420 016401 0ustar000000000 0000000 # Bugreport file format This document specifies the format of the bugreport files generated by the bugreport services (like `bugreport` and `bugreportplus`) and delivered to the end user (i.e., it doesn’t include other tools like `adb bugreport`). A _bugreport_ is initially generated by dumpstate, then processed by **Shell**, which in turn delivers it to the end user through a `ACTION_SEND_MULTIPLE` intent; the end user then select which app (like an email client) handles such intent. ## Text file (Pre-M) Prior to _Android M (Marshmallow)_, `dumpstate` generates a flat .txt file named _bugreport-DATE.txt_ (where _DATE_ is date the bugreport was generated, in the format _YYYY-MM-DD-HH-MM-SS_), and Shell simply propagates it as an attachment in the `ACTION_SEND_MULTIPLE` intent. ## Version 0 (Android M) On _Android M (Marshmallow)_, dumpstate still generates a flat _bugreport-DATE.txt_ file, but then **Shell** creates a zip file called _bugreport-DATE.zip_ containing a _bugreport-DATE.txt_ entry and sends that file as the `ACTION_SEND_MULTIPLE` attachment. ## Version 1.0 (Android N) On _Android N (TBD)_, `dumpstate` generates a zip file directly (unless there is a failure, in which case it reverts to the flat file that is zipped by **Shell** and hence the end result is the _v0_ format). The zip file is by default called _bugreport-BUILD_ID-DATE.zip_ and it contains a _bugreport-BUILD_ID-DATE.txt_ entry, although the end user can change the name (through **Shell**), in which case they would be called _bugreport-BUILD_ID-NEW_NAME.zip_ and _bugreport-BUILD_ID-NEW_NAME.txt_ respectively. The zip file also contains 2 metadata entries generated by `dumpstate`: - `version.txt`: whose value is **1.0**. - `main-entry.txt`: whose value is the name of the flat text entry (i.e., _bugreport-BUILD_ID-DATE.txt_ or _bugreport-NEW_NAME.txt_). `dumpstate` can also copy files from the device’s filesystem into the zip file under the `FS` folder. For example, a `/dirA/dirB/fileC` file in the device would generate a `FS/dirA/dirB/fileC` entry in the zip file. When systrace is enabled, the zip file will contain a `systrace.txt` file as well. The flat file also has some minor changes: - Tombstone files were removed and added to the zip file. - The duration of each section is printed in the report. - Some dumpsys sections (memory and cpuinfo) are reported earlier in the file. Besides the files generated by `dumpstate`, **Shell** can also add 2 other files upon the end user’s request: - `title.txt`: whose value is a single-line summary of the problem. - `description.txt`: whose value is a multi-line, detailed description of the problem. ## Intermediate versions During development, the versions will be suffixed with _-devX_ or _-devX-EXPERIMENTAL_FEATURE_, where _X_ is a number that increases as the changes become stable. For example, the initial version during _Android N_ development was **1.0-dev1**. When `dumpsys` was split in 2 sections but not all tools were ready to parse that format, the version was named **1.0-dev2**, which had to be passed do `dumpsys` explicitly (i.e., trhough a `-V 1.0-dev2` argument). Once that format became stable and tools knew how to parse it, the default version became **1.0-dev2**. Similarly, if changes in the file format are made after the initial release of Android defining that format, then a new _sub-version_ will be used. For example, if after _Android N_ launches changes are made for the next _N_ release, the version will be called **1.1** or something like that. Determining version and main entry ----------------------------------------------- Tools parsing the zipped bugreport file can use the following algorithm to determine the bugreport format version and its main entry: ``` If [entries contain "version.txt"] version = read("version.txt") main_entry = read("main_entry.txt") else version = 0 main_entry = entries[0] fi ``` cmds/dumpstate/dumpstate.cpp0100644 0000000 0000000 00000147670 13077405420 015274 0ustar000000000 0000000 /* * Copyright (C) 2008 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "private/android_filesystem_config.h" #define LOG_TAG "dumpstate" #include #include "dumpstate.h" #include "ScopedFd.h" #include "ziparchive/zip_writer.h" #include "mincrypt/sha256.h" using android::base::StringPrintf; /* read before root is shed */ static char cmdline_buf[16384] = "(unknown)"; static const char *dump_traces_path = NULL; // TODO: should be part of dumpstate object static unsigned long id; static char build_type[PROPERTY_VALUE_MAX]; static time_t now; static std::unique_ptr zip_writer; static std::set mount_points; void add_mountinfo(); static int control_socket_fd; /* suffix of the bugreport files - it's typically the date (when invoked with -d), * although it could be changed by the user using a system property */ static std::string suffix; #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops" #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" #define RAFT_DIR "/data/misc/raft/" #define RECOVERY_DIR "/cache/recovery" #define RECOVERY_DATA_DIR "/data/misc/recovery" #define LOGPERSIST_DATA_DIR "/data/misc/logd" #define TOMBSTONE_DIR "/data/tombstones" #define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_" /* Can accomodate a tombstone number up to 9999. */ #define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4) #define NUM_TOMBSTONES 10 #define WLUTIL "/vendor/xbin/wlutil" typedef struct { char name[TOMBSTONE_MAX_LEN]; int fd; } tombstone_data_t; static tombstone_data_t tombstone_data[NUM_TOMBSTONES]; const std::string ZIP_ROOT_DIR = "FS"; std::string bugreport_dir; /* * List of supported zip format versions. * * See bugreport-format.txt for more info. */ static std::string VERSION_DEFAULT = "1.0"; bool is_user_build() { return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1); } /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones, * otherwise gets just those modified in the last half an hour. */ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { time_t thirty_minutes_ago = now - 60*30; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); int fd = TEMP_FAILURE_RETRY(open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); struct stat st; if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) { data[i].fd = fd; } else { close(fd); data[i].fd = -1; } } } // for_each_pid() callback to get mount info about a process. void do_mountinfo(int pid, const char *name) { char path[PATH_MAX]; // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points // are added. snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid); char linkname[PATH_MAX]; ssize_t r = readlink(path, linkname, PATH_MAX); if (r == -1) { MYLOGE("Unable to read link for %s: %s\n", path, strerror(errno)); return; } linkname[r] = '\0'; if (mount_points.find(linkname) == mount_points.end()) { // First time this mount point was found: add it snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid); if (add_zip_entry(ZIP_ROOT_DIR + path, path)) { mount_points.insert(linkname); } else { MYLOGE("Unable to add mountinfo %s to zip file\n", path); } } } void add_mountinfo() { if (!zip_writer) return; const char *title = "MOUNT INFO"; mount_points.clear(); DurationReporter duration_reporter(title, NULL); for_each_pid(do_mountinfo, NULL); MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size()); } static void dump_dev_files(const char *title, const char *driverpath, const char *filename) { DIR *d; struct dirent *de; char path[PATH_MAX]; d = opendir(driverpath); if (d == NULL) { return; } while ((de = readdir(d))) { if (de->d_type != DT_LNK) { continue; } snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename); dump_file(title, path); } closedir(d); } static void dump_systrace() { if (!zip_writer) { MYLOGD("Not dumping systrace because zip_writer is not set\n"); return; } std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt"; if (systrace_path.empty()) { MYLOGE("Not dumping systrace because path is empty\n"); return; } const char* path = "/sys/kernel/debug/tracing/tracing_on"; long int is_tracing; if (read_file_as_long(path, &is_tracing)) { return; // error already logged } if (is_tracing <= 0) { MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing); return; } MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes", systrace_path.c_str()); if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o", systrace_path.c_str(), NULL)) { MYLOGE("systrace timed out, its zip entry will be incomplete\n"); // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally, // we should call strace to stop itself, but there is no such option yet (just a // --async_stop, which stops and dump // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) { // MYLOGE("could not stop systrace "); // } } if (!add_zip_entry("systrace.txt", systrace_path)) { MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str()); } else { if (remove(systrace_path.c_str())) { MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno)); } } } static bool skip_not_stat(const char *path) { static const char stat[] = "/stat"; size_t len = strlen(path); if (path[len - 1] == '/') { /* Directory? */ return false; } return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ } static bool skip_none(const char *path) { return false; } static const char mmcblk0[] = "/sys/block/mmcblk0/"; unsigned long worst_write_perf = 20000; /* in KB/s */ // // stat offsets // Name units description // ---- ----- ----------- // read I/Os requests number of read I/Os processed #define __STAT_READ_IOS 0 // read merges requests number of read I/Os merged with in-queue I/O #define __STAT_READ_MERGES 1 // read sectors sectors number of sectors read #define __STAT_READ_SECTORS 2 // read ticks milliseconds total wait time for read requests #define __STAT_READ_TICKS 3 // write I/Os requests number of write I/Os processed #define __STAT_WRITE_IOS 4 // write merges requests number of write I/Os merged with in-queue I/O #define __STAT_WRITE_MERGES 5 // write sectors sectors number of sectors written #define __STAT_WRITE_SECTORS 6 // write ticks milliseconds total wait time for write requests #define __STAT_WRITE_TICKS 7 // in_flight requests number of I/Os currently in flight #define __STAT_IN_FLIGHT 8 // io_ticks milliseconds total time this block device has been active #define __STAT_IO_TICKS 9 // time_in_queue milliseconds total wait time for all requests #define __STAT_IN_QUEUE 10 #define __STAT_NUMBER_FIELD 11 // // read I/Os, write I/Os // ===================== // // These values increment when an I/O request completes. // // read merges, write merges // ========================= // // These values increment when an I/O request is merged with an // already-queued I/O request. // // read sectors, write sectors // =========================== // // These values count the number of sectors read from or written to this // block device. The "sectors" in question are the standard UNIX 512-byte // sectors, not any device- or filesystem-specific block size. The // counters are incremented when the I/O completes. #define SECTOR_SIZE 512 // // read ticks, write ticks // ======================= // // These values count the number of milliseconds that I/O requests have // waited on this block device. If there are multiple I/O requests waiting, // these values will increase at a rate greater than 1000/second; for // example, if 60 read requests wait for an average of 30 ms, the read_ticks // field will increase by 60*30 = 1800. // // in_flight // ========= // // This value counts the number of I/O requests that have been issued to // the device driver but have not yet completed. It does not include I/O // requests that are in the queue but not yet issued to the device driver. // // io_ticks // ======== // // This value counts the number of milliseconds during which the device has // had I/O requests queued. // // time_in_queue // ============= // // This value counts the number of milliseconds that I/O requests have waited // on this block device. If there are multiple I/O requests waiting, this // value will increase as the product of the number of milliseconds times the // number of requests waiting (see "read ticks" above for an example). #define S_TO_MS 1000 // static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) { unsigned long long fields[__STAT_NUMBER_FIELD]; bool z; char *cp, *buffer = NULL; size_t i = 0; FILE *fp = fdopen(fd, "rb"); getline(&buffer, &i, fp); fclose(fp); if (!buffer) { return -errno; } i = strlen(buffer); while ((i > 0) && (buffer[i - 1] == '\n')) { buffer[--i] = '\0'; } if (!*buffer) { free(buffer); return 0; } z = true; for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) { fields[i] = strtoull(cp, &cp, 10); if (fields[i] != 0) { z = false; } } if (z) { /* never accessed */ free(buffer); return 0; } if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) { path += sizeof(mmcblk0) - 1; } printf("%s: %s\n", path, buffer); free(buffer); if (fields[__STAT_IO_TICKS]) { unsigned long read_perf = 0; unsigned long read_ios = 0; if (fields[__STAT_READ_TICKS]) { unsigned long long divisor = fields[__STAT_READ_TICKS] * fields[__STAT_IO_TICKS]; read_perf = ((unsigned long long)SECTOR_SIZE * fields[__STAT_READ_SECTORS] * fields[__STAT_IN_QUEUE] + (divisor >> 1)) / divisor; read_ios = ((unsigned long long)S_TO_MS * fields[__STAT_READ_IOS] * fields[__STAT_IN_QUEUE] + (divisor >> 1)) / divisor; } unsigned long write_perf = 0; unsigned long write_ios = 0; if (fields[__STAT_WRITE_TICKS]) { unsigned long long divisor = fields[__STAT_WRITE_TICKS] * fields[__STAT_IO_TICKS]; write_perf = ((unsigned long long)SECTOR_SIZE * fields[__STAT_WRITE_SECTORS] * fields[__STAT_IN_QUEUE] + (divisor >> 1)) / divisor; write_ios = ((unsigned long long)S_TO_MS * fields[__STAT_WRITE_IOS] * fields[__STAT_IN_QUEUE] + (divisor >> 1)) / divisor; } unsigned queue = (fields[__STAT_IN_QUEUE] + (fields[__STAT_IO_TICKS] >> 1)) / fields[__STAT_IO_TICKS]; if (!write_perf && !write_ios) { printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue); } else { printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, write_perf, write_ios, queue); } /* bugreport timeout factor adjustment */ if ((write_perf > 1) && (write_perf < worst_write_perf)) { worst_write_perf = write_perf; } } return 0; } /* Copied policy from system/core/logd/LogBuffer.cpp */ #define LOG_BUFFER_SIZE (256 * 1024) #define LOG_BUFFER_MIN_SIZE (64 * 1024UL) #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) static bool valid_size(unsigned long value) { if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { return false; } long pages = sysconf(_SC_PHYS_PAGES); if (pages < 1) { return true; } long pagesize = sysconf(_SC_PAGESIZE); if (pagesize <= 1) { pagesize = PAGE_SIZE; } // maximum memory impact a somewhat arbitrary ~3% pages = (pages + 31) / 32; unsigned long maximum = pages * pagesize; if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { return true; } return value <= maximum; } static unsigned long property_get_size(const char *key) { unsigned long value; char *cp, property[PROPERTY_VALUE_MAX]; property_get(key, property, ""); value = strtoul(property, &cp, 10); switch(*cp) { case 'm': case 'M': value *= 1024; /* FALLTHRU */ case 'k': case 'K': value *= 1024; /* FALLTHRU */ case '\0': break; default: value = 0; } if (!valid_size(value)) { value = 0; } return value; } /* timeout in ms */ static unsigned long logcat_timeout(const char *name) { static const char global_tuneable[] = "persist.logd.size"; // Settings App static const char global_default[] = "ro.logd.size"; // BoardConfig.mk char key[PROP_NAME_MAX]; unsigned long property_size, default_size; default_size = property_get_size(global_tuneable); if (!default_size) { default_size = property_get_size(global_default); } snprintf(key, sizeof(key), "%s.%s", global_tuneable, name); property_size = property_get_size(key); if (!property_size) { snprintf(key, sizeof(key), "%s.%s", global_default, name); property_size = property_get_size(key); } if (!property_size) { property_size = default_size; } if (!property_size) { property_size = LOG_BUFFER_SIZE; } /* Engineering margin is ten-fold our guess */ return 10 * (property_size + worst_write_perf) / worst_write_perf; } /* End copy from system/core/logd/LogBuffer.cpp */ /* dumps the current system state to stdout */ static void print_header(std::string version) { char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; char network[PROPERTY_VALUE_MAX], date[80]; property_get("ro.build.display.id", build, "(unknown)"); property_get("ro.build.fingerprint", fingerprint, "(unknown)"); property_get("ro.build.type", build_type, "(unknown)"); property_get("ro.baseband", radio, "(unknown)"); property_get("ro.bootloader", bootloader, "(unknown)"); property_get("gsm.operator.alpha", network, "(unknown)"); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); printf("========================================================\n"); printf("== dumpstate: %s\n", date); printf("========================================================\n"); printf("\n"); printf("Build: %s\n", build); printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */ printf("Bootloader: %s\n", bootloader); printf("Radio: %s\n", radio); printf("Network: %s\n", network); printf("Kernel: "); dump_file(NULL, "/proc/version"); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("Bugreport format version: %s\n", version.c_str()); printf("Dumpstate info: id=%lu pid=%d\n", id, getpid()); printf("\n"); } bool add_zip_entry_from_fd(const std::string& entry_name, int fd) { if (!zip_writer) { MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n", entry_name.c_str()); return false; } // Logging statement below is useful to time how long each entry takes, but it's too verbose. // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, get_mtime(fd, now)); if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); return false; } std::vector buffer(65536); while (1) { ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer))); if (bytes_read == 0) { break; } else if (bytes_read == -1) { MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno)); return false; } err = zip_writer->WriteBytes(buffer.data(), bytes_read); if (err) { MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err)); return false; } } err = zip_writer->FinishEntry(); if (err) { MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err)); return false; } return true; } bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) { ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); if (fd.get() == -1) { MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno)); return false; } return add_zip_entry_from_fd(entry_name, fd.get()); } /* adds a file to the existing zipped bugreport */ static int _add_file_from_fd(const char *title, const char *path, int fd) { return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1; } void add_dir(const char *dir, bool recursive) { if (!zip_writer) { MYLOGD("Not adding dir %s because zip_writer is not set\n", dir); return; } MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive); DurationReporter duration_reporter(dir, NULL); dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd); } /* adds a text entry entry to the existing zip file. */ static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) { if (!zip_writer) { MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str()); return false; } MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now); if (err) { MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); return false; } err = zip_writer->WriteBytes(content.c_str(), content.length()); if (err) { MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); return false; } err = zip_writer->FinishEntry(); if (err) { MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err)); return false; } return true; } static void dump_iptables() { run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL); run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL); run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL); /* no ip6 nat */ run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL); run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL); } static void dumpstate(const std::string& screenshot_path, const std::string& version) { DurationReporter duration_reporter("DUMPSTATE"); unsigned long timeout; dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd"); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL); run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL); dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat"); dump_file("VMALLOC INFO", "/proc/vmallocinfo"); dump_file("SLAB INFO", "/proc/slabinfo"); dump_file("ZONEINFO", "/proc/zoneinfo"); dump_file("PAGETYPEINFO", "/proc/pagetypeinfo"); dump_file("BUDDYINFO", "/proc/buddyinfo"); dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index"); dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources"); dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); dump_file("KERNEL SYNC", "/d/sync"); run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL); run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL); run_command("PRINTENV", 10, "printenv", NULL); run_command("NETSTAT", 10, "netstat", "-n", NULL); run_command("LSMOD", 10, "lsmod", NULL); do_dmesg(); run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL); for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)"); if (!screenshot_path.empty()) { MYLOGI("taking late screenshot\n"); take_screenshot(screenshot_path); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); } // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); // calculate timeout timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); if (timeout < 20000) { timeout = 20000; } run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v", NULL); timeout = logcat_timeout("events"); if (timeout < 20000) { timeout = 20000; } run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v", NULL); timeout = logcat_timeout("radio"); if (timeout < 20000) { timeout = 20000; } run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v", NULL); run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); run_command("RAFT LOGS", 600, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { dump_file("VM TRACES JUST NOW", dump_traces_path); } /* only show ANR traces if they're less than 15 minutes old */ struct stat st; char anr_traces_path[PATH_MAX]; property_get("dalvik.vm.stack-trace-file", anr_traces_path, ""); if (!anr_traces_path[0]) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { int fd = TEMP_FAILURE_RETRY(open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); } else { dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd); } } /* slow traces for slow operations */ if (anr_traces_path[0] != 0) { int tail = strlen(anr_traces_path)-1; while (tail > 0 && anr_traces_path[tail] != '/') { tail--; } int i = 0; while (1) { sprintf(anr_traces_path+tail+1, "slow%02d.txt", i); if (stat(anr_traces_path, &st)) { // No traces file at this index, done with the files. break; } dump_file("VM TRACES WHEN SLOW", anr_traces_path); i++; } } int dumped = 0; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { if (tombstone_data[i].fd != -1) { const char *name = tombstone_data[i].name; int fd = tombstone_data[i].fd; dumped = 1; if (zip_writer) { if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) { MYLOGE("Unable to add tombstone %s to zip file\n", name); } } else { dump_file_from_fd("TOMBSTONE", name, fd); } close(fd); tombstone_data[i].fd = -1; } } if (!dumped) { printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR); } dump_file("NETWORK DEV INFO", "/proc/net/dev"); dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all"); dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt"); dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats"); if (!stat(PSTORE_LAST_KMSG, &st)) { /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */ dump_file("LAST KMSG", PSTORE_LAST_KMSG); } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) { dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG); } else { /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */ dump_file("LAST KMSG", "/proc/last_kmsg"); } /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ run_command("LAST LOGCAT", 10, "logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v", NULL); /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ run_command("NETWORK INTERFACES", 10, "ip", "link", NULL); run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL); run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL); run_command("IP RULES", 10, "ip", "rule", "show", NULL); run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL); dump_route_tables(); run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL); run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL); run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL); run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL); #ifdef FWDUMP_bcmdhd run_command("ND OFFLOAD TABLE", 5, SU_PATH, "root", WLUTIL, "nd_hostip", NULL); run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20, SU_PATH, "root", WLUTIL, "counters", NULL); run_command("ND OFFLOAD STATUS (1)", 5, SU_PATH, "root", WLUTIL, "nd_status", NULL); #endif dump_file("INTERRUPTS (1)", "/proc/interrupts"); run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL); #ifdef FWDUMP_bcmdhd run_command("DUMP WIFI STATUS", 20, SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL); run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20, SU_PATH, "root", WLUTIL, "counters", NULL); run_command("ND OFFLOAD STATUS (2)", 5, SU_PATH, "root", WLUTIL, "nd_status", NULL); #endif dump_file("INTERRUPTS (2)", "/proc/interrupts"); print_properties(); run_command("VOLD DUMP", 10, "vdc", "dump", NULL); run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL); run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL); run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL); printf("------ BACKLIGHTS ------\n"); printf("LCD brightness="); dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness"); printf("Button brightness="); dump_file(NULL, "/sys/class/leds/button-backlight/brightness"); printf("Keyboard brightness="); dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness"); printf("ALS mode="); dump_file(NULL, "/sys/class/leds/lcd-backlight/als"); printf("LCD driver registers:\n"); dump_file(NULL, "/sys/class/leds/lcd-backlight/registers"); printf("\n"); /* Binder state is expensive to look at as it uses a lot of memory. */ dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats"); dump_file("BINDER STATE", "/sys/kernel/debug/binder/state"); printf("========================================================\n"); printf("== Board\n"); printf("========================================================\n"); dumpstate_board(); printf("\n"); /* Migrate the ril_dumpstate to a dumpstate_board()? */ char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0}; property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30"); if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) { if (is_user_build()) { // su does not exist on user builds, so try running without it. // This way any implementations of vril-dump that do not require // root can run on user builds. run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), "vril-dump", NULL); } else { run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), SU_PATH, "root", "vril-dump", NULL); } } printf("========================================================\n"); printf("== Android Framework Services\n"); printf("========================================================\n"); run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL); printf("========================================================\n"); printf("== Checkins\n"); printf("========================================================\n"); run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL); run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL); run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL); run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL); run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL); run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL); printf("========================================================\n"); printf("== Running Application Activities\n"); printf("========================================================\n"); run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL); printf("========================================================\n"); printf("== Running Application Services\n"); printf("========================================================\n"); run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL); printf("========================================================\n"); printf("== Running Application Providers\n"); printf("========================================================\n"); run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL); printf("========================================================\n"); printf("== Final progress (pid %d): %d/%d (originally %d)\n", getpid(), progress, weight_total, WEIGHT_TOTAL); printf("========================================================\n"); printf("== dumpstate: done\n"); printf("========================================================\n"); } static void usage() { fprintf(stderr, "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" " -o: write to file (instead of stdout)\n" " -d: append date to filename (requires -o)\n" " -p: capture screenshot to filename.png (requires -o)\n" " -z: generate zipped file (requires -o)\n" " -s: write output to control socket (for init)\n" " -S: write file location to control socket (for init; requires -o and -z)" " -q: disable vibrate\n" " -B: send broadcast when finished (requires -o)\n" " -P: send broadcast when started and update system properties on " "progress (requires -o and -B)\n" " -R: take bugreport in remote mode (requires -o, -z, -d and -B, " "shouldn't be used with -P)\n" " -V: sets the bugreport format version (valid values: %s)\n", VERSION_DEFAULT.c_str()); } static void sigpipe_handler(int n) { // don't complain to stderr or stdout _exit(EXIT_FAILURE); } /* adds the temporary report to the existing .zip file, closes the .zip file, and removes the temporary file. */ static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path, time_t now) { if (!add_zip_entry(bugreport_name, bugreport_path)) { MYLOGE("Failed to add text entry to .zip file\n"); return false; } if (!add_text_zip_entry("main_entry.txt", bugreport_name)) { MYLOGE("Failed to add main_entry.txt to .zip file\n"); return false; } int32_t err = zip_writer->Finish(); if (err) { MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err)); return false; } if (is_user_build()) { MYLOGD("Removing temporary file %s\n", bugreport_path.c_str()) if (remove(bugreport_path.c_str())) { ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno)); } } else { MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str()) } return true; } static std::string SHA256_file_hash(std::string filepath) { ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC | O_NOFOLLOW))); if (fd.get() == -1) { MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno)); return NULL; } SHA256_CTX ctx; SHA256_init(&ctx); std::vector buffer(65536); while (1) { ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size())); if (bytes_read == 0) { break; } else if (bytes_read == -1) { MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno)); return NULL; } SHA256_update(&ctx, buffer.data(), bytes_read); } uint8_t hash[SHA256_DIGEST_SIZE]; memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE); char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1]; for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) { sprintf(hash_buffer + (i * 2), "%02x", hash[i]); } hash_buffer[sizeof(hash_buffer) - 1] = 0; return std::string(hash_buffer); } int main(int argc, char *argv[]) { struct sigaction sigact; int do_add_date = 0; int do_zip_file = 0; int do_vibrate = 1; char* use_outfile = 0; int use_socket = 0; int use_control_socket = 0; int do_fb = 0; int do_broadcast = 0; int do_early_screenshot = 0; int is_remote_mode = 0; std::string version = VERSION_DEFAULT; now = time(NULL); MYLOGI("begin\n"); /* gets the sequential id */ char last_id[PROPERTY_VALUE_MAX]; property_get("dumpstate.last_id", last_id, "0"); id = strtoul(last_id, NULL, 10) + 1; snprintf(last_id, sizeof(last_id), "%lu", id); property_set("dumpstate.last_id", last_id); MYLOGI("dumpstate id: %lu\n", id); /* clear SIGPIPE handler */ memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = sigpipe_handler; sigaction(SIGPIPE, &sigact, NULL); /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); FILE *oom_adj = fopen("/proc/self/oom_adj", "we"); if (oom_adj) { fputs("-17", oom_adj); fclose(oom_adj); } /* parse arguments */ std::string args; format_args(argc, const_cast(argv), &args); MYLOGD("Dumpstate command line: %s\n", args.c_str()); int c; while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) { switch (c) { case 'd': do_add_date = 1; break; case 'z': do_zip_file = 1; break; case 'o': use_outfile = optarg; break; case 's': use_socket = 1; break; case 'S': use_control_socket = 1; break; case 'v': break; // compatibility no-op case 'q': do_vibrate = 0; break; case 'p': do_fb = 1; break; case 'P': do_update_progress = 1; break; case 'R': is_remote_mode = 1; break; case 'B': do_broadcast = 1; break; case 'V': version = optarg; break; case '?': printf("\n"); case 'h': usage(); exit(1); } } if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) { usage(); exit(1); } if (use_control_socket && !do_zip_file) { usage(); exit(1); } if (do_update_progress && !do_broadcast) { usage(); exit(1); } if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) { usage(); exit(1); } if (version != VERSION_DEFAULT) { usage(); exit(1); } MYLOGI("bugreport format version: %s\n", version.c_str()); do_early_screenshot = do_update_progress; // If we are going to use a socket, do it as early as possible // to avoid timeouts from bugreport. if (use_socket) { redirect_to_socket(stdout, "dumpstate"); } if (use_control_socket) { MYLOGD("Opening control socket\n"); control_socket_fd = open_socket("dumpstate"); } /* full path of the temporary file containing the bugreport */ std::string tmp_path; /* full path of the file containing the dumpstate logs*/ std::string log_path; /* full path of the systrace file, when enabled */ std::string systrace_path; /* full path of the temporary file containing the screenshot (when requested) */ std::string screenshot_path; /* base name (without suffix or extensions) of the bugreport files */ std::string base_name; /* pointer to the actual path, be it zip or text */ std::string path; /* pointer to the zipped file */ std::unique_ptr zip_file(NULL, fclose); /* redirect output if needed */ bool is_redirecting = !use_socket && use_outfile; if (is_redirecting) { bugreport_dir = dirname(use_outfile); base_name = basename(use_outfile); if (do_add_date) { char date[80]; strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now)); suffix = date; } else { suffix = "undated"; } char build_id[PROPERTY_VALUE_MAX]; property_get("ro.build.id", build_id, "UNKNOWN_BUILD"); base_name = base_name + "-" + build_id; if (do_fb) { // TODO: if dumpstate was an object, the paths could be internal variables and then // we could have a function to calculate the derived values, such as: // screenshot_path = GetPath(".png"); screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png"; } tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp"; log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt"; MYLOGD("Bugreport dir: %s\n" "Base name: %s\n" "Suffix: %s\n" "Log path: %s\n" "Temporary path: %s\n" "Screenshot path: %s\n", bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str()); if (do_zip_file) { path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip"; MYLOGD("Creating initial .zip file (%s)\n", path.c_str()); create_parent_dirs(path.c_str()); zip_file.reset(fopen(path.c_str(), "wb")); if (!zip_file) { MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno)); do_zip_file = 0; } else { zip_writer.reset(new ZipWriter(zip_file.get())); } add_text_zip_entry("version.txt", version); } if (do_update_progress) { std::vector am_args = { "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--es", "android.intent.extra.NAME", suffix, "--ei", "android.intent.extra.ID", std::to_string(id), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL), }; send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args); } } /* read /proc/cmdline before dropping root */ FILE *cmdline = fopen("/proc/cmdline", "re"); if (cmdline) { fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); fclose(cmdline); } /* open the vibrator before dropping root */ std::unique_ptr vibrator(NULL, fclose); if (do_vibrate) { vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we")); if (vibrator) { vibrate(vibrator.get(), 150); } } if (do_fb && do_early_screenshot) { if (screenshot_path.empty()) { // should not have happened MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); } else { MYLOGI("taking early screenshot\n"); take_screenshot(screenshot_path); MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str()); if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of screenshot file %s: %s\n", screenshot_path.c_str(), strerror(errno)); } } } if (do_zip_file) { if (chown(path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of zip file %s: %s\n", path.c_str(), strerror(errno)); } } if (is_redirecting) { redirect_to_file(stderr, const_cast(log_path.c_str())); if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path.c_str(), strerror(errno)); } /* TODO: rather than generating a text file now and zipping it later, it would be more efficient to redirect stdout to the zip entry directly, but the libziparchive doesn't support that option yet. */ redirect_to_file(stdout, const_cast(tmp_path.c_str())); if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n", tmp_path.c_str(), strerror(errno)); } } // NOTE: there should be no stdout output until now, otherwise it would break the header. // In particular, DurationReport objects should be created passing 'title, NULL', so their // duration is logged into MYLOG instead. print_header(version); // Dumps systrace right away, otherwise it will be filled with unnecessary events. dump_systrace(); // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL); run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL); /* collect stack traces from Dalvik and native processes (needs root) */ dump_traces_path = dump_traces(); /* Run some operations that require root. */ get_tombstone_fds(tombstone_data); add_dir(RECOVERY_DIR, true); add_dir(RECOVERY_DATA_DIR, true); add_dir(LOGPERSIST_DATA_DIR, false); add_mountinfo(); dump_iptables(); if (!drop_root_user()) { return -1; } dumpstate(do_early_screenshot ? "": screenshot_path, version); /* close output if needed */ if (is_redirecting) { fclose(stdout); } /* rename or zip the (now complete) .tmp file to its final location */ if (use_outfile) { /* check if user changed the suffix using system properties */ char key[PROPERTY_KEY_MAX]; char value[PROPERTY_VALUE_MAX]; snprintf(key, sizeof(key), "dumpstate.%d.name", getpid()); property_get(key, value, ""); bool change_suffix= false; if (value[0]) { /* must whitelist which characters are allowed, otherwise it could cross directories */ std::regex valid_regex("^[-_a-zA-Z0-9]+$"); if (std::regex_match(value, valid_regex)) { change_suffix = true; } else { MYLOGE("invalid suffix provided by user: %s\n", value); } } if (change_suffix) { MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value); suffix = value; if (!screenshot_path.empty()) { std::string new_screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png"; if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(), new_screenshot_path.c_str(), strerror(errno)); } else { screenshot_path = new_screenshot_path; } } } bool do_text_file = true; if (do_zip_file) { std::string entry_name = base_name + "-" + suffix + ".txt"; MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str()); if (!finish_zip_file(entry_name, tmp_path, now)) { MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); do_text_file = true; } else { do_text_file = false; // Since zip file is already created, it needs to be renamed. std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip"; if (path != new_path) { MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str()); if (rename(path.c_str(), new_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", path.c_str(), new_path.c_str(), strerror(errno)); } else { path = new_path; } } } } if (do_text_file) { path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt"; MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str()); if (rename(tmp_path.c_str(), path.c_str())) { MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno)); path.clear(); } } if (use_control_socket) { if (do_text_file) { dprintf(control_socket_fd, "FAIL:could not create zip file, check %s " "for more details\n", log_path.c_str()); } else { dprintf(control_socket_fd, "OK:%s\n", path.c_str()); } } } /* vibrate a few but shortly times to let user know it's finished */ if (vibrator) { for (int i = 0; i < 3; i++) { vibrate(vibrator.get(), 75); usleep((75 + 50) * 1000); } } /* tell activity manager we're done */ if (do_broadcast) { if (!path.empty()) { MYLOGI("Final bugreport path: %s\n", path.c_str()); std::vector am_args = { "--receiver-permission", "android.permission.DUMP", "--receiver-foreground", "--ei", "android.intent.extra.ID", std::to_string(id), "--ei", "android.intent.extra.PID", std::to_string(getpid()), "--ei", "android.intent.extra.MAX", std::to_string(weight_total), "--es", "android.intent.extra.BUGREPORT", path, "--es", "android.intent.extra.DUMPSTATE_LOG", log_path }; if (do_fb) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back(screenshot_path); } if (is_remote_mode) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH"); am_args.push_back(SHA256_file_hash(path)); send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args); } else { send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args); } } else { MYLOGE("Skipping finished broadcast because bugreport could not be generated\n"); } } MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL); MYLOGI("done\n"); if (is_redirecting) { fclose(stderr); } if (use_control_socket && control_socket_fd >= 0) { MYLOGD("Closing control socket\n"); close(control_socket_fd); } return 0; } cmds/dumpstate/dumpstate.h0100644 0000000 0000000 00000017454 13077405420 014735 0ustar000000000 0000000 /* * Copyright (C) 2008 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 _DUMPSTATE_H_ #define _DUMPSTATE_H_ /* When defined, skips the real dumps and just print the section headers. Useful when debugging dumpstate itself. */ //#define _DUMPSTATE_DRY_RUN_ #ifdef _DUMPSTATE_DRY_RUN_ #define ON_DRY_RUN_RETURN(X) return X #define ON_DRY_RUN(code) code #else #define ON_DRY_RUN_RETURN(X) #define ON_DRY_RUN(code) #endif #ifndef MYLOGD #define MYLOGD(...) fprintf(stderr, __VA_ARGS__); ALOGD(__VA_ARGS__); #endif #ifndef MYLOGI #define MYLOGI(...) fprintf(stderr, __VA_ARGS__); ALOGI(__VA_ARGS__); #endif #ifndef MYLOGE #define MYLOGE(...) fprintf(stderr, __VA_ARGS__); ALOGE(__VA_ARGS__); #endif #include #include #include #include #include #define SU_PATH "/system/xbin/su" #ifdef __cplusplus extern "C" { #endif typedef void (for_each_pid_func)(int, const char *); typedef void (for_each_tid_func)(int, int, const char *); /* Estimated total weight of bugreport generation. * * Each section contributes to the total weight by an individual weight, so the overall progress * can be calculated by dividing the all completed weight by the total weight. * * This value is defined empirically and it need to be adjusted as more sections are added. * * It does not need to match the exact sum of all sections, but ideally it should to be slight more * than such sum: a value too high will cause the bugreport to finish before the user expected (for * example, jumping from 70% to 100%), while a value too low will cause the progress to get stuck * at an almost-finished value (like 99%) for a while. */ static const int WEIGHT_TOTAL = 6500; /* Most simple commands have 10 as timeout, so 5 is a good estimate */ static const int WEIGHT_FILE = 5; /* * TODO: the dumpstate internal state is getting fragile; for example, this variable is defined * here, declared at utils.cpp, and used on utils.cpp and dumpstate.cpp. * It would be better to take advantage of the C++ migration and encapsulate the state in an object, * but that will be better handled in a major C++ refactoring, which would also get rid of other C * idioms (like using std::string instead of char*, removing varargs, etc...) */ extern int do_update_progress, progress, weight_total; /* full path of the directory where the bugreport files will be written */ extern std::string bugreport_dir; /* root dir for all files copied as-is into the bugreport. */ extern const std::string ZIP_ROOT_DIR; /* adds a new entry to the existing zip file. */ bool add_zip_entry(const std::string& entry_name, const std::string& entry_path); /* adds a new entry to the existing zip file. */ bool add_zip_entry_from_fd(const std::string& entry_name, int fd); /* adds all files from a directory to the zipped bugreport file */ void add_dir(const char *dir, bool recursive); /* prints the contents of a file */ int dump_file(const char *title, const char *path); /* saves the the contents of a file as a long */ int read_file_as_long(const char *path, long int *output); /* prints the contents of the fd * fd must have been opened with the flag O_NONBLOCK. */ int dump_file_from_fd(const char *title, const char *path, int fd); /* calls skip to gate calling dump_from_fd recursively * in the specified directory. dump_from_fd defaults to * dump_file_from_fd above when set to NULL. skip defaults * to false when set to NULL. dump_from_fd will always be * called with title NULL. */ int dump_files(const char *title, const char *dir, bool (*skip)(const char *path), int (*dump_from_fd)(const char *title, const char *path, int fd)); // TODO: need to refactor all those run_command variations; there shold be just one, receiving an // optional CommandOptions objects with values such as run_always, drop_root, etc... /* forks a command and waits for it to finish -- terminate args with NULL */ int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...); int run_command(const char *title, int timeout_seconds, const char *command, ...); enum RootMode { DROP_ROOT, DONT_DROP_ROOT }; enum StdoutMode { NORMAL_STDOUT, REDIRECT_TO_STDERR }; /* forks a command and waits for it to finish first element of args is the command, and last must be NULL. command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */ int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode, int timeout_seconds, const char *args[]); /* switch to non-root user and group */ bool drop_root_user(); /* sends a broadcast using Activity Manager */ void send_broadcast(const std::string& action, const std::vector& args); /* updates the overall progress of dumpstate by the given weight increment */ void update_progress(int weight); /* prints all the system properties */ void print_properties(); /** opens a socket and returns its file descriptor */ int open_socket(const char *service); /* redirect output to a service control socket */ void redirect_to_socket(FILE *redirect, const char *service); /* redirect output to a file */ void redirect_to_file(FILE *redirect, char *path); /* create leading directories, if necessary */ void create_parent_dirs(const char *path); /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces(); /* for each process in the system, run the specified function */ void for_each_pid(for_each_pid_func func, const char *header); /* for each thread in the system, run the specified function */ void for_each_tid(for_each_tid_func func, const char *header); /* Displays a blocked processes in-kernel wait channel */ void show_wchan(int pid, int tid, const char *name); /* Displays a processes times */ void show_showtime(int pid, const char *name); /* Runs "showmap" for a process */ void do_showmap(int pid, const char *name); /* Gets the dmesg output for the kernel */ void do_dmesg(); /* Prints the contents of all the routing tables, both IPv4 and IPv6. */ void dump_route_tables(); /* Play a sound via Stagefright */ void play_sound(const char *path); /* Implemented by libdumpstate_board to dump board-specific info */ void dumpstate_board(); /* Takes a screenshot and save it to the given file */ void take_screenshot(const std::string& path); /* Vibrates for a given durating (in milliseconds). */ void vibrate(FILE* vibrator, int ms); /* Checks if a given path is a directory. */ bool is_dir(const char* pathname); /** Gets the last modification time of a file, or default time if file is not found. */ time_t get_mtime(int fd, time_t default_mtime); /* Dumps eMMC Extended CSD data. */ void dump_emmc_ecsd(const char *ext_csd_path); /** Gets command-line arguments. */ void format_args(int argc, const char *argv[], std::string *args); /** Tells if the device is running a user build. */ bool is_user_build(); /* * Helper class used to report how long it takes for a section to finish. * * Typical usage: * * DurationReporter duration_reporter(title); * */ class DurationReporter { public: DurationReporter(const char *title); DurationReporter(const char *title, FILE* out); ~DurationReporter(); static uint64_t nanotime(); private: const char* title_; FILE* out_; uint64_t started_; }; #ifdef __cplusplus } #endif #endif /* _DUMPSTATE_H_ */ cmds/dumpstate/dumpstate.rc0100644 0000000 0000000 00000003104 13077405420 015075 0ustar000000000 0000000 on boot # Allow bugreports access to eMMC 5.0 stats chown root mount /sys/kernel/debug/mmc0/mmc0:0001/ext_csd chmod 0440 /sys/kernel/debug/mmc0/mmc0:0001/ext_csd service dumpstate /system/bin/dumpstate -s class main socket dumpstate stream 0660 shell log disabled oneshot # dumpstatez generates a zipped bugreport but also uses a socket to print the file location once # it is finished. service dumpstatez /system/bin/dumpstate -S -d -z \ -o /data/user_de/0/com.android.shell/files/bugreports/bugreport socket dumpstate stream 0660 shell log class main disabled oneshot # bugreportplus is an enhanced version of bugreport that provides a better # user interface (like displaying progress and allowing user to enter details). # It's typically triggered by the power button or developer settings. service bugreportplus /system/bin/dumpstate -d -B -P -z \ -o /data/user_de/0/com.android.shell/files/bugreports/bugreport class main disabled oneshot # bugreportremote is an altered version of bugreport that is supposed to be # called not by human user of the device, but by DevicePolicyManagerService only when the # Device Owner explicitly requests it, and shared with the Device Policy Controller (DPC) app only # if the user consents # it will disable vibrations, screenshot taking and will not track progress or # allow user to enter any details service bugreportremote /system/bin/dumpstate -d -q -B -R -z \ -o /data/user_de/0/com.android.shell/files/bugreports/remote/bugreport class main disabled oneshot cmds/dumpstate/libdumpstate_default.cpp0100644 0000000 0000000 00000001245 13077405420 017452 0ustar000000000 0000000 /* * Copyright (C) 2013 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 "dumpstate.h" void dumpstate_board(void) { } cmds/dumpstate/utils.cpp0100644 0000000 0000000 00000131241 13077405420 014411 0ustar000000000 0000000 /* * Copyright (C) 2008 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "dumpstate" #include #include #include #include #include #include #include "dumpstate.h" static const int64_t NANOS_PER_SEC = 1000000000; /* list of native processes to include in the native dumps */ // This matches the /proc/pid/exe link instead of /proc/pid/cmdline. static const char* native_processes_to_dump[] = { "/system/bin/audioserver", "/system/bin/cameraserver", "/system/bin/drmserver", "/system/bin/mediacodec", // media.codec "/system/bin/mediadrmserver", "/system/bin/mediaextractor", // media.extractor "/system/bin/mediaserver", "/system/bin/sdcard", "/system/bin/surfaceflinger", "/system/bin/vehicle_network_service", NULL, }; DurationReporter::DurationReporter(const char *title) : DurationReporter(title, stdout) {} DurationReporter::DurationReporter(const char *title, FILE *out) { title_ = title; if (title) { started_ = DurationReporter::nanotime(); } out_ = out; } DurationReporter::~DurationReporter() { if (title_) { uint64_t elapsed = DurationReporter::nanotime() - started_; // Use "Yoda grammar" to make it easier to grep|sort sections. if (out_) { fprintf(out_, "------ %.3fs was the duration of '%s' ------\n", (float) elapsed / NANOS_PER_SEC, title_); } else { MYLOGD("Duration of '%s': %.3fs\n", title_, (float) elapsed / NANOS_PER_SEC); } } } uint64_t DurationReporter::DurationReporter::nanotime() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t) ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec; } void for_each_userid(void (*func)(int), const char *header) { ON_DRY_RUN_RETURN(); DIR *d; struct dirent *de; if (header) printf("\n------ %s ------\n", header); func(0); if (!(d = opendir("/data/system/users"))) { printf("Failed to open /data/system/users (%s)\n", strerror(errno)); return; } while ((de = readdir(d))) { int userid; if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) { continue; } func(userid); } closedir(d); } static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) { DIR *d; struct dirent *de; if (!(d = opendir("/proc"))) { printf("Failed to open /proc (%s)\n", strerror(errno)); return; } if (header) printf("\n------ %s ------\n", header); while ((de = readdir(d))) { int pid; int fd; char cmdpath[255]; char cmdline[255]; if (!(pid = atoi(de->d_name))) { continue; } memset(cmdline, 0, sizeof(cmdline)); snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid); if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2)); close(fd); if (cmdline[0]) { helper(pid, cmdline, arg); continue; } } // if no cmdline, a kernel thread has comm snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid); if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4)); close(fd); if (cmdline[1]) { cmdline[0] = '['; size_t len = strcspn(cmdline, "\f\b\r\n"); cmdline[len] = ']'; cmdline[len+1] = '\0'; } } if (!cmdline[0]) { strcpy(cmdline, "N/A"); } helper(pid, cmdline, arg); } closedir(d); } static void for_each_pid_helper(int pid, const char *cmdline, void *arg) { for_each_pid_func *func = (for_each_pid_func*) arg; func(pid, cmdline); } void for_each_pid(for_each_pid_func func, const char *header) { ON_DRY_RUN_RETURN(); __for_each_pid(for_each_pid_helper, header, (void *)func); } static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { DIR *d; struct dirent *de; char taskpath[255]; for_each_tid_func *func = (for_each_tid_func *) arg; snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid); if (!(d = opendir(taskpath))) { printf("Failed to open %s (%s)\n", taskpath, strerror(errno)); return; } func(pid, pid, cmdline); while ((de = readdir(d))) { int tid; int fd; char commpath[255]; char comm[255]; if (!(tid = atoi(de->d_name))) { continue; } if (tid == pid) continue; snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid); memset(comm, 0, sizeof(comm)); if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) { strcpy(comm, "N/A"); } else { char *c; TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2)); close(fd); c = strrchr(comm, '\n'); if (c) { *c = '\0'; } } func(pid, tid, comm); } closedir(d); } void for_each_tid(for_each_tid_func func, const char *header) { ON_DRY_RUN_RETURN(); __for_each_pid(for_each_tid_helper, header, (void *) func); } void show_wchan(int pid, int tid, const char *name) { ON_DRY_RUN_RETURN(); char path[255]; char buffer[255]; int fd, ret, save_errno; char name_buffer[255]; memset(buffer, 0, sizeof(buffer)); snprintf(path, sizeof(path), "/proc/%d/wchan", tid); if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { printf("Failed to open '%s' (%s)\n", path, strerror(errno)); return; } ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); save_errno = errno; close(fd); if (ret < 0) { printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); return; } snprintf(name_buffer, sizeof(name_buffer), "%*s%s", pid == tid ? 0 : 3, "", name); printf("%-7d %-32s %s\n", tid, name_buffer, buffer); return; } // print time in centiseconds static void snprcent(char *buffer, size_t len, size_t spc, unsigned long long time) { static long hz; // cache discovered hz if (hz <= 0) { hz = sysconf(_SC_CLK_TCK); if (hz <= 0) { hz = 1000; } } // convert to centiseconds time = (time * 100 + (hz / 2)) / hz; char str[16]; snprintf(str, sizeof(str), " %llu.%02u", time / 100, (unsigned)(time % 100)); size_t offset = strlen(buffer); snprintf(buffer + offset, (len > offset) ? len - offset : 0, "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); } // print permille as a percent static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) { char str[16]; snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10); size_t offset = strlen(buffer); snprintf(buffer + offset, (len > offset) ? len - offset : 0, "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); } void show_showtime(int pid, const char *name) { ON_DRY_RUN_RETURN(); char path[255]; char buffer[1023]; int fd, ret, save_errno; memset(buffer, 0, sizeof(buffer)); snprintf(path, sizeof(path), "/proc/%d/stat", pid); if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { printf("Failed to open '%s' (%s)\n", path, strerror(errno)); return; } ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); save_errno = errno; close(fd); if (ret < 0) { printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); return; } // field 14 is utime // field 15 is stime // field 42 is iotime unsigned long long utime = 0, stime = 0, iotime = 0; if (sscanf(buffer, "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ", &utime, &stime, &iotime) != 3) { return; } unsigned long long total = utime + stime; if (!total) { return; } unsigned permille = (iotime * 1000 + (total / 2)) / total; if (permille > 1000) { permille = 1000; } // try to beautify and stabilize columns at <80 characters snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name); if ((name[0] != '[') || utime) { snprcent(buffer, sizeof(buffer), 57, utime); } snprcent(buffer, sizeof(buffer), 65, stime); if ((name[0] != '[') || iotime) { snprcent(buffer, sizeof(buffer), 73, iotime); } if (iotime) { snprdec(buffer, sizeof(buffer), 79, permille); } puts(buffer); // adds a trailing newline return; } void do_dmesg() { const char *title = "KERNEL LOG (dmesg)"; DurationReporter duration_reporter(title); printf("------ %s ------\n", title); ON_DRY_RUN_RETURN(); /* Get size of kernel buffer */ int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0); if (size <= 0) { printf("Unexpected klogctl return value: %d\n\n", size); return; } char *buf = (char *) malloc(size + 1); if (buf == NULL) { printf("memory allocation failed\n\n"); return; } int retval = klogctl(KLOG_READ_ALL, buf, size); if (retval < 0) { printf("klogctl failure\n\n"); free(buf); return; } buf[retval] = '\0'; printf("%s\n\n", buf); free(buf); return; } void do_showmap(int pid, const char *name) { char title[255]; char arg[255]; snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name); snprintf(arg, sizeof(arg), "%d", pid); run_command(title, 10, SU_PATH, "root", "showmap", "-q", arg, NULL); } static int _dump_file_from_fd(const char *title, const char *path, int fd) { if (title) { printf("------ %s (%s", title, path); struct stat st; // Only show the modification time of non-device files. size_t path_len = strlen(path); if ((path_len < 6 || memcmp(path, "/proc/", 6)) && (path_len < 5 || memcmp(path, "/sys/", 5)) && (path_len < 3 || memcmp(path, "/d/", 3)) && !fstat(fd, &st)) { char stamp[80]; time_t mtime = st.st_mtime; strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime)); printf(": %s", stamp); } printf(") ------\n"); } ON_DRY_RUN({ update_progress(WEIGHT_FILE); close(fd); return 0; }); bool newline = false; fd_set read_set; struct timeval tm; while (1) { FD_ZERO(&read_set); FD_SET(fd, &read_set); /* Timeout if no data is read for 30 seconds. */ tm.tv_sec = 30; tm.tv_usec = 0; uint64_t elapsed = DurationReporter::nanotime(); int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm)); if (ret == -1) { printf("*** %s: select failed: %s\n", path, strerror(errno)); newline = true; break; } else if (ret == 0) { elapsed = DurationReporter::nanotime() - elapsed; printf("*** %s: Timed out after %.3fs\n", path, (float) elapsed / NANOS_PER_SEC); newline = true; break; } else { char buffer[65536]; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); if (bytes_read > 0) { fwrite(buffer, bytes_read, 1, stdout); newline = (buffer[bytes_read-1] == '\n'); } else { if (bytes_read == -1) { printf("*** %s: Failed to read from fd: %s", path, strerror(errno)); newline = true; } break; } } } update_progress(WEIGHT_FILE); close(fd); if (!newline) printf("\n"); if (title) printf("\n"); return 0; } /* prints the contents of a file */ int dump_file(const char *title, const char *path) { DurationReporter duration_reporter(title); int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); if (fd < 0) { int err = errno; printf("*** %s: %s\n", path, strerror(err)); if (title) printf("\n"); return -1; } return _dump_file_from_fd(title, path, fd); } int read_file_as_long(const char *path, long int *output) { int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); if (fd < 0) { int err = errno; MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err)); return -1; } char buffer[50]; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); if (bytes_read == -1) { MYLOGE("Error reading file %s: %s\n", path, strerror(errno)); return -2; } if (bytes_read == 0) { MYLOGE("File %s is empty\n", path); return -3; } *output = atoi(buffer); return 0; } /* calls skip to gate calling dump_from_fd recursively * in the specified directory. dump_from_fd defaults to * dump_file_from_fd above when set to NULL. skip defaults * to false when set to NULL. dump_from_fd will always be * called with title NULL. */ int dump_files(const char *title, const char *dir, bool (*skip)(const char *path), int (*dump_from_fd)(const char *title, const char *path, int fd)) { DurationReporter duration_reporter(title); DIR *dirp; struct dirent *d; char *newpath = NULL; const char *slash = "/"; int fd, retval = 0; if (title) { printf("------ %s (%s) ------\n", title, dir); } ON_DRY_RUN_RETURN(0); if (dir[strlen(dir) - 1] == '/') { ++slash; } dirp = opendir(dir); if (dirp == NULL) { retval = -errno; MYLOGE("%s: %s\n", dir, strerror(errno)); return retval; } if (!dump_from_fd) { dump_from_fd = dump_file_from_fd; } for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) { if ((d->d_name[0] == '.') && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) || (d->d_name[1] == '\0'))) { continue; } asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name, (d->d_type == DT_DIR) ? "/" : ""); if (!newpath) { retval = -errno; continue; } if (skip && (*skip)(newpath)) { continue; } if (d->d_type == DT_DIR) { int ret = dump_files(NULL, newpath, skip, dump_from_fd); if (ret < 0) { retval = ret; } continue; } fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); if (fd < 0) { retval = fd; printf("*** %s: %s\n", newpath, strerror(errno)); continue; } (*dump_from_fd)(NULL, newpath, fd); } closedir(dirp); if (title) { printf("\n"); } return retval; } /* fd must have been opened with the flag O_NONBLOCK. With this flag set, * it's possible to avoid issues where opening the file itself can get * stuck. */ int dump_file_from_fd(const char *title, const char *path, int fd) { int flags = fcntl(fd, F_GETFL); if (flags == -1) { printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno)); close(fd); return -1; } else if (!(flags & O_NONBLOCK)) { printf("*** %s: fd must have O_NONBLOCK set.\n", path); close(fd); return -1; } return _dump_file_from_fd(title, path, fd); } bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { sigset_t child_mask, old_mask; sigemptyset(&child_mask); sigaddset(&child_mask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) { printf("*** sigprocmask failed: %s\n", strerror(errno)); return false; } struct timespec ts; ts.tv_sec = timeout_seconds; ts.tv_nsec = 0; int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts)); int saved_errno = errno; // Set the signals back the way they were. if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) { printf("*** sigprocmask failed: %s\n", strerror(errno)); if (ret == 0) { return false; } } if (ret == -1) { errno = saved_errno; if (errno == EAGAIN) { errno = ETIMEDOUT; } else { printf("*** sigtimedwait failed: %s\n", strerror(errno)); } return false; } pid_t child_pid = waitpid(pid, status, WNOHANG); if (child_pid != pid) { if (child_pid != -1) { printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); } else { printf("*** waitpid failed: %s\n", strerror(errno)); } return false; } return true; } // TODO: refactor all those commands that convert args void format_args(const char* command, const char *args[], std::string *string); int run_command(const char *title, int timeout_seconds, const char *command, ...) { DurationReporter duration_reporter(title); fflush(stdout); const char *args[1024] = {command}; size_t arg; va_list ap; va_start(ap, command); if (title) printf("------ %s (%s", title, command); bool null_terminated = false; for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) { args[arg] = va_arg(ap, const char *); if (args[arg] == nullptr) { null_terminated = true; break; } // TODO: null_terminated check is not really working; line below would crash dumpstate if // nullptr is missing if (title) printf(" %s", args[arg]); } if (title) printf(") ------\n"); fflush(stdout); if (!null_terminated) { // Fail now, otherwise execvp() call on run_command_always() might hang. std::string cmd; format_args(command, args, &cmd); MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str()); return -1; } ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; }); int status = run_command_always(title, DONT_DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args); va_end(ap); return status; } int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) { DurationReporter duration_reporter(title); fflush(stdout); const char *args[1024] = {command}; size_t arg; va_list ap; va_start(ap, command); if (title) printf("------ %s (%s", title, command); bool null_terminated = false; for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) { args[arg] = va_arg(ap, const char *); if (args[arg] == nullptr) { null_terminated = true; break; } // TODO: null_terminated check is not really working; line below would crash dumpstate if // nullptr is missing if (title) printf(" %s", args[arg]); } if (title) printf(") ------\n"); fflush(stdout); if (!null_terminated) { // Fail now, otherwise execvp() call on run_command_always() might hang. std::string cmd; format_args(command, args, &cmd); MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str()); return -1; } ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; }); int status = run_command_always(title, DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args); va_end(ap); return status; } /* forks a command and waits for it to finish */ int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode, int timeout_seconds, const char *args[]) { bool silent = (stdout_mode == REDIRECT_TO_STDERR); // TODO: need to check if args is null-terminated, otherwise execvp will crash dumpstate /* TODO: for now we're simplifying the progress calculation by using the timeout as the weight. * It's a good approximation for most cases, except when calling dumpsys, where its weight * should be much higher proportionally to its timeout. */ int weight = timeout_seconds; const char *command = args[0]; uint64_t start = DurationReporter::nanotime(); pid_t pid = fork(); /* handle error case */ if (pid < 0) { if (!silent) printf("*** fork: %s\n", strerror(errno)); MYLOGE("*** fork: %s\n", strerror(errno)); return pid; } /* handle child case */ if (pid == 0) { if (root_mode == DROP_ROOT && !drop_root_user()) { if (!silent) printf("*** fail todrop root before running %s: %s\n", command, strerror(errno)); MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno)); return -1; } if (silent) { // Redirect stderr to stdout dup2(STDERR_FILENO, STDOUT_FILENO); } /* make sure the child dies when dumpstate dies */ prctl(PR_SET_PDEATHSIG, SIGKILL); /* just ignore SIGPIPE, will go down with parent's */ struct sigaction sigact; memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigact, NULL); execvp(command, (char**) args); // execvp's result will be handled after waitpid_with_timeout() below, but if it failed, // it's safer to exit dumpstate. MYLOGD("execvp on command '%s' failed (error: %s)", command, strerror(errno)); fflush(stdout); // Must call _exit (instead of exit), otherwise it will corrupt the zip file. _exit(EXIT_FAILURE); } /* handle parent case */ int status; bool ret = waitpid_with_timeout(pid, timeout_seconds, &status); uint64_t elapsed = DurationReporter::nanotime() - start; std::string cmd; // used to log command and its args if (!ret) { if (errno == ETIMEDOUT) { format_args(command, args, &cmd); if (!silent) printf("*** command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid); MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid); } else { format_args(command, args, &cmd); if (!silent) printf("*** command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid); MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid); } kill(pid, SIGTERM); if (!waitpid_with_timeout(pid, 5, NULL)) { kill(pid, SIGKILL); if (!waitpid_with_timeout(pid, 5, NULL)) { if (!silent) printf("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid); MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid); } } return -1; } else if (status) { format_args(command, args, &cmd); if (!silent) printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno)); MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno)); return -2; } if (WIFSIGNALED(status)) { if (!silent) printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); MYLOGE("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) { if (!silent) printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); MYLOGE("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); } if (weight > 0) { update_progress(weight); } return status; } bool drop_root_user() { if (getgid() == AID_SHELL && getuid() == AID_SHELL) { MYLOGD("drop_root_user(): already running as Shell"); return true; } /* ensure we will keep capabilities when we drop root */ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); return false; } gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); return false; } if (setgid(AID_SHELL) != 0) { MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno)); return false; } if (setuid(AID_SHELL) != 0) { MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno)); return false; } struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); capdata[0].inheritable = 0; capdata[1].inheritable = 0; if (capset(&capheader, &capdata[0]) < 0) { MYLOGE("capset failed: %s\n", strerror(errno)); return false; } return true; } void send_broadcast(const std::string& action, const std::vector& args) { if (args.size() > 1000) { MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size()); return; } const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a", action.c_str() }; size_t am_index = 5; // Starts at the index of last initial value above. for (const std::string& arg : args) { am_args[++am_index] = arg.c_str(); } // Always terminate with NULL. am_args[am_index + 1] = NULL; std::string args_string; format_args(am_index + 1, am_args, &args_string); MYLOGD("send_broadcast command: %s\n", args_string.c_str()); run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args); } size_t num_props = 0; static char* props[2000]; static void print_prop(const char *key, const char *name, void *user) { (void) user; if (num_props < sizeof(props) / sizeof(props[0])) { char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10]; snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name); props[num_props++] = strdup(buf); } } static int compare_prop(const void *a, const void *b) { return strcmp(*(char * const *) a, *(char * const *) b); } /* prints all the system properties */ void print_properties() { const char* title = "SYSTEM PROPERTIES"; DurationReporter duration_reporter(title); printf("------ %s ------\n", title); ON_DRY_RUN_RETURN(); size_t i; num_props = 0; property_list(print_prop, NULL); qsort(&props, num_props, sizeof(props[0]), compare_prop); for (i = 0; i < num_props; ++i) { fputs(props[i], stdout); free(props[i]); } printf("\n"); } int open_socket(const char *service) { int s = android_get_control_socket(service); if (s < 0) { MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno)); exit(1); } fcntl(s, F_SETFD, FD_CLOEXEC); if (listen(s, 4) < 0) { MYLOGE("listen(control socket): %s\n", strerror(errno)); exit(1); } struct sockaddr addr; socklen_t alen = sizeof(addr); int fd = accept(s, &addr, &alen); if (fd < 0) { MYLOGE("accept(control socket): %s\n", strerror(errno)); exit(1); } return fd; } /* redirect output to a service control socket */ void redirect_to_socket(FILE *redirect, const char *service) { int fd = open_socket(service); fflush(redirect); dup2(fd, fileno(redirect)); close(fd); } // TODO: should call is_valid_output_file and/or be merged into it. void create_parent_dirs(const char *path) { char *chp = const_cast (path); /* skip initial slash */ if (chp[0] == '/') chp++; /* create leading directories, if necessary */ struct stat dir_stat; while (chp && chp[0]) { chp = strchr(chp, '/'); if (chp) { *chp = 0; if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) { MYLOGI("Creating directory %s\n", path); if (mkdir(path, 0770)) { /* drwxrwx--- */ MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno)); } else if (chown(path, AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno)); } } *chp++ = '/'; } } } /* redirect output to a file */ void redirect_to_file(FILE *redirect, char *path) { create_parent_dirs(path); int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); if (fd < 0) { MYLOGE("%s: %s\n", path, strerror(errno)); exit(1); } TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); close(fd); } static bool should_dump_native_traces(const char* path) { for (const char** p = native_processes_to_dump; *p; p++) { if (!strcmp(*p, path)) { return true; } } return false; } /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { DurationReporter duration_reporter("DUMP TRACES", NULL); ON_DRY_RUN_RETURN(NULL); const char* result = NULL; char traces_path[PROPERTY_VALUE_MAX] = ""; property_get("dalvik.vm.stack-trace-file", traces_path, ""); if (!traces_path[0]) return NULL; /* move the old traces.txt (if any) out of the way temporarily */ char anr_traces_path[PATH_MAX]; strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path)); strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path)); if (rename(traces_path, anr_traces_path) && errno != ENOENT) { MYLOGE("rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno)); return NULL; // Can't rename old traces.txt -- no permission? -- leave it alone instead } /* create a new, empty traces.txt file to receive stack dumps */ int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 0666)); /* -rw-rw-rw- */ if (fd < 0) { MYLOGE("%s: %s\n", traces_path, strerror(errno)); return NULL; } int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { MYLOGE("fchmod on %s failed: %s\n", traces_path, strerror(errno)); close(fd); return NULL; } /* Variables below must be initialized before 'goto' statements */ int dalvik_found = 0; int ifd, wfd = -1; /* walk /proc and kill -QUIT all Dalvik processes */ DIR *proc = opendir("/proc"); if (proc == NULL) { MYLOGE("/proc: %s\n", strerror(errno)); goto error_close_fd; } /* use inotify to find when processes are done dumping */ ifd = inotify_init(); if (ifd < 0) { MYLOGE("inotify_init: %s\n", strerror(errno)); goto error_close_fd; } wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE); if (wfd < 0) { MYLOGE("inotify_add_watch(%s): %s\n", traces_path, strerror(errno)); goto error_close_ifd; } struct dirent *d; while ((d = readdir(proc))) { int pid = atoi(d->d_name); if (pid <= 0) continue; char path[PATH_MAX]; char data[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/exe", pid); ssize_t len = readlink(path, data, sizeof(data) - 1); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) { /* skip zygote -- it won't dump its stack anyway */ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)); len = read(cfd, data, sizeof(data) - 1); close(cfd); if (len <= 0) { continue; } data[len] = '\0'; if (!strncmp(data, "zygote", strlen("zygote"))) { continue; } ++dalvik_found; uint64_t start = DurationReporter::nanotime(); if (kill(pid, SIGQUIT)) { MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); continue; } /* wait for the writable-close notification from inotify */ struct pollfd pfd = { ifd, POLLIN, 0 }; int ret = poll(&pfd, 1, 5000); /* 5 sec timeout */ if (ret < 0) { MYLOGE("poll: %s\n", strerror(errno)); } else if (ret == 0) { MYLOGE("warning: timed out dumping pid %d\n", pid); } else { struct inotify_event ie; read(ifd, &ie, sizeof(ie)); } if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid, (float)(DurationReporter::nanotime() - start) / NANOS_PER_SEC); } } else if (should_dump_native_traces(data)) { /* dump native process if appropriate */ if (lseek(fd, 0, SEEK_END) < 0) { MYLOGE("lseek: %s\n", strerror(errno)); } else { static uint16_t timeout_failures = 0; uint64_t start = DurationReporter::nanotime(); /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */ if (timeout_failures == 3) { dprintf(fd, "too many stack dump failures, skipping...\n"); } else if (dump_backtrace_to_file_timeout(pid, fd, 20) == -1) { dprintf(fd, "dumping failed, likely due to a timeout\n"); timeout_failures++; } else { timeout_failures = 0; } dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid, (float)(DurationReporter::nanotime() - start) / NANOS_PER_SEC); } } } if (dalvik_found == 0) { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } static char dump_traces_path[PATH_MAX]; strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path)); strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path)); if (rename(traces_path, dump_traces_path)) { MYLOGE("rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno)); goto error_close_ifd; } result = dump_traces_path; /* replace the saved [ANR] traces.txt file */ rename(anr_traces_path, traces_path); error_close_ifd: close(ifd); error_close_fd: close(fd); return result; } void dump_route_tables() { DurationReporter duration_reporter("DUMP ROUTE TABLES"); ON_DRY_RUN_RETURN(); const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables"; dump_file("RT_TABLES", RT_TABLES_PATH); FILE* fp = fopen(RT_TABLES_PATH, "re"); if (!fp) { printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno)); return; } char table[16]; // Each line has an integer (the table number), a space, and a string (the table name). We only // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name. // Add a fixed max limit so this doesn't go awry. for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) { run_command("ROUTE TABLE IPv4", 10, "ip", "-4", "route", "show", "table", table, NULL); run_command("ROUTE TABLE IPv6", 10, "ip", "-6", "route", "show", "table", table, NULL); } fclose(fp); } /* overall progress */ int progress = 0; int do_update_progress = 0; // Set by dumpstate.cpp int weight_total = WEIGHT_TOTAL; // TODO: make this function thread safe if sections are generated in parallel. void update_progress(int delta) { if (!do_update_progress) return; progress += delta; char key[PROPERTY_KEY_MAX]; char value[PROPERTY_VALUE_MAX]; // adjusts max on the fly if (progress > weight_total) { int new_total = weight_total * 1.2; MYLOGD("Adjusting total weight from %d to %d\n", weight_total, new_total); weight_total = new_total; snprintf(key, sizeof(key), "dumpstate.%d.max", getpid()); snprintf(value, sizeof(value), "%d", weight_total); int status = property_set(key, value); if (status) { MYLOGE("Could not update max weight by setting system property %s to %s: %d\n", key, value, status); } } snprintf(key, sizeof(key), "dumpstate.%d.progress", getpid()); snprintf(value, sizeof(value), "%d", progress); if (progress % 100 == 0) { // We don't want to spam logcat, so only log multiples of 100. MYLOGD("Setting progress (%s): %s/%d\n", key, value, weight_total); } else { // stderr is ignored on normal invocations, but useful when calling /system/bin/dumpstate // directly for debuggging. fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total); } int status = property_set(key, value); if (status) { MYLOGE("Could not update progress by setting system property %s to %s: %d\n", key, value, status); } } void take_screenshot(const std::string& path) { const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL }; run_command_always(NULL, DONT_DROP_ROOT, REDIRECT_TO_STDERR, 10, args); } void vibrate(FILE* vibrator, int ms) { fprintf(vibrator, "%d\n", ms); fflush(vibrator); } bool is_dir(const char* pathname) { struct stat info; if (stat(pathname, &info) == -1) { return false; } return S_ISDIR(info.st_mode); } time_t get_mtime(int fd, time_t default_mtime) { struct stat info; if (fstat(fd, &info) == -1) { return default_mtime; } return info.st_mtime; } void dump_emmc_ecsd(const char *ext_csd_path) { static const size_t EXT_CSD_REV = 192; static const size_t EXT_PRE_EOL_INFO = 267; static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268; static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269; struct hex { char str[2]; } buffer[512]; int fd, ext_csd_rev, ext_pre_eol_info; ssize_t bytes_read; static const char *ver_str[] = { "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0" }; static const char *eol_str[] = { "Undefined", "Normal", "Warning (consumed 80% of reserve)", "Urgent (consumed 90% of reserve)" }; printf("------ %s Extended CSD ------\n", ext_csd_path); fd = TEMP_FAILURE_RETRY(open(ext_csd_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); if (fd < 0) { printf("*** %s: %s\n\n", ext_csd_path, strerror(errno)); return; } bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); close(fd); if (bytes_read < 0) { printf("*** %s: %s\n\n", ext_csd_path, strerror(errno)); return; } if (bytes_read < (ssize_t)(EXT_CSD_REV * sizeof(struct hex))) { printf("*** %s: truncated content %zd\n\n", ext_csd_path, bytes_read); return; } ext_csd_rev = 0; if (sscanf(buffer[EXT_CSD_REV].str, "%02x", &ext_csd_rev) != 1) { printf("*** %s: EXT_CSD_REV parse error \"%.2s\"\n\n", ext_csd_path, buffer[EXT_CSD_REV].str); return; } printf("rev 1.%d (MMC %s)\n", ext_csd_rev, (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev] : "Unknown"); if (ext_csd_rev < 7) { printf("\n"); return; } if (bytes_read < (ssize_t)(EXT_PRE_EOL_INFO * sizeof(struct hex))) { printf("*** %s: truncated content %zd\n\n", ext_csd_path, bytes_read); return; } ext_pre_eol_info = 0; if (sscanf(buffer[EXT_PRE_EOL_INFO].str, "%02x", &ext_pre_eol_info) != 1) { printf("*** %s: PRE_EOL_INFO parse error \"%.2s\"\n\n", ext_csd_path, buffer[EXT_PRE_EOL_INFO].str); return; } printf("PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info, eol_str[(ext_pre_eol_info < (int) (sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info : 0]); for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A; lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B; ++lifetime) { int ext_device_life_time_est; static const char *est_str[] = { "Undefined", "0-10% of device lifetime used", "10-20% of device lifetime used", "20-30% of device lifetime used", "30-40% of device lifetime used", "40-50% of device lifetime used", "50-60% of device lifetime used", "60-70% of device lifetime used", "70-80% of device lifetime used", "80-90% of device lifetime used", "90-100% of device lifetime used", "Exceeded the maximum estimated device lifetime", }; if (bytes_read < (ssize_t)(lifetime * sizeof(struct hex))) { printf("*** %s: truncated content %zd\n", ext_csd_path, bytes_read); break; } ext_device_life_time_est = 0; if (sscanf(buffer[lifetime].str, "%02x", &ext_device_life_time_est) != 1) { printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%.2s\"\n", ext_csd_path, (unsigned)(lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) + 'A', buffer[lifetime].str); continue; } printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n", (unsigned)(lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) + 'A', ext_device_life_time_est, est_str[(ext_device_life_time_est < (int) (sizeof(est_str) / sizeof(est_str[0]))) ? ext_device_life_time_est : 0]); } printf("\n"); } // TODO: refactor all those commands that convert args void format_args(int argc, const char *argv[], std::string *args) { LOG_ALWAYS_FATAL_IF(args == nullptr); for (int i = 0; i < argc; i++) { args->append(argv[i]); if (i < argc -1) { args->append(" "); } } } void format_args(const char* command, const char *args[], std::string *string) { LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr); string->append(command); if (args[0] == nullptr) return; string->append(" "); for (int arg = 1; arg <= 1000; ++arg) { if (args[arg] == nullptr) return; string->append(args[arg]); if (args[arg+1] != nullptr) { string->append(" "); } } // TODO: not really working: if NULL is missing, it will crash dumpstate. MYLOGE("internal error: missing NULL entry on %s", string->c_str()); } cmds/dumpsys/0040755 0000000 0000000 00000000000 13077405420 012244 5ustar000000000 0000000 cmds/dumpsys/Android.mk0100644 0000000 0000000 00000000461 13077405420 014153 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ dumpsys.cpp LOCAL_SHARED_LIBRARIES := \ libbase \ libutils \ liblog \ libbinder ifeq ($(TARGET_OS),linux) LOCAL_CFLAGS += -DXP_UNIX #LOCAL_SHARED_LIBRARIES += librt endif LOCAL_MODULE:= dumpsys include $(BUILD_EXECUTABLE) cmds/dumpsys/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 015364 0ustar000000000 0000000 cmds/dumpsys/NOTICE0100644 0000000 0000000 00000024707 13077405420 013157 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS cmds/dumpsys/dumpsys.cpp0100644 0000000 0000000 00000020556 13077405420 014461 0ustar000000000 0000000 /* * Command that dumps interesting system state to the log. * */ #define LOG_TAG "dumpsys" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; using android::base::unique_fd; using android::base::WriteFully; static int sort_func(const String16* lhs, const String16* rhs) { return lhs->compare(*rhs); } static void usage() { fprintf(stderr, "usage: dumpsys\n" " To dump all services.\n" "or:\n" " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n" " --help: shows this help\n" " -l: only list services, do not dump them\n" " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n" " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n" " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n"); } bool IsSkipped(const Vector& skipped, const String16& service) { for (const auto& candidate : skipped) { if (candidate == service) { return true; } } return false; } int main(int argc, char* const argv[]) { signal(SIGPIPE, SIG_IGN); sp sm = defaultServiceManager(); fflush(stdout); if (sm == NULL) { ALOGE("Unable to get default service manager!"); aerr << "dumpsys: Unable to get default service manager!" << endl; return 20; } Vector services; Vector args; Vector skippedServices; bool showListOnly = false; bool skipServices = false; int timeoutArg = 10; static struct option longOptions[] = { {"skip", no_argument, 0, 0 }, {"help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; while (1) { int c; int optionIndex = 0; c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex); if (c == -1) { break; } switch (c) { case 0: if (!strcmp(longOptions[optionIndex].name, "skip")) { skipServices = true; } else if (!strcmp(longOptions[optionIndex].name, "help")) { usage(); return 0; } break; case 't': { char *endptr; timeoutArg = strtol(optarg, &endptr, 10); if (*endptr != '\0' || timeoutArg <= 0) { fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg); return -1; } } break; case 'l': showListOnly = true; break; default: fprintf(stderr, "\n"); usage(); return -1; } } for (int i = optind; i < argc; i++) { if (skipServices) { skippedServices.add(String16(argv[i])); } else { if (i == optind) { services.add(String16(argv[i])); } else { args.add(String16(argv[i])); } } } if ((skipServices && skippedServices.empty()) || (showListOnly && (!services.empty() || !skippedServices.empty()))) { usage(); return -1; } if (services.empty() || showListOnly) { // gets all services services = sm->listServices(); services.sort(sort_func); args.add(String16("-a")); } const size_t N = services.size(); if (N > 1) { // first print a list of the current services aout << "Currently running services:" << endl; for (size_t i=0; i service = sm->checkService(services[i]); if (service != NULL) { bool skipped = IsSkipped(skippedServices, services[i]); aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl; } } } if (showListOnly) { return 0; } for (size_t i = 0; i < N; i++) { String16 service_name = std::move(services[i]); if (IsSkipped(skippedServices, service_name)) continue; sp service = sm->checkService(service_name); if (service != NULL) { int sfd[2]; if (pipe(sfd) != 0) { aerr << "Failed to create pipe to dump service info for " << service_name << ": " << strerror(errno) << endl; continue; } unique_fd local_end(sfd[0]); unique_fd remote_end(sfd[1]); sfd[0] = sfd[1] = -1; if (N > 1) { aout << "------------------------------------------------------------" "-------------------" << endl; aout << "DUMP OF SERVICE " << service_name << ":" << endl; } // dump blocks until completion, so spawn a thread.. std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable { int err = service->dump(remote_end.get(), args); // It'd be nice to be able to close the remote end of the socketpair before the dump // call returns, to terminate our reads if the other end closes their copy of the // file descriptor, but then hangs for some reason. There doesn't seem to be a good // way to do this, though. remote_end.clear(); if (err != 0) { aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name << endl; } }); auto timeout = std::chrono::seconds(timeoutArg); auto end = std::chrono::steady_clock::now() + timeout; struct pollfd pfd = { .fd = local_end.get(), .events = POLLIN }; bool timed_out = false; bool error = false; while (true) { // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout. auto time_left_ms = [end]() { auto now = std::chrono::steady_clock::now(); auto diff = std::chrono::duration_cast(end - now); return std::max(diff.count(), 0ll); }; int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); if (rc < 0) { aerr << "Error in poll while dumping service " << service_name << " : " << strerror(errno) << endl; error = true; break; } else if (rc == 0) { timed_out = true; break; } char buf[4096]; rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf))); if (rc < 0) { aerr << "Failed to read while dumping service " << service_name << ": " << strerror(errno) << endl; error = true; break; } else if (rc == 0) { // EOF. break; } if (!WriteFully(STDOUT_FILENO, buf, rc)) { aerr << "Failed to write while dumping service " << service_name << ": " << strerror(errno) << endl; error = true; break; } } if (timed_out) { aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl; } if (timed_out || error) { dump_thread.detach(); } else { dump_thread.join(); } } else { aerr << "Can't find service: " << service_name << endl; } } return 0; } cmds/flatland/0040755 0000000 0000000 00000000000 13077405420 012325 5ustar000000000 0000000 cmds/flatland/Android.mk0100644 0000000 0000000 00000001061 13077405420 014231 0ustar000000000 0000000 local_target_dir := $(TARGET_OUT_DATA)/local/tmp LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ Composers.cpp \ GLHelper.cpp \ Renderers.cpp \ Main.cpp \ LOCAL_MODULE:= flatland LOCAL_MODULE_TAGS := tests LOCAL_MODULE_PATH := $(local_target_dir) LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := flatland LOCAL_MODULE_STEM_64 := flatland64 LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv2 \ libcutils \ libgui \ libui \ libutils \ include $(BUILD_EXECUTABLE) cmds/flatland/Composers.cpp0100644 0000000 0000000 00000017266 13077405420 015014 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include "Flatland.h" #include "GLHelper.h" namespace android { class Blitter { public: bool setUp(GLHelper* helper) { bool result; result = helper->getShaderProgram("Blit", &mBlitPgm); if (!result) { return false; } mPosAttribLoc = glGetAttribLocation(mBlitPgm, "position"); mUVAttribLoc = glGetAttribLocation(mBlitPgm, "uv"); mUVToTexUniformLoc = glGetUniformLocation(mBlitPgm, "uvToTex"); mObjToNdcUniformLoc = glGetUniformLocation(mBlitPgm, "objToNdc"); mBlitSrcSamplerLoc = glGetUniformLocation(mBlitPgm, "blitSrc"); mModColorUniformLoc = glGetUniformLocation(mBlitPgm, "modColor"); return true; } bool blit(GLuint texName, const float* texMatrix, int32_t x, int32_t y, uint32_t w, uint32_t h) { float modColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; return modBlit(texName, texMatrix, modColor, x, y, w, h); } bool modBlit(GLuint texName, const float* texMatrix, float* modColor, int32_t x, int32_t y, uint32_t w, uint32_t h) { glUseProgram(mBlitPgm); GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); float screenToNdc[16] = { 2.0f/float(vp[2]), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f/float(vp[3]), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, }; const float pos[] = { float(x), float(y), float(x+w), float(y), float(x), float(y+h), float(x+w), float(y+h), }; const float uv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, }; glVertexAttribPointer(mPosAttribLoc, 2, GL_FLOAT, GL_FALSE, 0, pos); glVertexAttribPointer(mUVAttribLoc, 2, GL_FLOAT, GL_FALSE, 0, uv); glEnableVertexAttribArray(mPosAttribLoc); glEnableVertexAttribArray(mUVAttribLoc); glUniformMatrix4fv(mObjToNdcUniformLoc, 1, GL_FALSE, screenToNdc); glUniformMatrix4fv(mUVToTexUniformLoc, 1, GL_FALSE, texMatrix); glUniform4fv(mModColorUniformLoc, 1, modColor); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texName); glUniform1i(mBlitSrcSamplerLoc, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(mPosAttribLoc); glDisableVertexAttribArray(mUVAttribLoc); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "GL error!\n"); } return true; } private: GLuint mBlitPgm; GLint mPosAttribLoc; GLint mUVAttribLoc; GLint mUVToTexUniformLoc; GLint mObjToNdcUniformLoc; GLint mBlitSrcSamplerLoc; GLint mModColorUniformLoc; }; class ComposerBase : public Composer { public: virtual ~ComposerBase() {} virtual bool setUp(const LayerDesc& desc, GLHelper* helper) { mLayerDesc = desc; return setUp(helper); } virtual void tearDown() { } virtual bool compose(GLuint /*texName*/, const sp& /*glc*/) { return true; } protected: virtual bool setUp(GLHelper* /*helper*/) { return true; } LayerDesc mLayerDesc; }; Composer* nocomp() { class NoComp : public ComposerBase { }; return new NoComp(); } Composer* opaque() { class OpaqueComp : public ComposerBase { virtual bool setUp(GLHelper* helper) { return mBlitter.setUp(helper); } virtual bool compose(GLuint texName, const sp& glc) { float texMatrix[16]; glc->getTransformMatrix(texMatrix); int32_t x = mLayerDesc.x; int32_t y = mLayerDesc.y; int32_t w = mLayerDesc.width; int32_t h = mLayerDesc.height; return mBlitter.blit(texName, texMatrix, x, y, w, h); } Blitter mBlitter; }; return new OpaqueComp(); } Composer* opaqueShrink() { class OpaqueComp : public ComposerBase { virtual bool setUp(GLHelper* helper) { mParity = false; return mBlitter.setUp(helper); } virtual bool compose(GLuint texName, const sp& glc) { float texMatrix[16]; glc->getTransformMatrix(texMatrix); int32_t x = mLayerDesc.x; int32_t y = mLayerDesc.y; int32_t w = mLayerDesc.width; int32_t h = mLayerDesc.height; mParity = !mParity; if (mParity) { x += w / 128; y += h / 128; w -= w / 64; h -= h / 64; } return mBlitter.blit(texName, texMatrix, x, y, w, h); } Blitter mBlitter; bool mParity; }; return new OpaqueComp(); } Composer* blend() { class BlendComp : public ComposerBase { virtual bool setUp(GLHelper* helper) { return mBlitter.setUp(helper); } virtual bool compose(GLuint texName, const sp& glc) { bool result; float texMatrix[16]; glc->getTransformMatrix(texMatrix); float modColor[4] = { .75f, .75f, .75f, .75f }; int32_t x = mLayerDesc.x; int32_t y = mLayerDesc.y; int32_t w = mLayerDesc.width; int32_t h = mLayerDesc.height; glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); result = mBlitter.modBlit(texName, texMatrix, modColor, x, y, w, h); if (!result) { return false; } glDisable(GL_BLEND); return true; } Blitter mBlitter; }; return new BlendComp(); } Composer* blendShrink() { class BlendShrinkComp : public ComposerBase { virtual bool setUp(GLHelper* helper) { mParity = false; return mBlitter.setUp(helper); } virtual bool compose(GLuint texName, const sp& glc) { bool result; float texMatrix[16]; glc->getTransformMatrix(texMatrix); float modColor[4] = { .75f, .75f, .75f, .75f }; int32_t x = mLayerDesc.x; int32_t y = mLayerDesc.y; int32_t w = mLayerDesc.width; int32_t h = mLayerDesc.height; mParity = !mParity; if (mParity) { x += w / 128; y += h / 128; w -= w / 64; h -= h / 64; } glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); result = mBlitter.modBlit(texName, texMatrix, modColor, x, y, w, h); if (!result) { return false; } glDisable(GL_BLEND); return true; } Blitter mBlitter; bool mParity; }; return new BlendShrinkComp(); } } // namespace android cmds/flatland/Flatland.h0100644 0000000 0000000 00000003237 13077405420 014225 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include namespace android { #define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0]))) enum { MAX_NUM_LAYERS = 16 }; enum { MAX_TEST_RUNS = 16 }; class Composer; class Renderer; class GLHelper; struct LayerDesc { uint32_t flags; Renderer* (*rendererFactory)(); Composer* (*composerFactory)(); int32_t x; int32_t y; uint32_t width; uint32_t height; }; void resetColorGenerator(); class Composer { public: virtual ~Composer() {} virtual bool setUp(const LayerDesc& desc, GLHelper* helper) = 0; virtual void tearDown() = 0; virtual bool compose(GLuint texName, const sp& glc) = 0; }; Composer* nocomp(); Composer* opaque(); Composer* opaqueShrink(); Composer* blend(); Composer* blendShrink(); class Renderer { public: virtual ~Renderer() {} virtual bool setUp(GLHelper* helper) = 0; virtual void tearDown() = 0; virtual bool render(EGLSurface surface) = 0; }; Renderer* staticGradient(); } // namespace android cmds/flatland/GLHelper.cpp0100644 0000000 0000000 00000031653 13077405420 014500 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include #include "GLHelper.h" namespace android { GLHelper::GLHelper() : mGraphicBufferAlloc(new GraphicBufferAlloc()), mDisplay(EGL_NO_DISPLAY), mContext(EGL_NO_CONTEXT), mDummySurface(EGL_NO_SURFACE), mConfig(0), mShaderPrograms(NULL), mDitherTexture(0) { } GLHelper::~GLHelper() { } bool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) { bool result; mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mDisplay == EGL_NO_DISPLAY) { fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError()); return false; } EGLint majorVersion; EGLint minorVersion; result = eglInitialize(mDisplay, &majorVersion, &minorVersion); if (result != EGL_TRUE) { fprintf(stderr, "eglInitialize error: %#x\n", eglGetError()); return false; } EGLint numConfigs = 0; EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs); if (result != EGL_TRUE) { fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError()); return false; } EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs); if (mContext == EGL_NO_CONTEXT) { fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError()); return false; } bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer, &mDummySurface); if (!resultb) { return false; } resultb = makeCurrent(mDummySurface); if (!resultb) { return false; } resultb = setUpShaders(shaderDescs, numShaders); if (!resultb) { return false; } return true; } void GLHelper::tearDown() { if (mShaderPrograms != NULL) { delete[] mShaderPrograms; mShaderPrograms = NULL; } if (mSurfaceComposerClient != NULL) { mSurfaceComposerClient->dispose(); mSurfaceComposerClient.clear(); } if (mDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } if (mContext != EGL_NO_CONTEXT) { eglDestroyContext(mDisplay, mContext); } if (mDummySurface != EGL_NO_SURFACE) { eglDestroySurface(mDisplay, mDummySurface); } mDisplay = EGL_NO_DISPLAY; mContext = EGL_NO_CONTEXT; mDummySurface = EGL_NO_SURFACE; mDummyGLConsumer.clear(); mConfig = 0; } bool GLHelper::makeCurrent(EGLSurface surface) { EGLint result; result = eglMakeCurrent(mDisplay, surface, surface, mContext); if (result != EGL_TRUE) { fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError()); return false; } EGLint w, h; eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w); eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h); glViewport(0, 0, w, h); return true; } bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h, sp* glConsumer, EGLSurface* surface, GLuint* name) { if (!makeCurrent(mDummySurface)) { return false; } *name = 0; glGenTextures(1, name); if (*name == 0) { fprintf(stderr, "glGenTextures error: %#x\n", glGetError()); return false; } return createNamedSurfaceTexture(*name, w, h, glConsumer, surface); } void GLHelper::destroySurface(EGLSurface* surface) { if (eglGetCurrentSurface(EGL_READ) == *surface || eglGetCurrentSurface(EGL_DRAW) == *surface) { eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } eglDestroySurface(mDisplay, *surface); *surface = EGL_NO_SURFACE; } bool GLHelper::swapBuffers(EGLSurface surface) { EGLint result; result = eglSwapBuffers(mDisplay, surface); if (result != EGL_TRUE) { fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError()); return false; } return true; } bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { for (size_t i = 0; i < mNumShaders; i++) { if (strcmp(mShaderDescs[i].name, name) == 0) { *outPgm = mShaderPrograms[i]; return true; } } fprintf(stderr, "unknown shader name: \"%s\"\n", name); return false; } bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp* glConsumer, EGLSurface* surface) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc); sp glc = new GLConsumer(consumer, name, GL_TEXTURE_EXTERNAL_OES, false, true); glc->setDefaultBufferSize(w, h); producer->setMaxDequeuedBufferCount(2); glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); sp anw = new Surface(producer); EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); if (s == EGL_NO_SURFACE) { fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); return false; } *glConsumer = glc; *surface = s; return true; } bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { sp dpy = mSurfaceComposerClient->getBuiltInDisplay(0); if (dpy == NULL) { fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n"); return false; } DisplayInfo info; status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err); return false; } float scaleX = float(info.w) / float(w); float scaleY = float(info.h) / float(h); *scale = scaleX < scaleY ? scaleX : scaleY; return true; } bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, sp* surfaceControl, EGLSurface* surface) { bool result; status_t err; if (mSurfaceComposerClient == NULL) { mSurfaceComposerClient = new SurfaceComposerClient; } err = mSurfaceComposerClient->initCheck(); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); return false; } sp sc = mSurfaceComposerClient->createSurface( String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0); if (sc == NULL || !sc->isValid()) { fprintf(stderr, "Failed to create SurfaceControl.\n"); return false; } float scale; result = computeWindowScale(w, h, &scale); if (!result) { return false; } SurfaceComposerClient::openGlobalTransaction(); err = sc->setLayer(0x7FFFFFFF); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); return false; } err = sc->setMatrix(scale, 0.0f, 0.0f, scale); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); return false; } err = sc->show(); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); return false; } SurfaceComposerClient::closeGlobalTransaction(); sp anw = sc->getSurface(); EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); if (s == EGL_NO_SURFACE) { fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); return false; } *surfaceControl = sc; *surface = s; return true; } static bool compileShader(GLenum shaderType, const char* src, GLuint* outShader) { GLuint shader = glCreateShader(shaderType); if (shader == 0) { fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); return false; } glShaderSource(shader, 1, &src, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = new char[infoLen]; if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); fprintf(stderr, "Shader compile log:\n%s\n", buf); delete[] buf; } } glDeleteShader(shader); return false; } *outShader = shader; return true; } static void printShaderSource(const char* const* src) { for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { fprintf(stderr, "%3zu: %s\n", i+1, src[i]); } } static const char* makeShaderString(const char* const* src) { size_t len = 0; for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { // The +1 is for the '\n' that will be added. len += strlen(src[i]) + 1; } char* result = new char[len+1]; char* end = result; for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { strcpy(end, src[i]); end += strlen(src[i]); *end = '\n'; end++; } *end = '\0'; return result; } static bool compileShaderLines(GLenum shaderType, const char* const* lines, GLuint* outShader) { const char* src = makeShaderString(lines); bool result = compileShader(shaderType, src, outShader); if (!result) { fprintf(stderr, "Shader source:\n"); printShaderSource(lines); return false; } delete[] src; return true; } static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) { GLuint program = glCreateProgram(); if (program == 0) { fprintf(stderr, "glCreateProgram error: %#x\n", glGetError()); return false; } glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = new char[bufLength]; if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); fprintf(stderr, "Program link log:\n%s\n", buf); delete[] buf; } } glDeleteProgram(program); program = 0; } *outPgm = program; return program != 0; } bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) { mShaderPrograms = new GLuint[numShaders]; bool result = true; for (size_t i = 0; i < numShaders && result; i++) { GLuint vs, fs; result = compileShaderLines(GL_VERTEX_SHADER, shaderDescs[i].vertexShader, &vs); if (!result) { return false; } result = compileShaderLines(GL_FRAGMENT_SHADER, shaderDescs[i].fragmentShader, &fs); if (!result) { glDeleteShader(vs); return false; } result = linkShaderProgram(vs, fs, &mShaderPrograms[i]); glDeleteShader(vs); glDeleteShader(fs); } mNumShaders = numShaders; mShaderDescs = shaderDescs; return result; } bool GLHelper::getDitherTexture(GLuint* outTexName) { if (mDitherTexture == 0) { const uint8_t pattern[] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 }; glGenTextures(1, &mDitherTexture); glBindTexture(GL_TEXTURE_2D, mDitherTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); } *outTexName = mDitherTexture; return true; } } cmds/flatland/GLHelper.h0100644 0000000 0000000 00000004566 13077405420 014150 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include #include #include namespace android { class SurfaceComposerClient; class SurfaceControl; enum { MAX_SHADER_LINES = 128 }; struct ShaderDesc { const char* name; const char* vertexShader[MAX_SHADER_LINES]; const char* fragmentShader[MAX_SHADER_LINES]; }; class GLHelper { public: enum { DITHER_KERNEL_SIZE = 4 }; GLHelper(); ~GLHelper(); bool setUp(const ShaderDesc* shaderDescs, size_t numShaders); void tearDown(); bool makeCurrent(EGLSurface surface); bool createSurfaceTexture(uint32_t w, uint32_t h, sp* surfaceTexture, EGLSurface* surface, GLuint* name); bool createWindowSurface(uint32_t w, uint32_t h, sp* surfaceControl, EGLSurface* surface); void destroySurface(EGLSurface* surface); bool swapBuffers(EGLSurface surface); bool getShaderProgram(const char* name, GLuint* outPgm); bool getDitherTexture(GLuint* outTexName); private: bool createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp* surfaceTexture, EGLSurface* surface); bool computeWindowScale(uint32_t w, uint32_t h, float* scale); bool setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders); sp mGraphicBufferAlloc; EGLDisplay mDisplay; EGLContext mContext; EGLSurface mDummySurface; sp mDummyGLConsumer; EGLConfig mConfig; sp mSurfaceComposerClient; GLuint* mShaderPrograms; const ShaderDesc* mShaderDescs; size_t mNumShaders; GLuint mDitherTexture; }; } // namespace android cmds/flatland/Main.cpp0100644 0000000 0000000 00000051174 13077405420 013722 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define ATRACE_TAG ATRACE_TAG_ALWAYS #include #include #include #include #include #include #include #include #include #include #include #include "Flatland.h" #include "GLHelper.h" using namespace ::android; static uint32_t g_SleepBetweenSamplesMs = 0; static bool g_PresentToWindow = false; static size_t g_BenchmarkNameLen = 0; struct BenchmarkDesc { // The name of the test. const char* name; // The dimensions of the space in which window layers are specified. uint32_t width; uint32_t height; // The screen heights at which to run the test. uint32_t runHeights[MAX_TEST_RUNS]; // The list of window layers. LayerDesc layers[MAX_NUM_LAYERS]; }; static const BenchmarkDesc benchmarks[] = { { "16:10 Single Static Window", 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Window 0, staticGradient, opaque, 0, 50, 2560, 1454, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2560, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1504, 2560, 96, }, }, }, { "4:3 Single Static Window", 2048, 1536, { 1536 }, { { // Window 0, staticGradient, opaque, 0, 50, 2048, 1440, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2048, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1440, 2048, 96, }, }, }, { "16:10 App -> Home Transition", 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Wallpaper 0, staticGradient, opaque, 0, 50, 2560, 1454, }, { // Launcher 0, staticGradient, blend, 0, 50, 2560, 1454, }, { // Outgoing activity 0, staticGradient, blendShrink, 20, 70, 2520, 1414, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2560, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1504, 2560, 96, }, }, }, { "4:3 App -> Home Transition", 2048, 1536, { 1536 }, { { // Wallpaper 0, staticGradient, opaque, 0, 50, 2048, 1440, }, { // Launcher 0, staticGradient, blend, 0, 50, 2048, 1440, }, { // Outgoing activity 0, staticGradient, blendShrink, 20, 70, 2048, 1400, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2048, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1440, 2048, 96, }, }, }, { "16:10 SurfaceView -> Home Transition", 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Wallpaper 0, staticGradient, opaque, 0, 50, 2560, 1454, }, { // Launcher 0, staticGradient, blend, 0, 50, 2560, 1454, }, { // Outgoing SurfaceView 0, staticGradient, blendShrink, 20, 70, 2520, 1414, }, { // Outgoing activity 0, staticGradient, blendShrink, 20, 70, 2520, 1414, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2560, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1504, 2560, 96, }, }, }, { "4:3 SurfaceView -> Home Transition", 2048, 1536, { 1536 }, { { // Wallpaper 0, staticGradient, opaque, 0, 50, 2048, 1440, }, { // Launcher 0, staticGradient, blend, 0, 50, 2048, 1440, }, { // Outgoing SurfaceView 0, staticGradient, blendShrink, 20, 70, 2048, 1400, }, { // Outgoing activity 0, staticGradient, blendShrink, 20, 70, 2048, 1400, }, { // Status bar 0, staticGradient, opaque, 0, 0, 2048, 50, }, { // Navigation bar 0, staticGradient, opaque, 0, 1440, 2048, 96, }, }, }, }; static const ShaderDesc shaders[] = { { .name="Blit", .vertexShader={ "precision mediump float;", "", "attribute vec4 position;", "attribute vec4 uv;", "", "varying vec4 texCoords;", "", "uniform mat4 objToNdc;", "uniform mat4 uvToTex;", "", "void main() {", " gl_Position = objToNdc * position;", " texCoords = uvToTex * uv;", "}", }, .fragmentShader={ "#extension GL_OES_EGL_image_external : require", "precision mediump float;", "", "varying vec4 texCoords;", "", "uniform samplerExternalOES blitSrc;", "uniform vec4 modColor;", "", "void main() {", " gl_FragColor = texture2D(blitSrc, texCoords.xy);", " gl_FragColor *= modColor;", "}", }, }, { .name="Gradient", .vertexShader={ "precision mediump float;", "", "attribute vec4 position;", "attribute vec4 uv;", "", "varying float interp;", "", "uniform mat4 objToNdc;", "uniform mat4 uvToInterp;", "", "void main() {", " gl_Position = objToNdc * position;", " interp = (uvToInterp * uv).x;", "}", }, .fragmentShader={ "precision mediump float;", "", "varying float interp;", "", "uniform vec4 color0;", "uniform vec4 color1;", "", "uniform sampler2D ditherKernel;", "uniform float invDitherKernelSize;", "uniform float invDitherKernelSizeSq;", "", "void main() {", " float dither = texture2D(ditherKernel,", " gl_FragCoord.xy * invDitherKernelSize).a;", " dither *= invDitherKernelSizeSq;", " vec4 color = mix(color0, color1, clamp(interp, 0.0, 1.0));", " gl_FragColor = color + vec4(dither, dither, dither, 0.0);", "}", }, }, }; class Layer { public: Layer() : mFirstFrame(true), mGLHelper(NULL), mSurface(EGL_NO_SURFACE) { } bool setUp(const LayerDesc& desc, GLHelper* helper) { bool result; mDesc = desc; mGLHelper = helper; result = mGLHelper->createSurfaceTexture(mDesc.width, mDesc.height, &mGLConsumer, &mSurface, &mTexName); if (!result) { return false; } mRenderer = desc.rendererFactory(); result = mRenderer->setUp(helper); if (!result) { return false; } mComposer = desc.composerFactory(); result = mComposer->setUp(desc, helper); if (!result) { return false; } return true; } void tearDown() { if (mComposer != NULL) { mComposer->tearDown(); delete mComposer; mComposer = NULL; } if (mRenderer != NULL) { mRenderer->tearDown(); delete mRenderer; mRenderer = NULL; } if (mSurface != EGL_NO_SURFACE) { mGLHelper->destroySurface(&mSurface); mGLConsumer->abandon(); } mGLHelper = NULL; mGLConsumer.clear(); } bool render() { return mRenderer->render(mSurface); } bool prepareComposition() { status_t err; err = mGLConsumer->updateTexImage(); if (err < 0) { fprintf(stderr, "GLConsumer::updateTexImage error: %d\n", err); return false; } return true; } bool compose() { return mComposer->compose(mTexName, mGLConsumer); } private: bool mFirstFrame; LayerDesc mDesc; GLHelper* mGLHelper; GLuint mTexName; sp mGLConsumer; EGLSurface mSurface; Renderer* mRenderer; Composer* mComposer; }; class BenchmarkRunner { public: BenchmarkRunner(const BenchmarkDesc& desc, size_t instance) : mDesc(desc), mInstance(instance), mNumLayers(countLayers(desc)), mGLHelper(NULL), mSurface(EGL_NO_SURFACE), mWindowSurface(EGL_NO_SURFACE) { } bool setUp() { ATRACE_CALL(); bool result; EGLint resulte; float scaleFactor = float(mDesc.runHeights[mInstance]) / float(mDesc.height); uint32_t w = uint32_t(scaleFactor * float(mDesc.width)); uint32_t h = mDesc.runHeights[mInstance]; mGLHelper = new GLHelper(); result = mGLHelper->setUp(shaders, NELEMS(shaders)); if (!result) { return false; } GLuint texName; result = mGLHelper->createSurfaceTexture(w, h, &mGLConsumer, &mSurface, &texName); if (!result) { return false; } for (size_t i = 0; i < mNumLayers; i++) { // Scale the layer to match the current screen size. LayerDesc ld = mDesc.layers[i]; ld.x = int32_t(scaleFactor * float(ld.x)); ld.y = int32_t(scaleFactor * float(ld.y)); ld.width = uint32_t(scaleFactor * float(ld.width)); ld.height = uint32_t(scaleFactor * float(ld.height)); // Set up the layer. result = mLayers[i].setUp(ld, mGLHelper); if (!result) { return false; } } if (g_PresentToWindow) { result = mGLHelper->createWindowSurface(w, h, &mSurfaceControl, &mWindowSurface); if (!result) { return false; } result = doFrame(mWindowSurface); if (!result) { return false; } } return true; } void tearDown() { ATRACE_CALL(); for (size_t i = 0; i < mNumLayers; i++) { mLayers[i].tearDown(); } if (mGLHelper != NULL) { if (mWindowSurface != EGL_NO_SURFACE) { mGLHelper->destroySurface(&mWindowSurface); } mGLHelper->destroySurface(&mSurface); mGLConsumer->abandon(); mGLConsumer.clear(); mSurfaceControl.clear(); mGLHelper->tearDown(); delete mGLHelper; mGLHelper = NULL; } } nsecs_t run(uint32_t warmUpFrames, uint32_t totalFrames) { ATRACE_CALL(); bool result; status_t err; resetColorGenerator(); // Do the warm-up frames. for (uint32_t i = 0; i < warmUpFrames; i++) { result = doFrame(mSurface); if (!result) { return -1; } } // Grab the fence for the start timestamp. sp startFence = mGLConsumer->getCurrentFence(); // the timed frames. for (uint32_t i = warmUpFrames; i < totalFrames; i++) { result = doFrame(mSurface); if (!result) { return -1; } } // Grab the fence for the end timestamp. sp endFence = mGLConsumer->getCurrentFence(); // Keep doing frames until the end fence has signaled. while (endFence->wait(0) == -ETIME) { result = doFrame(mSurface); if (!result) { return -1; } } // Compute the time delta. nsecs_t startTime = startFence->getSignalTime(); nsecs_t endTime = endFence->getSignalTime(); return endTime - startTime; } private: bool doFrame(EGLSurface surface) { bool result; status_t err; for (size_t i = 0; i < mNumLayers; i++) { result = mLayers[i].render(); if (!result) { return false; } } for (size_t i = 0; i < mNumLayers; i++) { result = mLayers[i].prepareComposition(); if (!result) { return false; } } result = mGLHelper->makeCurrent(surface); if (!result) { return false; } glClearColor(1.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); for (size_t i = 0; i < mNumLayers; i++) { result = mLayers[i].compose(); if (!result) { return false; } } result = mGLHelper->swapBuffers(surface); if (!result) { return false; } err = mGLConsumer->updateTexImage(); if (err < 0) { fprintf(stderr, "GLConsumer::updateTexImage error: %d\n", err); return false; } return true; } static size_t countLayers(const BenchmarkDesc& desc) { size_t i; for (i = 0; i < MAX_NUM_LAYERS; i++) { if (desc.layers[i].rendererFactory == NULL) { break; } } return i; } const BenchmarkDesc& mDesc; const size_t mInstance; const size_t mNumLayers; GLHelper* mGLHelper; // The surface into which layers are composited sp mGLConsumer; EGLSurface mSurface; // Used for displaying the surface to a window. EGLSurface mWindowSurface; sp mSurfaceControl; Layer mLayers[MAX_NUM_LAYERS]; }; static int cmpDouble(const double* lhs, const double* rhs) { if (*lhs < *rhs) { return -1; } else if (*rhs < *lhs) { return 1; } return 0; } // Run a single benchmark and print the result. static bool runTest(const BenchmarkDesc b, size_t run) { bool success = true; double prevResult = 0.0, result = 0.0; Vector samples; uint32_t runHeight = b.runHeights[run]; uint32_t runWidth = b.width * runHeight / b.height; printf(" %-*s | %4d x %4d | ", static_cast(g_BenchmarkNameLen), b.name, runWidth, runHeight); fflush(stdout); BenchmarkRunner r(b, run); if (!r.setUp()) { fprintf(stderr, "error initializing runner.\n"); return false; } // The slowest 1/outlierFraction sample results are ignored as potential // outliers. const uint32_t outlierFraction = 16; const double threshold = .0025; uint32_t warmUpFrames = 1; uint32_t totalFrames = 5; // Find the number of frames needed to run for over 100ms. double runTime = 0.0; while (true) { runTime = double(r.run(warmUpFrames, totalFrames)); if (runTime < 50e6) { warmUpFrames *= 2; totalFrames *= 2; } else { break; } } if (totalFrames - warmUpFrames > 16) { // The test runs too fast to get a stable result. Skip it. printf(" fast"); goto done; } else if (totalFrames == 5 && runTime > 200e6) { // The test runs too slow to be very useful. Skip it. printf(" slow"); goto done; } do { size_t newSamples = samples.size(); if (newSamples == 0) { newSamples = 4*outlierFraction; } if (newSamples > 512) { printf("varies"); goto done; } for (size_t i = 0; i < newSamples; i++) { double sample = double(r.run(warmUpFrames, totalFrames)); if (g_SleepBetweenSamplesMs > 0) { usleep(g_SleepBetweenSamplesMs * 1000); } if (sample < 0.0) { success = false; goto done; } samples.add(sample); } samples.sort(cmpDouble); prevResult = result; size_t elem = (samples.size() * (outlierFraction-1) / outlierFraction); result = (samples[elem-1] + samples[elem]) * 0.5; } while (fabs(result - prevResult) > threshold * result); printf("%6.3f", result / double(totalFrames - warmUpFrames) / 1e6); done: printf("\n"); fflush(stdout); r.tearDown(); return success; } static void printResultsTableHeader() { const char* scenario = "Scenario"; size_t len = strlen(scenario); size_t leftPad = (g_BenchmarkNameLen - len) / 2; size_t rightPad = g_BenchmarkNameLen - len - leftPad; printf(" %*s%s%*s | Resolution | Time (ms)\n", static_cast(leftPad), "", "Scenario", static_cast(rightPad), ""); } // Run ALL the benchmarks! static bool runTests() { printResultsTableHeader(); for (size_t i = 0; i < NELEMS(benchmarks); i++) { const BenchmarkDesc& b = benchmarks[i]; for (size_t j = 0; j < MAX_TEST_RUNS && b.runHeights[j]; j++) { if (!runTest(b, j)) { return false; } } } return true; } // Return the length longest benchmark name. static size_t maxBenchmarkNameLen() { size_t maxLen = 0; for (size_t i = 0; i < NELEMS(benchmarks); i++) { const BenchmarkDesc& b = benchmarks[i]; size_t len = strlen(b.name); if (len > maxLen) { maxLen = len; } } return maxLen; } // Print the command usage help to stderr. static void showHelp(const char *cmd) { fprintf(stderr, "usage: %s [options]\n", cmd); fprintf(stderr, "options include:\n" " -s N sleep for N ms between samples\n" " -d display the test frame to a window\n" " --help print this helpful message and exit\n" ); } int main(int argc, char** argv) { if (argc == 2 && 0 == strcmp(argv[1], "--help")) { showHelp(argv[0]); exit(0); } for (;;) { int ret; int option_index = 0; static struct option long_options[] = { {"help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; ret = getopt_long(argc, argv, "ds:", long_options, &option_index); if (ret < 0) { break; } switch(ret) { case 'd': g_PresentToWindow = true; break; case 's': g_SleepBetweenSamplesMs = atoi(optarg); break; case 0: if (strcmp(long_options[option_index].name, "help")) { showHelp(argv[0]); exit(0); } break; default: showHelp(argv[0]); exit(2); } } g_BenchmarkNameLen = maxBenchmarkNameLen(); printf(" cmdline:"); for (int i = 0; i < argc; i++) { printf(" %s", argv[i]); } printf("\n"); if (!runTests()) { fprintf(stderr, "exiting due to error.\n"); return 1; } } cmds/flatland/README.txt0100644 0000000 0000000 00000007450 13077405420 014026 0ustar000000000 0000000 Flatland is a benchmark for measuring GPU performance in various 2D UI rendering and window compositing scenarios. It is designed to be used early in the device development process to evaluate GPU hardware (e.g. for SoC selection). It uses OpenGL ES 2.0, gralloc, and the Android explicit synchronization framework, so it can only be run on devices with drivers supporting those HALs. Preparing a Device Because it's measuring hardware performance, flatland should be run in as consistent and static an environment as possible. The display should be turned off and background services should be stopped before running the benchmark. Running 'adb shell stop' after turning off the display is probably sufficient for this, but if there are device- specific background services that consume much CPU cycles, memory bandwidth, or might otherwise interfere with GPU rendering, those should be stopped as well (and ideally they'd be fixed or eliminated for production devices). Additionally, all relevant hardware clocks should be locked at a particular frequency when running flatland. At a minimum this includes the CPU, GPU, and memory bus clocks. Running flatland with dynamic clocking essentially measures the behavior of the dynamic clocking algorithm under a fairly unrealistic workload, and will likely result in unstable and useless results. If running the benchmark with the clocks locked causes thermal issues, the -s command line option can be used to insert a sleep (specified in milliseconds) in between each benchmark sample run. Regardless of the scenario being measured, each sample measurement runs for between 50 and 200 ms, so a sleep time between 10 and 50 ms should address most thermal problems. Interpreting the Output The output of flatland should look something like this: cmdline: flatland Scenario | Resolution | Time (ms) 16:10 Single Static Window | 1280 x 800 | fast 16:10 Single Static Window | 2560 x 1600 | 5.368 16:10 Single Static Window | 3840 x 2400 | 11.979 16:10 App -> Home Transition | 1280 x 800 | 4.069 16:10 App -> Home Transition | 2560 x 1600 | 15.911 16:10 App -> Home Transition | 3840 x 2400 | 38.795 16:10 SurfaceView -> Home Transition | 1280 x 800 | 5.387 16:10 SurfaceView -> Home Transition | 2560 x 1600 | 21.147 16:10 SurfaceView -> Home Transition | 3840 x 2400 | slow The first column is simply a description of the scenario that's being simulated. The second column indicates the resolution at which the scenario was measured. The third column is the measured benchmark result. It indicates the expected time in milliseconds that a single frame of the scenario takes to complete. The third column may also contain one of three other values: fast - This indicates that frames of the scenario completed too fast to be reliably benchmarked. This corresponds to a frame time less than 3 ms. Rather than spending time trying (and likely failing) to get a stable result, the scenario was skipped. slow - This indicates that frames of the scenario took too long to complete. This corresponds to a frame time over 50 ms. Rather than simulating a scenario that is obviously impractical on this device, the scenario was skipped. varies - This indicates that the scenario was measured, but it did not yield a stable result. Occasionally this happens with an otherwise stable scenario. In this case, simply rerunning flatland should yield a valid result. If a scenario repeatedly results in a 'varies' output, that probably indicates that something is wrong with the environment in which flatland is being run. Check that the hardware clock frequencies are locked and that no heavy-weight services / daemons are running in the background. cmds/flatland/Renderers.cpp0100644 0000000 0000000 00000013227 13077405420 014764 0ustar000000000 0000000 /* * Copyright (C) 2012 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 "Flatland.h" #include "GLHelper.h" namespace android { static float colors[][4] = { { .85f, .14f, .44f, 1.0f }, { .91f, .72f, .10f, 1.0f }, { .04f, .66f, .42f, 1.0f }, { .84f, .39f, .68f, 1.0f }, { .38f, .53f, .78f, 1.0f }, }; static size_t g_colorIndex; const float* genColor() { float* color = colors[g_colorIndex]; g_colorIndex = (g_colorIndex + 1) % NELEMS(colors); return color; } void resetColorGenerator() { g_colorIndex = 0; } class GradientRenderer { public: bool setUp(GLHelper* helper) { bool result; result = helper->getShaderProgram("Gradient", &mGradPgm); if (!result) { return false; } result = helper->getDitherTexture(&mDitherTexName); if (!result) { return false; } mPosAttribLoc = glGetAttribLocation(mGradPgm, "position"); mUVAttribLoc = glGetAttribLocation(mGradPgm, "uv"); mUVToInterpUniformLoc = glGetUniformLocation(mGradPgm, "uvToInterp"); mObjToNdcUniformLoc = glGetUniformLocation(mGradPgm, "objToNdc"); mDitherKernelSamplerLoc = glGetUniformLocation(mGradPgm, "ditherKernel"); mInvDitherKernelSizeUniformLoc = glGetUniformLocation(mGradPgm, "invDitherKernelSize"); mInvDitherKernelSizeSqUniformLoc = glGetUniformLocation(mGradPgm, "invDitherKernelSizeSq"); mColor0UniformLoc = glGetUniformLocation(mGradPgm, "color0"); mColor1UniformLoc = glGetUniformLocation(mGradPgm, "color1"); return true; } void tearDown() { } bool drawGradient() { float identity[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; const float pos[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, }; const float uv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, }; const float* color0 = genColor(); const float* color1 = genColor(); glUseProgram(mGradPgm); glVertexAttribPointer(mPosAttribLoc, 2, GL_FLOAT, GL_FALSE, 0, pos); glVertexAttribPointer(mUVAttribLoc, 2, GL_FLOAT, GL_FALSE, 0, uv); glEnableVertexAttribArray(mPosAttribLoc); glEnableVertexAttribArray(mUVAttribLoc); float invDitherKernelSize = 1.0f / float(GLHelper::DITHER_KERNEL_SIZE); float invDitherKernelSizeSq = invDitherKernelSize * invDitherKernelSize; glUniformMatrix4fv(mObjToNdcUniformLoc, 1, GL_FALSE, identity); glUniformMatrix4fv(mUVToInterpUniformLoc, 1, GL_FALSE, identity); glUniform1f(mInvDitherKernelSizeUniformLoc, invDitherKernelSize); glUniform1f(mInvDitherKernelSizeSqUniformLoc, invDitherKernelSizeSq); glUniform4fv(mColor0UniformLoc, 1, color0); glUniform4fv(mColor1UniformLoc, 1, color1); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "GL error! 0\n"); } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mDitherTexName); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "GL error! 1\n"); } glUniform1i(mDitherKernelSamplerLoc, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(mPosAttribLoc); glDisableVertexAttribArray(mUVAttribLoc); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "GL error! 2\n"); } return true; } GLuint mGradPgm; GLuint mDitherTexName; GLuint mPosAttribLoc; GLuint mUVAttribLoc; GLuint mObjToNdcUniformLoc; GLuint mUVToInterpUniformLoc; GLuint mDitherKernelSamplerLoc; GLuint mInvDitherKernelSizeUniformLoc; GLuint mInvDitherKernelSizeSqUniformLoc; GLuint mColor0UniformLoc; GLuint mColor1UniformLoc; }; Renderer* staticGradient() { class NoRenderer : public Renderer { virtual bool setUp(GLHelper* helper) { mIsFirstFrame = true; mGLHelper = helper; return mGradientRenderer.setUp(helper); } virtual void tearDown() { mGradientRenderer.tearDown(); } virtual bool render(EGLSurface surface) { if (mIsFirstFrame) { bool result; mIsFirstFrame = false; result = mGLHelper->makeCurrent(surface); if (!result) { return false; } result = mGradientRenderer.drawGradient(); if (!result) { return false; } result = mGLHelper->swapBuffers(surface); if (!result) { return false; } } return true; } bool mIsFirstFrame; GLHelper* mGLHelper; GradientRenderer mGradientRenderer; }; return new NoRenderer; } } // namespace android cmds/installd/0040755 0000000 0000000 00000000000 13077405420 012352 5ustar000000000 0000000 cmds/installd/Android.mk0100644 0000000 0000000 00000005515 13077405420 014266 0ustar000000000 0000000 LOCAL_PATH := $(call my-dir) common_src_files := commands.cpp globals.cpp utils.cpp common_cflags := -Wall -Werror # # Static library used in testing and executable # include $(CLEAR_VARS) LOCAL_MODULE := libinstalld LOCAL_MODULE_TAGS := eng tests LOCAL_SRC_FILES := $(common_src_files) LOCAL_CFLAGS := $(common_cflags) LOCAL_SHARED_LIBRARIES := \ libbase \ liblogwrap \ libselinux \ LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true include $(BUILD_STATIC_LIBRARY) # # Executable # include $(CLEAR_VARS) LOCAL_MODULE := installd LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := $(common_cflags) LOCAL_SRC_FILES := installd.cpp $(common_src_files) LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ liblog \ liblogwrap \ libselinux \ LOCAL_STATIC_LIBRARIES := libdiskusage LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_INIT_RC := installd.rc LOCAL_CLANG := true include $(BUILD_EXECUTABLE) # # OTA Executable # include $(CLEAR_VARS) LOCAL_MODULE := otapreopt LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := $(common_cflags) # Base & ASLR boundaries for boot image creation. ifndef LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA := -0x1000000 else LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA := $(LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA) endif ifndef LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA := 0x1000000 else LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA := $(LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA) endif LOCAL_CFLAGS += -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS) LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA) LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA) LOCAL_SRC_FILES := otapreopt.cpp $(common_src_files) LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ liblog \ liblogwrap \ libselinux \ LOCAL_STATIC_LIBRARIES := libdiskusage LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true include $(BUILD_EXECUTABLE) # OTA chroot tool include $(CLEAR_VARS) LOCAL_MODULE := otapreopt_chroot LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := $(common_cflags) LOCAL_SRC_FILES := otapreopt_chroot.cpp LOCAL_SHARED_LIBRARIES := \ libbase \ liblog \ LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true include $(BUILD_EXECUTABLE) # OTA postinstall script include $(CLEAR_VARS) LOCAL_MODULE:= otapreopt_script LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_SRC_FILES := otapreopt_script.sh # Let this depend on otapreopt and the chroot tool, so we just have to mention one in a # configuration. LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot include $(BUILD_PREBUILT) # Tests. include $(LOCAL_PATH)/tests/Android.mkcmds/installd/commands.cpp0100644 0000000 0000000 00000214673 13077405420 014671 0ustar000000000 0000000 /* ** Copyright 2008, 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 "commands.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO: Move everything to base/logging. #include #include #include #include #include #include #include #include #include #ifndef LOG_TAG #define LOG_TAG "installd" #endif using android::base::StringPrintf; namespace android { namespace installd { static constexpr const char* kCpPath = "/system/bin/cp"; static constexpr const char* kXattrDefault = "user.default"; #define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M typedef int fd_t; static bool property_get_bool(const char* property_name, bool default_value = false) { char tmp_property_value[kPropertyValueMax]; bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0; if (!have_property) { return default_value; } return strcmp(tmp_property_value, "true") == 0; } // Keep profile paths in sync with ActivityThread. constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof"; static std::string create_primary_profile(const std::string& profile_dir) { return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME); } int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, appid_t appid, const char* seinfo, int target_sdk_version) { uid_t uid = multiuser_get_uid(userid, appid); int target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751; if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_package_path(uuid, userid, pkgname); if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) { PLOG(ERROR) << "Failed to prepare " << path; return -1; } if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << path; return -1; } } if (flags & FLAG_STORAGE_DE) { auto path = create_data_user_de_package_path(uuid, userid, pkgname); if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) == -1) { PLOG(ERROR) << "Failed to prepare " << path; // TODO: include result once 25796509 is fixed return 0; } if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) { PLOG(ERROR) << "Failed to setfilecon " << path; // TODO: include result once 25796509 is fixed return 0; } if (property_get_bool("dalvik.vm.usejitprofiles")) { const std::string profile_path = create_data_user_profile_package_path(userid, pkgname); // read-write-execute only for the app user. if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) { PLOG(ERROR) << "Failed to prepare " << profile_path; return -1; } std::string profile_file = create_primary_profile(profile_path); // read-write only for the app user. if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) { PLOG(ERROR) << "Failed to prepare " << profile_path; return -1; } const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname); // dex2oat/profman runs under the shared app gid and it needs to read/write reference // profiles. appid_t shared_app_gid = multiuser_get_shared_app_gid(uid); if (fs_prepare_dir_strict( ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) { PLOG(ERROR) << "Failed to prepare " << ref_profile_path; return -1; } } } return 0; } int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) { // This method only exists to upgrade system apps that have requested // forceDeviceEncrypted, so their default storage always lives in a // consistent location. This only works on non-FBE devices, since we // never want to risk exposing data on a device with real CE/DE storage. auto ce_path = create_data_user_ce_package_path(uuid, userid, pkgname); auto de_path = create_data_user_de_package_path(uuid, userid, pkgname); // If neither directory is marked as default, assume CE is default if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1 && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) { if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) { PLOG(ERROR) << "Failed to mark default storage " << ce_path; return -1; } } // Migrate default data location if needed auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path; auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path; if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) { LOG(WARNING) << "Requested default storage " << target << " is not active; migrating from " << source; if (delete_dir_contents_and_dir(target) != 0) { PLOG(ERROR) << "Failed to delete"; return -1; } if (rename(source.c_str(), target.c_str()) != 0) { PLOG(ERROR) << "Failed to rename"; return -1; } } return 0; } static bool clear_profile(const std::string& profile) { base::unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); if (ufd.get() < 0) { if (errno != ENOENT) { PLOG(WARNING) << "Could not open profile " << profile; return false; } else { // Nothing to clear. That's ok. return true; } } if (flock(ufd.get(), LOCK_EX | LOCK_NB) != 0) { if (errno != EWOULDBLOCK) { PLOG(WARNING) << "Error locking profile " << profile; } // This implies that the app owning this profile is running // (and has acquired the lock). // // If we can't acquire the lock bail out since clearing is useless anyway // (the app will write again to the profile). // // Note: // This does not impact the this is not an issue for the profiling correctness. // In case this is needed because of an app upgrade, profiles will still be // eventually cleared by the app itself due to checksum mismatch. // If this is needed because profman advised, then keeping the data around // until the next run is again not an issue. // // If the app attempts to acquire a lock while we've held one here, // it will simply skip the current write cycle. return false; } bool truncated = ftruncate(ufd.get(), 0) == 0; if (!truncated) { PLOG(WARNING) << "Could not truncate " << profile; } if (flock(ufd.get(), LOCK_UN) != 0) { PLOG(WARNING) << "Error unlocking profile " << profile; } return truncated; } static bool clear_reference_profile(const char* pkgname) { std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname); std::string reference_profile = create_primary_profile(reference_profile_dir); return clear_profile(reference_profile); } static bool clear_current_profile(const char* pkgname, userid_t user) { std::string profile_dir = create_data_user_profile_package_path(user, pkgname); std::string profile = create_primary_profile(profile_dir); return clear_profile(profile); } static bool clear_current_profiles(const char* pkgname) { bool success = true; std::vector users = get_known_users(/*volume_uuid*/ nullptr); for (auto user : users) { success &= clear_current_profile(pkgname, user); } return success; } int clear_app_profiles(const char* pkgname) { bool success = true; success &= clear_reference_profile(pkgname); success &= clear_current_profiles(pkgname); return success ? 0 : -1; } int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode) { std::string suffix = ""; bool only_cache = false; if (flags & FLAG_CLEAR_CACHE_ONLY) { suffix = CACHE_DIR_POSTFIX; only_cache = true; } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) { suffix = CODE_CACHE_DIR_POSTFIX; only_cache = true; } int res = 0; if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode) + suffix; if (access(path.c_str(), F_OK) == 0) { res |= delete_dir_contents(path); } } if (flags & FLAG_STORAGE_DE) { auto path = create_data_user_de_package_path(uuid, userid, pkgname) + suffix; if (access(path.c_str(), F_OK) == 0) { // TODO: include result once 25796509 is fixed delete_dir_contents(path); } if (!only_cache) { if (!clear_current_profile(pkgname, userid)) { res |= -1; } } } return res; } static int destroy_app_reference_profile(const char *pkgname) { return delete_dir_contents_and_dir( create_data_ref_profile_package_path(pkgname), /*ignore_if_missing*/ true); } static int destroy_app_current_profiles(const char *pkgname, userid_t userid) { return delete_dir_contents_and_dir( create_data_user_profile_package_path(userid, pkgname), /*ignore_if_missing*/ true); } int destroy_app_profiles(const char *pkgname) { int result = 0; std::vector users = get_known_users(/*volume_uuid*/ nullptr); for (auto user : users) { result |= destroy_app_current_profiles(pkgname, user); } result |= destroy_app_reference_profile(pkgname); return result; } int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode) { int res = 0; if (flags & FLAG_STORAGE_CE) { res |= delete_dir_contents_and_dir( create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode)); } if (flags & FLAG_STORAGE_DE) { res |= delete_dir_contents_and_dir( create_data_user_de_package_path(uuid, userid, pkgname)); destroy_app_current_profiles(pkgname, userid); // TODO(calin): If the package is still installed by other users it's probably // beneficial to keep the reference profile around. // Verify if it's ok to do that. destroy_app_reference_profile(pkgname); } return res; } int move_complete_app(const char *from_uuid, const char *to_uuid, const char *package_name, const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version) { std::vector users = get_known_users(from_uuid); // Copy app { auto from = create_data_app_package_path(from_uuid, data_app_name); auto to = create_data_app_package_path(to_uuid, data_app_name); auto to_parent = create_data_app_path(to_uuid); char *argv[] = { (char*) kCpPath, (char*) "-F", /* delete any existing destination file first (--remove-destination) */ (char*) "-p", /* preserve timestamps, ownership, and permissions */ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */ (char*) "-P", /* Do not follow symlinks [default] */ (char*) "-d", /* don't dereference symlinks */ (char*) from.c_str(), (char*) to_parent.c_str() }; LOG(DEBUG) << "Copying " << from << " to " << to; int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); if (rc != 0) { LOG(ERROR) << "Failed copying " << from << " to " << to << ": status " << rc; goto fail; } if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) { LOG(ERROR) << "Failed to restorecon " << to; goto fail; } } // Copy private data for all known users for (auto user : users) { // Data source may not exist for all users; that's okay auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name); if (access(from_ce.c_str(), F_OK) != 0) { LOG(INFO) << "Missing source " << from_ce; continue; } if (create_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appid, seinfo, target_sdk_version) != 0) { LOG(ERROR) << "Failed to create package target on " << to_uuid; goto fail; } char *argv[] = { (char*) kCpPath, (char*) "-F", /* delete any existing destination file first (--remove-destination) */ (char*) "-p", /* preserve timestamps, ownership, and permissions */ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */ (char*) "-P", /* Do not follow symlinks [default] */ (char*) "-d", /* don't dereference symlinks */ nullptr, nullptr }; { auto from = create_data_user_de_package_path(from_uuid, user, package_name); auto to = create_data_user_de_path(to_uuid, user); argv[6] = (char*) from.c_str(); argv[7] = (char*) to.c_str(); LOG(DEBUG) << "Copying " << from << " to " << to; int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); if (rc != 0) { LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc; goto fail; } } { auto from = create_data_user_ce_package_path(from_uuid, user, package_name); auto to = create_data_user_ce_path(to_uuid, user); argv[6] = (char*) from.c_str(); argv[7] = (char*) to.c_str(); LOG(DEBUG) << "Copying " << from << " to " << to; int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); if (rc != 0) { LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc; goto fail; } } if (restorecon_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appid, seinfo) != 0) { LOG(ERROR) << "Failed to restorecon"; goto fail; } } // We let the framework scan the new location and persist that before // deleting the data in the old location; this ordering ensures that // we can recover from things like battery pulls. return 0; fail: // Nuke everything we might have already copied { auto to = create_data_app_package_path(to_uuid, data_app_name); if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } for (auto user : users) { { auto to = create_data_user_de_package_path(to_uuid, user, package_name); if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } { auto to = create_data_user_ce_package_path(to_uuid, user, package_name); if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } } return -1; } int create_user_data(const char *uuid, userid_t userid, int user_serial ATTRIBUTE_UNUSED, int flags) { if (flags & FLAG_STORAGE_DE) { if (uuid == nullptr) { return ensure_config_user_dirs(userid); } } return 0; } int destroy_user_data(const char *uuid, userid_t userid, int flags) { int res = 0; if (flags & FLAG_STORAGE_DE) { res |= delete_dir_contents_and_dir(create_data_user_de_path(uuid, userid), true); if (uuid == nullptr) { res |= delete_dir_contents_and_dir(create_data_misc_legacy_path(userid), true); res |= delete_dir_contents_and_dir(create_data_user_profiles_path(userid), true); } } if (flags & FLAG_STORAGE_CE) { res |= delete_dir_contents_and_dir(create_data_user_ce_path(uuid, userid), true); res |= delete_dir_contents_and_dir(create_data_media_path(uuid, userid), true); } return res; } /* Try to ensure free_size bytes of storage are available. * Returns 0 on success. * This is rather simple-minded because doing a full LRU would * be potentially memory-intensive, and without atime it would * also require that apps constantly modify file metadata even * when just reading from the cache, which is pretty awful. */ int free_cache(const char *uuid, int64_t free_size) { cache_t* cache; int64_t avail; auto data_path = create_data_path(uuid); avail = data_disk_free(data_path); if (avail < 0) return -1; ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail); if (avail >= free_size) return 0; cache = start_cache_collection(); auto users = get_known_users(uuid); for (auto user : users) { add_cache_files(cache, create_data_user_ce_path(uuid, user)); add_cache_files(cache, create_data_user_de_path(uuid, user)); add_cache_files(cache, StringPrintf("%s/Android/data", create_data_media_path(uuid, user).c_str())); } clear_cache_files(data_path, cache, free_size); finish_cache_collection(cache); return data_disk_free(data_path) >= free_size ? 0 : -1; } int rm_dex(const char *path, const char *instruction_set) { char dex_path[PKG_PATH_MAX]; if (validate_apk_path(path) && validate_system_app_path(path)) { ALOGE("invalid apk path '%s' (bad prefix)\n", path); return -1; } if (!create_cache_path(dex_path, path, instruction_set)) return -1; ALOGV("unlink %s\n", dex_path); if (unlink(dex_path) < 0) { if (errno != ENOENT) { ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno)); } return -1; } else { return 0; } } static void add_app_data_size(std::string& path, int64_t *codesize, int64_t *datasize, int64_t *cachesize) { DIR *d; int dfd; struct dirent *de; struct stat s; d = opendir(path.c_str()); if (d == nullptr) { PLOG(WARNING) << "Failed to open " << path; return; } dfd = dirfd(d); while ((de = readdir(d))) { const char *name = de->d_name; int64_t statsize = 0; if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { statsize = stat_size(&s); } if (de->d_type == DT_DIR) { int subfd; int64_t dirsize = 0; /* always skip "." and ".." */ if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); if (subfd >= 0) { dirsize = calculate_dir_size(subfd); close(subfd); } // TODO: check xattrs! if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) { *datasize += statsize; *cachesize += dirsize; } else { *datasize += dirsize + statsize; } } else if (de->d_type == DT_LNK && !strcmp(name, "lib")) { *codesize += statsize; } else { *datasize += statsize; } } closedir(d); } int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode, const char *code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t* asecsize) { DIR *d; int dfd; d = opendir(code_path); if (d != nullptr) { dfd = dirfd(d); *codesize += calculate_dir_size(dfd); closedir(d); } if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode); add_app_data_size(path, codesize, datasize, cachesize); } if (flags & FLAG_STORAGE_DE) { auto path = create_data_user_de_package_path(uuid, userid, pkgname); add_app_data_size(path, codesize, datasize, cachesize); } *asecsize = 0; return 0; } int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode) { struct stat buf; memset(&buf, 0, sizeof(buf)); if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_package_path(uuid, userid, pkgname); if (stat(path.c_str(), &buf) == 0) { *inode = buf.st_ino; return 0; } } return -1; } static int split_count(const char *str) { char *ctx; int count = 0; char buf[kPropertyValueMax]; strncpy(buf, str, sizeof(buf)); char *pBuf = buf; while(strtok_r(pBuf, " ", &ctx) != NULL) { count++; pBuf = NULL; } return count; } static int split(char *buf, const char **argv) { char *ctx; int count = 0; char *tok; char *pBuf = buf; while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) { argv[count++] = tok; pBuf = NULL; } return count; } static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set) { static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; static const char* PATCHOAT_BIN = "/system/bin/patchoat"; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { ALOGE("Instruction set %s longer than max length of %d", instruction_set, MAX_INSTRUCTION_SET_LEN); return; } /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/ char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN]; char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN]; const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art"; // The caller has already gotten all the locks we need. const char* no_lock_arg = "--no-lock-output"; sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd); ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n", PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name); /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ char* argv[7]; argv[0] = (char*) PATCHOAT_BIN; argv[1] = (char*) patched_image_location_arg; argv[2] = (char*) no_lock_arg; argv[3] = instruction_set_arg; argv[4] = output_oat_fd_arg; argv[5] = input_oat_fd_arg; argv[6] = NULL; execv(PATCHOAT_BIN, (char* const *)argv); ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); } static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name, const char* output_file_name, int swap_fd, const char *instruction_set, const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { ALOGE("Instruction set %s longer than max length of %d", instruction_set, MAX_INSTRUCTION_SET_LEN); return; } char dex2oat_Xms_flag[kPropertyValueMax]; bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0; char dex2oat_Xmx_flag[kPropertyValueMax]; bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0; char dex2oat_threads_buf[kPropertyValueMax]; bool have_dex2oat_threads_flag = get_property(post_bootcomplete ? "dalvik.vm.dex2oat-threads" : "dalvik.vm.boot-dex2oat-threads", dex2oat_threads_buf, NULL) > 0; char dex2oat_threads_arg[kPropertyValueMax + 2]; if (have_dex2oat_threads_flag) { sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf); } char dex2oat_isa_features_key[kPropertyKeyMax]; sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set); char dex2oat_isa_features[kPropertyValueMax]; bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key, dex2oat_isa_features, NULL) > 0; char dex2oat_isa_variant_key[kPropertyKeyMax]; sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set); char dex2oat_isa_variant[kPropertyValueMax]; bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key, dex2oat_isa_variant, NULL) > 0; const char *dex2oat_norelocation = "-Xnorelocate"; bool have_dex2oat_relocation_skip_flag = false; char dex2oat_flags[kPropertyValueMax]; int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags", dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags); ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags); // If we booting without the real /data, don't spend time compiling. char vold_decrypt[kPropertyValueMax]; bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0; bool skip_compilation = (have_vold_decrypt && (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 || (strcmp(vold_decrypt, "1") == 0))); bool generate_debug_info = property_get_bool("debug.generate-debug-info"); char app_image_format[kPropertyValueMax]; char image_format_arg[strlen("--image-format=") + kPropertyValueMax]; bool have_app_image_format = image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; if (have_app_image_format) { sprintf(image_format_arg, "--image-format=%s", app_image_format); } static const char* DEX2OAT_BIN = "/system/bin/dex2oat"; static const char* RUNTIME_ARG = "--runtime-arg"; static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char instruction_set_variant_arg[strlen("--instruction-set-variant=") + kPropertyValueMax]; char instruction_set_features_arg[strlen("--instruction-set-features=") + kPropertyValueMax]; char dex2oat_Xms_arg[strlen("-Xms") + kPropertyValueMax]; char dex2oat_Xmx_arg[strlen("-Xmx") + kPropertyValueMax]; char dex2oat_compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax]; bool have_dex2oat_swap_fd = false; char dex2oat_swap_fd[strlen("--swap-fd=") + MAX_INT_LEN]; bool have_dex2oat_image_fd = false; char dex2oat_image_fd[strlen("--app-image-fd=") + MAX_INT_LEN]; sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant); sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features); if (swap_fd >= 0) { have_dex2oat_swap_fd = true; sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd); } if (image_fd >= 0) { have_dex2oat_image_fd = true; sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd); } if (have_dex2oat_Xms_flag) { sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag); } if (have_dex2oat_Xmx_flag) { sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag); } // Compute compiler filter. bool have_dex2oat_compiler_filter_flag; if (skip_compilation) { strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none"); have_dex2oat_compiler_filter_flag = true; have_dex2oat_relocation_skip_flag = true; } else if (vm_safe_mode) { strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only"); have_dex2oat_compiler_filter_flag = true; } else if (compiler_filter != nullptr && strlen(compiler_filter) + strlen("--compiler-filter=") < arraysize(dex2oat_compiler_filter_arg)) { sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter); have_dex2oat_compiler_filter_flag = true; } else { char dex2oat_compiler_filter_flag[kPropertyValueMax]; have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter", dex2oat_compiler_filter_flag, NULL) > 0; if (have_dex2oat_compiler_filter_flag) { sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag); } } // Check whether all apps should be compiled debuggable. if (!debuggable) { char prop_buf[kPropertyValueMax]; debuggable = (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) && (prop_buf[0] == '1'); } char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN]; if (profile_fd != -1) { sprintf(profile_arg, "--profile-file-fd=%d", profile_fd); } ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); const char* argv[7 // program name, mandatory arguments and the final NULL + (have_dex2oat_isa_variant ? 1 : 0) + (have_dex2oat_isa_features ? 1 : 0) + (have_dex2oat_Xms_flag ? 2 : 0) + (have_dex2oat_Xmx_flag ? 2 : 0) + (have_dex2oat_compiler_filter_flag ? 1 : 0) + (have_dex2oat_threads_flag ? 1 : 0) + (have_dex2oat_swap_fd ? 1 : 0) + (have_dex2oat_image_fd ? 1 : 0) + (have_dex2oat_relocation_skip_flag ? 2 : 0) + (generate_debug_info ? 1 : 0) + (debuggable ? 1 : 0) + (have_app_image_format ? 1 : 0) + dex2oat_flags_count + (profile_fd == -1 ? 0 : 1) + (shared_libraries != nullptr ? 4 : 0)]; int i = 0; argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; argv[i++] = zip_location_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_location_arg; argv[i++] = instruction_set_arg; if (have_dex2oat_isa_variant) { argv[i++] = instruction_set_variant_arg; } if (have_dex2oat_isa_features) { argv[i++] = instruction_set_features_arg; } if (have_dex2oat_Xms_flag) { argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_Xms_arg; } if (have_dex2oat_Xmx_flag) { argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_Xmx_arg; } if (have_dex2oat_compiler_filter_flag) { argv[i++] = dex2oat_compiler_filter_arg; } if (have_dex2oat_threads_flag) { argv[i++] = dex2oat_threads_arg; } if (have_dex2oat_swap_fd) { argv[i++] = dex2oat_swap_fd; } if (have_dex2oat_image_fd) { argv[i++] = dex2oat_image_fd; } if (generate_debug_info) { argv[i++] = "--generate-debug-info"; } if (debuggable) { argv[i++] = "--debuggable"; } if (have_app_image_format) { argv[i++] = image_format_arg; } if (dex2oat_flags_count) { i += split(dex2oat_flags, argv + i); } if (have_dex2oat_relocation_skip_flag) { argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_norelocation; } if (profile_fd != -1) { argv[i++] = profile_arg; } if (shared_libraries != nullptr) { argv[i++] = RUNTIME_ARG; argv[i++] = "-classpath"; argv[i++] = RUNTIME_ARG; argv[i++] = shared_libraries; } // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; execv(DEX2OAT_BIN, (char * const *)argv); ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); } /* * Whether dexopt should use a swap file when compiling an APK. * * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision * itself, anyways). * * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true". * * Otherwise, return true if this is a low-mem device. * * Otherwise, return default value. */ static bool kAlwaysProvideSwapFile = false; static bool kDefaultProvideSwapFile = true; static bool ShouldUseSwapFileForDexopt() { if (kAlwaysProvideSwapFile) { return true; } // Check the "override" property. If it exists, return value == "true". char dex2oat_prop_buf[kPropertyValueMax]; if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) { if (strcmp(dex2oat_prop_buf, "true") == 0) { return true; } else { return false; } } // Shortcut for default value. This is an implementation optimization for the process sketched // above. If the default value is true, we can avoid to check whether this is a low-mem device, // as low-mem is never returning false. The compiler will optimize this away if it can. if (kDefaultProvideSwapFile) { return true; } bool is_low_mem = property_get_bool("ro.config.low_ram"); if (is_low_mem) { return true; } // Default value must be false here. return kDefaultProvideSwapFile; } static void SetDex2OatAndPatchOatScheduling(bool set_to_bg) { if (set_to_bg) { if (set_sched_policy(0, SP_BACKGROUND) < 0) { ALOGE("set_sched_policy failed: %s\n", strerror(errno)); exit(70); } if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { ALOGE("setpriority failed: %s\n", strerror(errno)); exit(71); } } } static void close_all_fds(const std::vector& fds, const char* description) { for (size_t i = 0; i < fds.size(); i++) { if (close(fds[i]) != 0) { PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i; } } } static fd_t open_profile_dir(const std::string& profile_dir) { fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(), O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW)); if (profile_dir_fd < 0) { // In a multi-user environment, these directories can be created at // different points and it's possible we'll attempt to open a profile // dir before it exists. if (errno != ENOENT) { PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir; } } return profile_dir_fd; } static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) { fd_t profile_dir_fd = open_profile_dir(profile_dir); if (profile_dir_fd < 0) { return -1; } fd_t profile_fd = -1; std::string profile_file = create_primary_profile(profile_dir); profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW)); if (profile_fd == -1) { // It's not an error if the profile file does not exist. if (errno != ENOENT) { PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir; } } // TODO(calin): use AutoCloseFD instead of closing the fd manually. if (close(profile_dir_fd) != 0) { PLOG(WARNING) << "Could not close profile dir " << profile_dir; } return profile_fd; } static fd_t open_primary_profile_file(userid_t user, const char* pkgname) { std::string profile_dir = create_data_user_profile_package_path(user, pkgname); return open_primary_profile_file_from_dir(profile_dir, O_RDONLY); } static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) { std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname); int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY; fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags); if (fd < 0) { return -1; } if (read_write) { // Fix the owner. if (fchown(fd, uid, uid) < 0) { close(fd); return -1; } } return fd; } static void open_profile_files(uid_t uid, const char* pkgname, /*out*/ std::vector* profiles_fd, /*out*/ fd_t* reference_profile_fd) { // Open the reference profile in read-write mode as profman might need to save the merge. *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true); if (*reference_profile_fd < 0) { // We can't access the reference profile file. return; } std::vector users = get_known_users(/*volume_uuid*/ nullptr); for (auto user : users) { fd_t profile_fd = open_primary_profile_file(user, pkgname); // Add to the lists only if both fds are valid. if (profile_fd >= 0) { profiles_fd->push_back(profile_fd); } } } static void drop_capabilities(uid_t uid) { if (setgid(uid) != 0) { ALOGE("setgid(%d) failed in installd during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed in installd during dexopt\n", uid); exit(65); } // drop capabilities struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(66); } } static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0; static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1; static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2; static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3; static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4; static void run_profman_merge(const std::vector& profiles_fd, fd_t reference_profile_fd) { static const size_t MAX_INT_LEN = 32; static const char* PROFMAN_BIN = "/system/bin/profman"; std::vector profile_args(profiles_fd.size()); char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN]; for (size_t k = 0; k < profiles_fd.size(); k++) { sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]); profile_args[k].assign(profile_buf); } char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN]; sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd); // program name, reference profile fd, the final NULL and the profile fds const char* argv[3 + profiles_fd.size()]; int i = 0; argv[i++] = PROFMAN_BIN; argv[i++] = reference_profile_arg; for (size_t k = 0; k < profile_args.size(); k++) { argv[i++] = profile_args[k].c_str(); } // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; execv(PROFMAN_BIN, (char * const *)argv); ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno)); exit(68); /* only get here on exec failure */ } // Decides if profile guided compilation is needed or not based on existing profiles. // Returns true if there is enough information in the current profiles that worth // a re-compilation of the package. // If the return value is true all the current profiles would have been merged into // the reference profiles accessible with open_reference_profile(). static bool analyse_profiles(uid_t uid, const char* pkgname) { std::vector profiles_fd; fd_t reference_profile_fd = -1; open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd); if (profiles_fd.empty() || (reference_profile_fd == -1)) { // Skip profile guided compilation because no profiles were found. // Or if the reference profile info couldn't be opened. close_all_fds(profiles_fd, "profiles_fd"); if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) { PLOG(WARNING) << "Failed to close fd for reference profile"; } return false; } ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); run_profman_merge(profiles_fd, reference_profile_fd); exit(68); /* only get here on exec failure */ } /* parent */ int return_code = wait_child(pid); bool need_to_compile = false; bool should_clear_current_profiles = false; bool should_clear_reference_profile = false; if (!WIFEXITED(return_code)) { LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code; } else { return_code = WEXITSTATUS(return_code); switch (return_code) { case PROFMAN_BIN_RETURN_CODE_COMPILE: need_to_compile = true; should_clear_current_profiles = true; should_clear_reference_profile = false; break; case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION: need_to_compile = false; should_clear_current_profiles = false; should_clear_reference_profile = false; break; case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES: LOG(WARNING) << "Bad profiles for package " << pkgname; need_to_compile = false; should_clear_current_profiles = true; should_clear_reference_profile = true; break; case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING: // Temporary IO problem (e.g. locking). Ignore but log a warning. LOG(WARNING) << "IO error while reading profiles for package " << pkgname; need_to_compile = false; should_clear_current_profiles = false; should_clear_reference_profile = false; break; default: // Unknown return code or error. Unlink profiles. LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname << ": " << return_code; need_to_compile = false; should_clear_current_profiles = true; should_clear_reference_profile = true; break; } } close_all_fds(profiles_fd, "profiles_fd"); if (close(reference_profile_fd) != 0) { PLOG(WARNING) << "Failed to close fd for reference profile"; } if (should_clear_current_profiles) { clear_current_profiles(pkgname); } if (should_clear_reference_profile) { clear_reference_profile(pkgname); } return need_to_compile; } static void run_profman_dump(const std::vector& profile_fds, fd_t reference_profile_fd, const std::vector& dex_locations, const std::vector& apk_fds, fd_t output_fd) { std::vector profman_args; static const char* PROFMAN_BIN = "/system/bin/profman"; profman_args.push_back(PROFMAN_BIN); profman_args.push_back("--dump-only"); profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd)); if (reference_profile_fd != -1) { profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d", reference_profile_fd)); } for (fd_t profile_fd : profile_fds) { profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fd)); } for (const std::string& dex_location : dex_locations) { profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str())); } for (fd_t apk_fd : apk_fds) { profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fd)); } const char **argv = new const char*[profman_args.size() + 1]; size_t i = 0; for (const std::string& profman_arg : profman_args) { argv[i++] = profman_arg.c_str(); } argv[i] = NULL; execv(PROFMAN_BIN, (char * const *)argv); ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno)); exit(68); /* only get here on exec failure */ } static const char* get_location_from_path(const char* path) { static constexpr char kLocationSeparator = '/'; const char *location = strrchr(path, kLocationSeparator); if (location == NULL) { return path; } else { // Skip the separator character. return location + 1; } } // Dumps the contents of a profile file, using pkgname's dex files for pretty // printing the result. bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) { std::vector profile_fds; fd_t reference_profile_fd = -1; std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname); ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname); open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd); const bool has_reference_profile = (reference_profile_fd != -1); const bool has_profiles = !profile_fds.empty(); if (!has_reference_profile && !has_profiles) { ALOGE("profman dump: no profiles to dump for '%s'", pkgname); return false; } fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW); if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) { ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str()); return false; } std::vector code_full_paths = base::Split(code_path_string, ";"); std::vector dex_locations; std::vector apk_fds; for (const std::string& code_full_path : code_full_paths) { const char* full_path = code_full_path.c_str(); fd_t apk_fd = open(full_path, O_RDONLY | O_NOFOLLOW); if (apk_fd == -1) { ALOGE("installd cannot open '%s'\n", full_path); return false; } dex_locations.push_back(get_location_from_path(full_path)); apk_fds.push_back(apk_fd); } pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); run_profman_dump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd); exit(68); /* only get here on exec failure */ } /* parent */ close_all_fds(apk_fds, "apk_fds"); close_all_fds(profile_fds, "profile_fds"); if (close(reference_profile_fd) != 0) { PLOG(WARNING) << "Failed to close fd for reference profile"; } int return_code = wait_child(pid); if (!WIFEXITED(return_code)) { LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code; return false; } return true; } static void trim_extension(char* path) { // Trim the extension. int pos = strlen(path); for (; pos >= 0 && path[pos] != '.'; --pos) {} if (pos >= 0) { path[pos] = '\0'; // Trim extension } } static bool add_extension_to_file_name(char* file_name, const char* extension) { if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) { return false; } strcat(file_name, extension); return true; } static int open_output_file(char* file_name, bool recreate, int permissions) { int flags = O_RDWR | O_CREAT; if (recreate) { if (unlink(file_name) < 0) { if (errno != ENOENT) { PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name; } } flags |= O_EXCL; } return open(file_name, flags, permissions); } static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) { if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("installd cannot chmod '%s' during dexopt\n", path); return false; } else if (fchown(fd, AID_SYSTEM, uid) < 0) { ALOGE("installd cannot chown '%s' during dexopt\n", path); return false; } return true; } static bool create_oat_out_path(const char* apk_path, const char* instruction_set, const char* oat_dir, /*out*/ char* out_path) { // Early best-effort check whether we can fit the the path into our buffers. // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // without a swap file, if necessary. Reference profiles file also add an extra ".prof" // extension to the cache path (5 bytes). if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { ALOGE("apk_path too long '%s'\n", apk_path); return false; } if (oat_dir != NULL && oat_dir[0] != '!') { if (validate_apk_path(oat_dir)) { ALOGE("invalid oat_dir '%s'\n", oat_dir); return false; } if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { return false; } } else { if (!create_cache_path(out_path, apk_path, instruction_set)) { return false; } } return true; } // TODO: Consider returning error codes. bool merge_profiles(uid_t uid, const char *pkgname) { return analyse_profiles(uid, pkgname); } int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries) { struct utimbuf ut; struct stat input_stat; char out_path[PKG_PATH_MAX]; char swap_file_name[PKG_PATH_MAX]; char image_path[PKG_PATH_MAX]; const char *input_file; char in_odex_path[PKG_PATH_MAX]; int res; fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1; bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0); bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0; bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0; bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0; bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0; CHECK(pkgname != nullptr); CHECK(pkgname[0] != 0); fd_t reference_profile_fd = -1; // Public apps should not be compiled with profile information ever. Same goes for the special // package '*' used for the system server. if (!is_public && pkgname[0] != '*') { // Open reference profile in read only mode as dex2oat does not get write permissions. reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false); // Note: it's OK to not find a profile here. } if ((dexopt_flags & ~DEXOPT_MASK) != 0) { LOG_FATAL("dexopt flags contains unknown fields\n"); } if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) { return false; } switch (dexopt_needed) { case DEXOPT_DEX2OAT_NEEDED: input_file = apk_path; break; case DEXOPT_PATCHOAT_NEEDED: if (!calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) { return -1; } input_file = in_odex_path; break; case DEXOPT_SELF_PATCHOAT_NEEDED: input_file = out_path; break; default: ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); exit(72); } memset(&input_stat, 0, sizeof(input_stat)); stat(input_file, &input_stat); input_fd = open(input_file, O_RDONLY, 0); if (input_fd < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", input_file); return -1; } out_fd = open_output_file(out_path, /*recreate*/true, /*permissions*/0644); if (out_fd < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_path); goto fail; } if (!set_permissions_and_ownership(out_fd, is_public, uid, out_path)) { goto fail; } // Create a swap file if necessary. if (ShouldUseSwapFileForDexopt()) { // Make sure there really is enough space. strcpy(swap_file_name, out_path); if (add_extension_to_file_name(swap_file_name, ".swap")) { swap_fd = open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600); } if (swap_fd < 0) { // Could not create swap file. Optimistically go on and hope that we can compile // without it. ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name); } else { // Immediately unlink. We don't really want to hit flash. if (unlink(swap_file_name) < 0) { PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name; } } } // Avoid generating an app image for extract only since it will not contain any classes. strcpy(image_path, out_path); trim_extension(image_path); if (add_extension_to_file_name(image_path, ".art")) { char app_image_format[kPropertyValueMax]; bool have_app_image_format = get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; // Use app images only if it is enabled (by a set image format) and we are compiling // profile-guided (so the app image doesn't conservatively contain all classes). if (profile_guided && have_app_image_format) { // Recreate is true since we do not want to modify a mapped image. If the app is already // running and we modify the image file, it can cause crashes (b/27493510). image_fd = open_output_file(image_path, /*recreate*/true, /*permissions*/0600); if (image_fd < 0) { // Could not create application image file. Go on since we can compile without it. ALOGE("installd could not create '%s' for image file during dexopt\n", image_path); } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) { image_fd = -1; } } // If we have a valid image file path but no image fd, erase the image file. if (image_fd < 0) { if (unlink(image_path) < 0) { if (errno != ENOENT) { PLOG(ERROR) << "Couldn't unlink image file " << image_path; } } } } ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file); pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); SetDex2OatAndPatchOatScheduling(boot_complete); if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); exit(67); } if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set); } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { // Pass dex2oat the relative path to the input file. const char *input_file_name = get_location_from_path(input_file); run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd, instruction_set, compiler_filter, vm_safe_mode, debuggable, boot_complete, reference_profile_fd, shared_libraries); } else { ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); exit(73); } exit(68); /* only get here on exec failure */ } else { res = wait_child(pid); if (res == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", input_file); } else { ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res); goto fail; } } ut.actime = input_stat.st_atime; ut.modtime = input_stat.st_mtime; utime(out_path, &ut); close(out_fd); close(input_fd); if (swap_fd >= 0) { close(swap_fd); } if (reference_profile_fd >= 0) { close(reference_profile_fd); } if (image_fd >= 0) { close(image_fd); } return 0; fail: if (out_fd >= 0) { close(out_fd); unlink(out_path); } if (input_fd >= 0) { close(input_fd); } if (reference_profile_fd >= 0) { close(reference_profile_fd); // We failed to compile. Unlink the reference profile. Current profiles are already unlinked // when profmoan advises compilation. clear_reference_profile(pkgname); } if (swap_fd >= 0) { close(swap_fd); } if (image_fd >= 0) { close(image_fd); } return -1; } int mark_boot_complete(const char* instruction_set) { char boot_marker_path[PKG_PATH_MAX]; sprintf(boot_marker_path, "%s/%s/%s/.booting", android_data_dir.path, DALVIK_CACHE, instruction_set); ALOGV("mark_boot_complete : %s", boot_marker_path); if (unlink(boot_marker_path) != 0) { ALOGE("Unable to unlink boot marker at %s, error=%s", boot_marker_path, strerror(errno)); return -1; } return 0; } void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, struct stat* statbuf) { while (path[basepos] != 0) { if (path[basepos] == '/') { path[basepos] = 0; if (lstat(path, statbuf) < 0) { ALOGV("Making directory: %s\n", path); if (mkdir(path, mode) == 0) { chown(path, uid, gid); } else { ALOGW("Unable to make directory %s: %s\n", path, strerror(errno)); } } path[basepos] = '/'; basepos++; } basepos++; } } int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId) { struct stat s, libStat; int rc = 0; std::string _pkgdir(create_data_user_ce_package_path(uuid, userId, pkgname)); std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX); const char* pkgdir = _pkgdir.c_str(); const char* libsymlink = _libsymlink.c_str(); if (stat(pkgdir, &s) < 0) return -1; if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) { ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno)); return -1; } if (chmod(pkgdir, 0700) < 0) { ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno)); rc = -1; goto out; } if (lstat(libsymlink, &libStat) < 0) { if (errno != ENOENT) { ALOGE("couldn't stat lib dir: %s\n", strerror(errno)); rc = -1; goto out; } } else { if (S_ISDIR(libStat.st_mode)) { if (delete_dir_contents(libsymlink, 1, NULL) < 0) { rc = -1; goto out; } } else if (S_ISLNK(libStat.st_mode)) { if (unlink(libsymlink) < 0) { ALOGE("couldn't unlink lib dir: %s\n", strerror(errno)); rc = -1; goto out; } } } if (symlink(asecLibDir, libsymlink) < 0) { ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir, strerror(errno)); rc = -errno; goto out; } out: if (chmod(pkgdir, s.st_mode) < 0) { ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno)); rc = -errno; } if (chown(pkgdir, s.st_uid, s.st_gid) < 0) { ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno)); return -errno; } return rc; } static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) { static const char *IDMAP_BIN = "/system/bin/idmap"; static const size_t MAX_INT_LEN = 32; char idmap_str[MAX_INT_LEN]; snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd); execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL); ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno)); } // Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix) // eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap static int flatten_path(const char *prefix, const char *suffix, const char *overlay_path, char *idmap_path, size_t N) { if (overlay_path == NULL || idmap_path == NULL) { return -1; } const size_t len_overlay_path = strlen(overlay_path); // will access overlay_path + 1 further below; requires absolute path if (len_overlay_path < 2 || *overlay_path != '/') { return -1; } const size_t len_idmap_root = strlen(prefix); const size_t len_suffix = strlen(suffix); if (SIZE_MAX - len_idmap_root < len_overlay_path || SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) { // additions below would cause overflow return -1; } if (N < len_idmap_root + len_overlay_path + len_suffix) { return -1; } memset(idmap_path, 0, N); snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix); char *ch = idmap_path + len_idmap_root; while (*ch != '\0') { if (*ch == '/') { *ch = '@'; } ++ch; } return 0; } int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) { ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid); int idmap_fd = -1; char idmap_path[PATH_MAX]; if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, idmap_path, sizeof(idmap_path)) == -1) { ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); goto fail; } unlink(idmap_path); idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (idmap_fd < 0) { ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno)); goto fail; } if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) { ALOGE("idmap cannot chown '%s'\n", idmap_path); goto fail; } if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { ALOGE("idmap cannot chmod '%s'\n", idmap_path); goto fail; } pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during idmap\n", uid); exit(1); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed during idmap\n", uid); exit(1); } if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno)); exit(1); } run_idmap(target_apk, overlay_apk, idmap_fd); exit(1); /* only if exec call to idmap failed */ } else { int status = wait_child(pid); if (status != 0) { ALOGE("idmap failed, status=0x%04x\n", status); goto fail; } } close(idmap_fd); return 0; fail: if (idmap_fd >= 0) { close(idmap_fd); unlink(idmap_path); } return -1; } int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags, appid_t appid, const char* seinfo) { int res = 0; // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE; if (!pkgName || !seinfo) { ALOGE("Package name or seinfo tag is null when trying to restorecon."); return -1; } uid_t uid = multiuser_get_uid(userid, appid); if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_package_path(uuid, userid, pkgName); if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) { PLOG(ERROR) << "restorecon failed for " << path; res = -1; } } if (flags & FLAG_STORAGE_DE) { auto path = create_data_user_de_package_path(uuid, userid, pkgName); if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) { PLOG(ERROR) << "restorecon failed for " << path; // TODO: include result once 25796509 is fixed } } return res; } int create_oat_dir(const char* oat_dir, const char* instruction_set) { char oat_instr_dir[PKG_PATH_MAX]; if (validate_apk_path(oat_dir)) { ALOGE("invalid apk path '%s' (bad prefix)\n", oat_dir); return -1; } if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) { return -1; } if (selinux_android_restorecon(oat_dir, 0)) { ALOGE("cannot restorecon dir '%s': %s\n", oat_dir, strerror(errno)); return -1; } snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set); if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) { return -1; } return 0; } int rm_package_dir(const char* apk_path) { if (validate_apk_path(apk_path)) { ALOGE("invalid apk path '%s' (bad prefix)\n", apk_path); return -1; } return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */); } int link_file(const char* relative_path, const char* from_base, const char* to_base) { char from_path[PKG_PATH_MAX]; char to_path[PKG_PATH_MAX]; snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path); snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path); if (validate_apk_path_subdirs(from_path)) { ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path); return -1; } if (validate_apk_path_subdirs(to_path)) { ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path); return -1; } const int ret = link(from_path, to_path); if (ret < 0) { ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno)); return -1; } return 0; } // Helper for move_ab, so that we can have common failure-case cleanup. static bool unlink_and_rename(const char* from, const char* to) { // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise, // return a failure. struct stat s; if (stat(to, &s) == 0) { if (!S_ISREG(s.st_mode)) { LOG(ERROR) << from << " is not a regular file to replace for A/B."; return false; } if (unlink(to) != 0) { LOG(ERROR) << "Could not unlink " << to << " to move A/B."; return false; } } else { // This may be a permission problem. We could investigate the error code, but we'll just // let the rename failure do the work for us. } // Try to rename "to" to "from." if (rename(from, to) != 0) { PLOG(ERROR) << "Could not rename " << from << " to " << to; return false; } return true; } int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) { if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) { LOG(ERROR) << "Cannot move_ab with null input"; return -1; } if (validate_apk_path(apk_path) != 0) { LOG(ERROR) << "invalid apk_path " << apk_path; return -1; } if (validate_apk_path(oat_dir) != 0) { LOG(ERROR) << "invalid oat_dir " << oat_dir; return -1; } char a_path[PKG_PATH_MAX]; if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) { return -1; } // B path = A path + ".b" std::string b_path = StringPrintf("%s.b", a_path); // Check whether B exists. { struct stat s; if (stat(b_path.c_str(), &s) != 0) { // Silently ignore for now. The service calling this isn't smart enough to understand // lack of artifacts at the moment. return -1; } if (!S_ISREG(s.st_mode)) { LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file."; // Try to unlink, but swallow errors. unlink(b_path.c_str()); return -1; } } // Rename B to A. if (!unlink_and_rename(b_path.c_str(), a_path)) { // Delete the b_path so we don't try again (or fail earlier). if (unlink(b_path.c_str()) != 0) { PLOG(ERROR) << "Could not unlink " << b_path; } return -1; } return 0; } } // namespace installd } // namespace android cmds/installd/commands.h0100644 0000000 0000000 00000006410 13077405420 014322 0ustar000000000 0000000 /* ** ** Copyright 2008, 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 COMMANDS_H_ #define COMMANDS_H_ #include #include #include #include namespace android { namespace installd { int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, appid_t appid, const char* seinfo, int target_sdk_version); int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags, appid_t appid, const char* seinfo); int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags); int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode); int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode); int move_complete_app(const char* from_uuid, const char *to_uuid, const char *package_name, const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version); int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode, const char* code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize); int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode); int create_user_data(const char *uuid, userid_t userid, int user_serial, int flags); int destroy_user_data(const char *uuid, userid_t userid, int flags); int rm_dex(const char *path, const char *instruction_set); int free_cache(const char *uuid, int64_t free_size); bool merge_profiles(uid_t uid, const char *pkgname); bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files); int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* shared_libraries); int mark_boot_complete(const char *instruction_set); int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid); int create_oat_dir(const char* oat_dir, const char *instruction_set); int rm_package_dir(const char* apk_path); int clear_app_profiles(const char* pkgname); int destroy_app_profiles(const char* pkgname); int link_file(const char *relative_path, const char *from_base, const char *to_base); // Move a B version over to the A location. Only works for oat_dir != nullptr. int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir); } // namespace installd } // namespace android #endif // COMMANDS_H_ cmds/installd/file_parsing.h0100644 0000000 0000000 00000002771 13077405420 015171 0ustar000000000 0000000 /* * Copyright (C) 2016 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 OTAPREOPT_FILE_PARSING_H_ #define OTAPREOPT_FILE_PARSING_H_ #include #include #include namespace android { namespace installd { bool ParseFile(const std::string& strFile, std::function parse) { std::ifstream input_stream(strFile); if (!input_stream.is_open()) { return false; } while (!input_stream.eof()) { // Read the next line. std::string line; getline(input_stream, line); // Is the line empty? Simplifies the next check. if (line.empty()) { continue; } // Is this a comment (starts with pound)? if (line[0] == '#') { continue; } if (!parse(line)) { return false; } } return true; } } // namespace installd } // namespace android #endif // OTAPREOPT_FILE_PARSING_H_ cmds/installd/globals.cpp0100644 0000000 0000000 00000010272 13077405420 014500 0ustar000000000 0000000 /* ** Copyright 2015, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include #include #include // TODO: Move everything to base::logging. #include #include #include #ifndef LOG_TAG #define LOG_TAG "installd" #endif namespace android { namespace installd { /* Directory records that are used in execution of commands. */ dir_rec_t android_app_dir; dir_rec_t android_app_ephemeral_dir; dir_rec_t android_app_lib_dir; dir_rec_t android_app_private_dir; dir_rec_t android_asec_dir; dir_rec_t android_data_dir; dir_rec_t android_media_dir; dir_rec_t android_mnt_expand_dir; dir_rec_t android_profiles_dir; dir_rec_array_t android_system_dirs; /** * Initialize all the global variables that are used elsewhere. Returns 0 upon * success and -1 on error. */ void free_globals() { size_t i; for (i = 0; i < android_system_dirs.count; i++) { if (android_system_dirs.dirs[i].path != NULL) { free(android_system_dirs.dirs[i].path); } } free(android_system_dirs.dirs); } bool init_globals_from_data_and_root(const char* data, const char* root) { // Get the android data directory. if (get_path_from_string(&android_data_dir, data) < 0) { return false; } // Get the android app directory. if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) { return false; } // Get the android protected app directory. if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) { return false; } // Get the android ephemeral app directory. if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) { return -1; } // Get the android app native library directory. if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) { return false; } // Get the sd-card ASEC mount point. if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) { return false; } // Get the android media directory. if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) { return false; } // Get the android external app directory. if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) { return false; } // Get the android profiles directory. if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) { return false; } // Take note of the system and vendor directories. android_system_dirs.count = 4; android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t)); if (android_system_dirs.dirs == NULL) { ALOGE("Couldn't allocate array for dirs; aborting\n"); return false; } dir_rec_t android_root_dir; if (get_path_from_string(&android_root_dir, root) < 0) { return false; } android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR); android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path); android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR); android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path); android_system_dirs.dirs[2].path = strdup("/vendor/app/"); android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path); android_system_dirs.dirs[3].path = strdup("/oem/app/"); android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path); return true; } } // namespace installd } // namespace android cmds/installd/globals.h0100644 0000000 0000000 00000002623 13077405420 014146 0ustar000000000 0000000 /* ** ** Copyright 2008, 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 GLOBALS_H_ #define GLOBALS_H_ #include namespace android { namespace installd { /* data structures */ struct dir_rec_t { char* path; size_t len; }; struct dir_rec_array_t { size_t count; dir_rec_t* dirs; }; extern dir_rec_t android_app_dir; extern dir_rec_t android_app_ephemeral_dir; extern dir_rec_t android_app_lib_dir; extern dir_rec_t android_app_private_dir; extern dir_rec_t android_asec_dir; extern dir_rec_t android_data_dir; extern dir_rec_t android_media_dir; extern dir_rec_t android_mnt_expand_dir; extern dir_rec_t android_profiles_dir; extern dir_rec_array_t android_system_dirs; void free_globals(); bool init_globals_from_data_and_root(const char* data, const char* root); } // namespace installd } // namespace android #endif // GLOBALS_H_ cmds/installd/installd.cpp0100644 0000000 0000000 00000056552 13077405420 014702 0ustar000000000 0000000 /* ** Copyright 2008, 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 #include #include #include #include #include #include #include #include #include #include // TODO: Move everything to base::logging. #include #include #include #include #include #include #include // Need to fill in requirements of commands. #include #ifndef LOG_TAG #define LOG_TAG "installd" #endif #define SOCKET_PATH "installd" #define BUFFER_MAX 1024 /* input buffer for commands */ #define TOKEN_MAX 16 /* max number of arguments in buffer */ #define REPLY_MAX 256 /* largest reply allowed */ namespace android { namespace installd { // Check that installd-deps sizes match cutils sizes. static_assert(kPropertyKeyMax == PROPERTY_KEY_MAX, "Size mismatch."); static_assert(kPropertyValueMax == PROPERTY_VALUE_MAX, "Size mismatch."); //////////////////////// // Plug-in functions. // //////////////////////// int get_property(const char *key, char *value, const char *default_value) { return property_get(key, value, default_value); } // Compute the output path of bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set) { char *file_name_start; char *file_name_end; file_name_start = strrchr(apk_path, '/'); if (file_name_start == NULL) { ALOGE("apk_path '%s' has no '/'s in it\n", apk_path); return false; } file_name_end = strrchr(apk_path, '.'); if (file_name_end < file_name_start) { ALOGE("apk_path '%s' has no extension\n", apk_path); return false; } // Calculate file_name int file_name_len = file_name_end - file_name_start - 1; char file_name[file_name_len + 1]; memcpy(file_name, file_name_start + 1, file_name_len); file_name[file_name_len] = '\0'; // /oat//.odex snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name); return true; } /* * Computes the odex file for the given apk_path and instruction_set. * /system/framework/whatever.jar -> /system/framework/oat//whatever.odex * * Returns false if it failed to determine the odex file path. */ bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path, const char *instruction_set) { if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set) + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) { ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path); return false; } strcpy(path, apk_path); char *end = strrchr(path, '/'); if (end == NULL) { ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path); return false; } const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/'); strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0 strcat(path, instruction_set); // path = /system/framework/oat/\0 strcat(path, apk_end); // path = /system/framework/oat//whatever.jar\0 end = strrchr(path, '.'); if (end == NULL) { ALOGE("apk_path '%s' has no extension.\n", apk_path); return false; } strcpy(end + 1, "odex"); return true; } bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) { /* demand that we are an absolute path */ if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) { return false; } size_t srclen = strlen(src); if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX? return false; } size_t dstlen = android_data_dir.len + strlen(DALVIK_CACHE) + 1 + strlen(instruction_set) + srclen + strlen(DALVIK_CACHE_POSTFIX) + 2; if (dstlen > PKG_PATH_MAX) { return false; } sprintf(path,"%s%s/%s/%s%s", android_data_dir.path, DALVIK_CACHE, instruction_set, src + 1, /* skip the leading / */ DALVIK_CACHE_POSTFIX); char* tmp = path + android_data_dir.len + strlen(DALVIK_CACHE) + 1 + strlen(instruction_set) + 1; for(; *tmp; tmp++) { if (*tmp == '/') { *tmp = '@'; } } return true; } static char* parse_null(char* arg) { if (strcmp(arg, "!") == 0) { return nullptr; } else { return arg; } } static int do_ping(char **arg ATTRIBUTE_UNUSED, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return 0; } static int do_create_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, const char *pkgname, userid_t userid, int flags, appid_t appid, const char* seinfo, int target_sdk_version */ return create_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]), arg[5], atoi(arg[6])); } static int do_restorecon_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char* uuid, const char* pkgName, userid_t userid, int flags, appid_t appid, const char* seinfo */ return restorecon_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]), arg[5]); } static int do_migrate_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, const char *pkgname, userid_t userid, int flags */ return migrate_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3])); } static int do_clear_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */ return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4])); } static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */ return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4])); } // We use otapreopt_chroot to get into the chroot. static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot"; static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { // Time to fork and run otapreopt. // Check that the tool exists. struct stat s; if (stat(kOtaPreopt, &s) != 0) { LOG(ERROR) << "Otapreopt chroot tool not found."; return -1; } pid_t pid = fork(); if (pid == 0) { const char* argv[1 + 9 + 1]; argv[0] = kOtaPreopt; for (size_t i = 1; i <= 9; ++i) { argv[i] = arg[i - 1]; } argv[10] = nullptr; execv(argv[0], (char * const *)argv); PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed"; exit(99); } else { int res = wait_child(pid); if (res == 0) { ALOGV("DexInv: --- END OTAPREOPT (success) ---\n"); } else { ALOGE("DexInv: --- END OTAPREOPT --- status=0x%04x, process failed\n", res); } return res; } } static int do_dexopt(char **arg, char reply[REPLY_MAX]) { int dexopt_flags = atoi(arg[6]); if ((dexopt_flags & DEXOPT_OTA) != 0) { return do_ota_dexopt(arg, reply); } return dexopt(arg[0], // apk_path atoi(arg[1]), // uid arg[2], // pkgname arg[3], // instruction_set atoi(arg[4]), // dexopt_needed arg[5], // oat_dir dexopt_flags, arg[7], // compiler_filter parse_null(arg[8]), // volume_uuid parse_null(arg[9])); // shared_libraries } static int do_merge_profiles(char **arg, char reply[REPLY_MAX]) { uid_t uid = static_cast(atoi(arg[0])); const char* pkgname = arg[1]; if (merge_profiles(uid, pkgname)) { strncpy(reply, "true", REPLY_MAX); } else { strncpy(reply, "false", REPLY_MAX); } return 0; } static int do_dump_profiles(char **arg, char reply[REPLY_MAX]) { uid_t uid = static_cast(atoi(arg[0])); const char* pkgname = arg[1]; const char* dex_files = arg[2]; if (dump_profile(uid, pkgname, dex_files)) { strncpy(reply, "true", REPLY_MAX); } else { strncpy(reply, "false", REPLY_MAX); } return 0; } static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return mark_boot_complete(arg[0] /* instruction set */); } static int do_rm_dex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return rm_dex(arg[0], arg[1]); /* pkgname, instruction_set */ } static int do_free_cache(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) /* TODO int:free_size */ { return free_cache(parse_null(arg[0]), (int64_t)atoll(arg[1])); /* uuid, free_size */ } static int do_get_app_size(char **arg, char reply[REPLY_MAX]) { int64_t codesize = 0; int64_t datasize = 0; int64_t cachesize = 0; int64_t asecsize = 0; int res = 0; /* const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode, const char* code_path */ res = get_app_size(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]), arg[5], &codesize, &datasize, &cachesize, &asecsize); /* * Each int64_t can take up 22 characters printed out. Make sure it * doesn't go over REPLY_MAX in the future. */ snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize, asecsize); return res; } static int do_get_app_data_inode(char **arg, char reply[REPLY_MAX]) { ino_t inode = 0; int res = 0; /* const char *uuid, const char *pkgname, int userid, int flags */ res = get_app_data_inode(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), &inode); snprintf(reply, REPLY_MAX, "%" PRId64, (int64_t) inode); return res; } static int do_move_complete_app(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char* from_uuid, const char *to_uuid, const char *package_name, const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version */ return move_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5], atoi(arg[6])); } static int do_create_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, userid_t userid, int user_serial, int flags */ return create_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2]), atoi(arg[3])); } static int do_destroy_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* const char *uuid, userid_t userid, int flags */ return destroy_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2])); } static int do_linklib(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return linklib(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3])); } static int do_idmap(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return idmap(arg[0], arg[1], atoi(arg[2])); } static int do_create_oat_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* oat_dir, instruction_set */ return create_oat_dir(arg[0], arg[1]); } static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* oat_dir */ return rm_package_dir(arg[0]); } static int do_clear_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* package_name */ return clear_app_profiles(arg[0]); } static int do_destroy_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* package_name */ return destroy_app_profiles(arg[0]); } static int do_link_file(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { /* relative_path, from_base, to_base */ return link_file(arg[0], arg[1], arg[2]); } static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { // apk_path, instruction_set, oat_dir return move_ab(arg[0], arg[1], arg[2]); } struct cmdinfo { const char *name; unsigned numargs; int (*func)(char **arg, char reply[REPLY_MAX]); }; struct cmdinfo cmds[] = { { "ping", 0, do_ping }, { "create_app_data", 7, do_create_app_data }, { "restorecon_app_data", 6, do_restorecon_app_data }, { "migrate_app_data", 4, do_migrate_app_data }, { "clear_app_data", 5, do_clear_app_data }, { "destroy_app_data", 5, do_destroy_app_data }, { "move_complete_app", 7, do_move_complete_app }, { "get_app_size", 6, do_get_app_size }, { "get_app_data_inode", 4, do_get_app_data_inode }, { "create_user_data", 4, do_create_user_data }, { "destroy_user_data", 3, do_destroy_user_data }, { "dexopt", 10, do_dexopt }, { "markbootcomplete", 1, do_mark_boot_complete }, { "rmdex", 2, do_rm_dex }, { "freecache", 2, do_free_cache }, { "linklib", 4, do_linklib }, { "idmap", 3, do_idmap }, { "createoatdir", 2, do_create_oat_dir }, { "rmpackagedir", 1, do_rm_package_dir }, { "clear_app_profiles", 1, do_clear_app_profiles }, { "destroy_app_profiles", 1, do_destroy_app_profiles }, { "linkfile", 3, do_link_file }, { "move_ab", 3, do_move_ab }, { "merge_profiles", 2, do_merge_profiles }, { "dump_profiles", 3, do_dump_profiles }, }; static int readx(int s, void *_buf, int count) { char *buf = (char *) _buf; int n = 0, r; if (count < 0) return -1; while (n < count) { r = read(s, buf + n, count - n); if (r < 0) { if (errno == EINTR) continue; ALOGE("read error: %s\n", strerror(errno)); return -1; } if (r == 0) { ALOGE("eof\n"); return -1; /* EOF */ } n += r; } return 0; } static int writex(int s, const void *_buf, int count) { const char *buf = (const char *) _buf; int n = 0, r; if (count < 0) return -1; while (n < count) { r = write(s, buf + n, count - n); if (r < 0) { if (errno == EINTR) continue; ALOGE("write error: %s\n", strerror(errno)); return -1; } n += r; } return 0; } /* Tokenize the command buffer, locate a matching command, * ensure that the required number of arguments are provided, * call the function(), return the result. */ static int execute(int s, char cmd[BUFFER_MAX]) { char reply[REPLY_MAX]; char *arg[TOKEN_MAX+1]; unsigned i; unsigned n = 0; unsigned short count; int ret = -1; // ALOGI("execute('%s')\n", cmd); /* default reply is "" */ reply[0] = 0; /* n is number of args (not counting arg[0]) */ arg[0] = cmd; while (*cmd) { if (isspace(*cmd)) { *cmd++ = 0; n++; arg[n] = cmd; if (n == TOKEN_MAX) { ALOGE("too many arguments\n"); goto done; } } if (*cmd) { cmd++; } } for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { if (!strcmp(cmds[i].name,arg[0])) { if (n != cmds[i].numargs) { ALOGE("%s requires %d arguments (%d given)\n", cmds[i].name, cmds[i].numargs, n); } else { ret = cmds[i].func(arg + 1, reply); } goto done; } } ALOGE("unsupported command '%s'\n", arg[0]); done: if (reply[0]) { n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply); } else { n = snprintf(cmd, BUFFER_MAX, "%d", ret); } if (n > BUFFER_MAX) n = BUFFER_MAX; count = n; // ALOGI("reply: '%s'\n", cmd); if (writex(s, &count, sizeof(count))) return -1; if (writex(s, cmd, count)) return -1; return 0; } bool initialize_globals() { const char* data_path = getenv("ANDROID_DATA"); if (data_path == nullptr) { ALOGE("Could not find ANDROID_DATA"); return false; } const char* root_path = getenv("ANDROID_ROOT"); if (root_path == nullptr) { ALOGE("Could not find ANDROID_ROOT"); return false; } return init_globals_from_data_and_root(data_path, root_path); } static int initialize_directories() { int res = -1; // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { oldVersion = 0; } int version = oldVersion; if (version < 2) { SLOGD("Assuming that device has multi-user storage layout; upgrade no longer supported"); version = 2; } if (ensure_config_user_dirs(0) == -1) { ALOGE("Failed to setup misc for user 0"); goto fail; } if (version == 2) { ALOGD("Upgrading to /data/misc/user directories"); char misc_dir[PATH_MAX]; snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path); char keychain_added_dir[PATH_MAX]; snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir); char keychain_removed_dir[PATH_MAX]; snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir); DIR *dir; struct dirent *dirent; dir = opendir("/data/user"); if (dir != NULL) { while ((dirent = readdir(dir))) { const char *name = dirent->d_name; // skip "." and ".." if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } uint32_t user_id = atoi(name); // /data/misc/user/ if (ensure_config_user_dirs(user_id) == -1) { goto fail; } char misc_added_dir[PATH_MAX]; snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name); char misc_removed_dir[PATH_MAX]; snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name); uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM); gid_t gid = uid; if (access(keychain_added_dir, F_OK) == 0) { if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) { ALOGE("Some files failed to copy"); } } if (access(keychain_removed_dir, F_OK) == 0) { if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) { ALOGE("Some files failed to copy"); } } } closedir(dir); if (access(keychain_added_dir, F_OK) == 0) { delete_dir_contents(keychain_added_dir, 1, 0); } if (access(keychain_removed_dir, F_OK) == 0) { delete_dir_contents(keychain_removed_dir, 1, 0); } } version = 3; } // Persist layout version if changed if (version != oldVersion) { if (fs_write_atomic_int(version_path, version) == -1) { ALOGE("Failed to save version to %s: %s", version_path, strerror(errno)); goto fail; } } // Success! res = 0; fail: return res; } static int log_callback(int type, const char *fmt, ...) { va_list ap; int priority; switch (type) { case SELINUX_WARNING: priority = ANDROID_LOG_WARN; break; case SELINUX_INFO: priority = ANDROID_LOG_INFO; break; default: priority = ANDROID_LOG_ERROR; break; } va_start(ap, fmt); LOG_PRI_VA(priority, "SELinux", fmt, ap); va_end(ap); return 0; } static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; int lsocket, s; int selinux_enabled = (is_selinux_enabled() > 0); setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv); ALOGI("installd firing up\n"); union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); if (!initialize_globals()) { ALOGE("Could not initialize globals; exiting.\n"); exit(1); } if (initialize_directories() < 0) { ALOGE("Could not create directories; exiting.\n"); exit(1); } if (selinux_enabled && selinux_status_open(true) < 0) { ALOGE("Could not open selinux status; exiting.\n"); exit(1); } lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); exit(1); } if (listen(lsocket, 5)) { ALOGE("Listen on socket failed: %s\n", strerror(errno)); exit(1); } fcntl(lsocket, F_SETFD, FD_CLOEXEC); for (;;) { alen = sizeof(addr); s = accept(lsocket, &addr, &alen); if (s < 0) { ALOGE("Accept failed: %s\n", strerror(errno)); continue; } fcntl(s, F_SETFD, FD_CLOEXEC); ALOGI("new connection\n"); for (;;) { unsigned short count; if (readx(s, &count, sizeof(count))) { ALOGE("failed to read size\n"); break; } if ((count < 1) || (count >= BUFFER_MAX)) { ALOGE("invalid size %d\n", count); break; } if (readx(s, buf, count)) { ALOGE("failed to read command\n"); break; } buf[count] = 0; if (selinux_enabled && selinux_status_updated() > 0) { selinux_android_seapp_context_reload(); } if (execute(s, buf)) break; } ALOGI("closing connection\n"); close(s); } return 0; } } // namespace installd } // namespace android int main(const int argc, char *argv[]) { return android::installd::installd_main(argc, argv); } cmds/installd/installd.rc0100644 0000000 0000000 00000000142 13077405420 014504 0ustar000000000 0000000 service installd /system/bin/installd class main socket installd stream 600 system system cmds/installd/installd_constants.h0100644 0000000 0000000 00000007103 13077405420 016427 0ustar000000000 0000000 /* ** ** Copyright 2008, 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 INSTALLD_CONSTANTS_H_ #define INSTALLD_CONSTANTS_H_ namespace android { namespace installd { /* elements combined with a valid package name to form paths */ constexpr const char* PRIMARY_USER_PREFIX = "data/"; constexpr const char* SECONDARY_USER_PREFIX = "user/"; constexpr const char* PKG_DIR_POSTFIX = ""; constexpr const char* PKG_LIB_POSTFIX = "/lib"; constexpr const char* CACHE_DIR_POSTFIX = "/cache"; constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache"; constexpr const char* APP_SUBDIR = "app/"; // sub-directory under ANDROID_DATA constexpr const char* PRIV_APP_SUBDIR = "priv-app/"; // sub-directory under ANDROID_DATA constexpr const char* EPHEMERAL_APP_SUBDIR = "app-ephemeral/"; // sub-directory under ANDROID_DATA constexpr const char* APP_LIB_SUBDIR = "app-lib/"; // sub-directory under ANDROID_DATA constexpr const char* MEDIA_SUBDIR = "media/"; // sub-directory under ANDROID_DATA constexpr const char* PROFILES_SUBDIR = "misc/profiles"; // sub-directory under ANDROID_DATA /* other handy constants */ constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under ANDROID_DATA // This is used as a string literal, can't be constants. TODO: std::string... #define DALVIK_CACHE "dalvik-cache" constexpr const char* DALVIK_CACHE_POSTFIX = "/classes.dex"; constexpr const char* DALVIK_CACHE_POSTFIX2 = "@classes.dex"; constexpr const char* IDMAP_PREFIX = "/data/resource-cache/"; constexpr const char* IDMAP_SUFFIX = "@idmap"; constexpr size_t PKG_NAME_MAX = 128u; /* largest allowed package name */ constexpr size_t PKG_PATH_MAX = 256u; /* max size of any path we use */ // NOTE: keep in sync with StorageManager constexpr int FLAG_STORAGE_DE = 1 << 0; constexpr int FLAG_STORAGE_CE = 1 << 1; // NOTE: keep in sync with Installer constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8; constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9; /* dexopt needed flags matching those in dalvik.system.DexFile */ constexpr int DEXOPT_DEX2OAT_NEEDED = 1; constexpr int DEXOPT_PATCHOAT_NEEDED = 2; constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3; /**************************************************************************** * IMPORTANT: These values are passed from Java code. Keep them in sync with * frameworks/base/services/core/java/com/android/server/pm/Installer.java ***************************************************************************/ constexpr int DEXOPT_PUBLIC = 1 << 1; constexpr int DEXOPT_SAFEMODE = 1 << 2; constexpr int DEXOPT_DEBUGGABLE = 1 << 3; constexpr int DEXOPT_BOOTCOMPLETE = 1 << 4; constexpr int DEXOPT_PROFILE_GUIDED = 1 << 5; constexpr int DEXOPT_OTA = 1 << 6; /* all known values for dexopt flags */ constexpr int DEXOPT_MASK = DEXOPT_PUBLIC | DEXOPT_SAFEMODE | DEXOPT_DEBUGGABLE | DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_OTA; #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) } // namespace installd } // namespace android #endif // INSTALLD_CONSTANTS_H_ cmds/installd/installd_deps.h0100644 0000000 0000000 00000004511 13077405420 015346 0ustar000000000 0000000 /* ** ** Copyright 2008, 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 INSTALLD_DEPS_H_ #define INSTALLD_DEPS_H_ #include #include namespace android { namespace installd { // Dependencies for a full binary. These functions need to be provided to // figure out parts of the configuration. // Retrieve a system property. Same API as cutils, just renamed. extern int get_property(const char *key, char *value, const char *default_value); // Size constants. Should be checked to be equal to the cutils requirements. constexpr size_t kPropertyKeyMax = 32u; constexpr size_t kPropertyValueMax = 92u; // Compute the output path for dex2oat. extern bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set); // Compute the output path for patchoat. // // Computes the odex file for the given apk_path and instruction_set, e.g., // /system/framework/whatever.jar -> /system/framework/oat//whatever.odex // // Returns false if it failed to determine the odex file path. // extern bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path, const char *instruction_set); // Compute the output path into the dalvik cache. extern bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set); // Initialize globals. May be implemented with the helper in globals.h. extern bool initialize_globals(); } // namespace installd } // namespace android #endif // INSTALLD_DEPS_H_ cmds/installd/otapreopt.cpp0100644 0000000 0000000 00000057030 13077405420 015075 0ustar000000000 0000000 /* ** Copyright 2016, 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Need to fill in requirements of commands. #include #include #include #ifndef LOG_TAG #define LOG_TAG "otapreopt" #endif #define BUFFER_MAX 1024 /* input buffer for commands */ #define TOKEN_MAX 16 /* max number of arguments in buffer */ #define REPLY_MAX 256 /* largest reply allowed */ using android::base::StringPrintf; namespace android { namespace installd { static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH"; static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT"; static constexpr const char* kOTARootDirectory = "/system-b"; static constexpr size_t kISAIndex = 3; template static constexpr T RoundDown(T x, typename std::decay::type n) { return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n); } template static constexpr T RoundUp(T x, typename std::remove_reference::type n) { return RoundDown(x + n - 1, n); } class OTAPreoptService { public: static constexpr const char* kOTADataDirectory = "/data/ota"; // Main driver. Performs the following steps. // // 1) Parse options (read system properties etc from B partition). // // 2) Read in package data. // // 3) Prepare environment variables. // // 4) Prepare(compile) boot image, if necessary. // // 5) Run update. int Main(int argc, char** argv) { if (!ReadSystemProperties()) { LOG(ERROR)<< "Failed reading system properties."; return 1; } if (!ReadEnvironment()) { LOG(ERROR) << "Failed reading environment properties."; return 2; } if (!ReadPackage(argc, argv)) { LOG(ERROR) << "Failed reading command line file."; return 3; } PrepareEnvironment(); if (!PrepareBootImage()) { LOG(ERROR) << "Failed preparing boot image."; return 4; } int dexopt_retcode = RunPreopt(); return dexopt_retcode; } int GetProperty(const char* key, char* value, const char* default_value) { const std::string* prop_value = system_properties_.GetProperty(key); if (prop_value == nullptr) { if (default_value == nullptr) { return 0; } // Copy in the default value. strncpy(value, default_value, kPropertyValueMax - 1); value[kPropertyValueMax - 1] = 0; return strlen(default_value);// TODO: Need to truncate? } size_t size = std::min(kPropertyValueMax - 1, prop_value->length()); strncpy(value, prop_value->data(), size); value[size] = 0; return static_cast(size); } private: bool ReadSystemProperties() { static constexpr const char* kPropertyFiles[] = { "/default.prop", "/system/build.prop" }; for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) { if (!system_properties_.Load(kPropertyFiles[i])) { return false; } } return true; } bool ReadEnvironment() { // Parse the environment variables from init.environ.rc, which have the form // export NAME VALUE // For simplicity, don't respect string quotation. The values we are interested in can be // encoded without them. std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)"); bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) { std::smatch export_match; if (!std::regex_match(line, export_match, export_regex)) { return true; } if (export_match.size() != 3) { return true; } std::string name = export_match[1].str(); std::string value = export_match[2].str(); system_properties_.SetProperty(name, value); return true; }); if (!parse_result) { return false; } // Check that we found important properties. constexpr const char* kRequiredProperties[] = { kBootClassPathPropertyName, kAndroidRootPathPropertyName }; for (size_t i = 0; i < arraysize(kRequiredProperties); ++i) { if (system_properties_.GetProperty(kRequiredProperties[i]) == nullptr) { return false; } } return true; } bool ReadPackage(int argc ATTRIBUTE_UNUSED, char** argv) { size_t index = 0; while (index < ARRAY_SIZE(package_parameters_) && argv[index + 1] != nullptr) { package_parameters_[index] = argv[index + 1]; index++; } if (index != ARRAY_SIZE(package_parameters_)) { LOG(ERROR) << "Wrong number of parameters"; return false; } return true; } void PrepareEnvironment() { CHECK(system_properties_.GetProperty(kBootClassPathPropertyName) != nullptr); const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName); environ_.push_back(StringPrintf("BOOTCLASSPATH=%s", boot_cp.c_str())); environ_.push_back(StringPrintf("ANDROID_DATA=%s", kOTADataDirectory)); CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr); const std::string& android_root = *system_properties_.GetProperty(kAndroidRootPathPropertyName); environ_.push_back(StringPrintf("ANDROID_ROOT=%s", android_root.c_str())); for (const std::string& e : environ_) { putenv(const_cast(e.c_str())); } } // Ensure that we have the right boot image. The first time any app is // compiled, we'll try to generate it. bool PrepareBootImage() { if (package_parameters_[kISAIndex] == nullptr) { LOG(ERROR) << "Instruction set missing."; return false; } const char* isa = package_parameters_[kISAIndex]; // Check whether the file exists where expected. std::string dalvik_cache = std::string(kOTADataDirectory) + "/" + DALVIK_CACHE; std::string isa_path = dalvik_cache + "/" + isa; std::string art_path = isa_path + "/system@framework@boot.art"; std::string oat_path = isa_path + "/system@framework@boot.oat"; if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) { // Files exist, assume everything is alright. return true; } // Create the directories, if necessary. if (access(dalvik_cache.c_str(), F_OK) != 0) { if (mkdir(dalvik_cache.c_str(), 0711) != 0) { PLOG(ERROR) << "Could not create dalvik-cache dir"; return false; } } if (access(isa_path.c_str(), F_OK) != 0) { if (mkdir(isa_path.c_str(), 0711) != 0) { PLOG(ERROR) << "Could not create dalvik-cache isa dir"; return false; } } // Prepare to create. // TODO: Delete files, just for a blank slate. const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName); std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa); if (access(preopted_boot_art_path.c_str(), F_OK) == 0) { return PatchoatBootImage(art_path, isa); } else { // No preopted boot image. Try to compile. return Dex2oatBootImage(boot_cp, art_path, oat_path, isa); } } bool PatchoatBootImage(const std::string& art_path, const char* isa) { // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc. std::vector cmd; cmd.push_back("/system/bin/patchoat"); cmd.push_back("--input-image-location=/system/framework/boot.art"); cmd.push_back(StringPrintf("--output-image-file=%s", art_path.c_str())); cmd.push_back(StringPrintf("--instruction-set=%s", isa)); int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, ART_BASE_ADDRESS_MAX_DELTA); cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset)); std::string error_msg; bool result = Exec(cmd, &error_msg); if (!result) { LOG(ERROR) << "Could not generate boot image: " << error_msg; } return result; } bool Dex2oatBootImage(const std::string& boot_cp, const std::string& art_path, const std::string& oat_path, const char* isa) { // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc. std::vector cmd; cmd.push_back("/system/bin/dex2oat"); cmd.push_back(StringPrintf("--image=%s", art_path.c_str())); for (const std::string& boot_part : Split(boot_cp, ':')) { cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str())); } cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str())); int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, ART_BASE_ADDRESS_MAX_DELTA); cmd.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset)); cmd.push_back(StringPrintf("--instruction-set=%s", isa)); // These things are pushed by AndroidRuntime, see frameworks/base/core/jni/AndroidRuntime.cpp. AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xms", "-Xms", true, cmd); AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-Xmx", "-Xmx", true, cmd); AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-filter", "--compiler-filter=", false, cmd); cmd.push_back("--image-classes=/system/etc/preloaded-classes"); // TODO: Compiled-classes. const std::string* extra_opts = system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags"); if (extra_opts != nullptr) { std::vector extra_vals = Split(*extra_opts, ' '); cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end()); } // TODO: Should we lower this? It's usually set close to max, because // normally there's not much else going on at boot. AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-threads", "-j", false, cmd); AddCompilerOptionFromSystemProperty( StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(), "--instruction-set-variant=", false, cmd); AddCompilerOptionFromSystemProperty( StringPrintf("dalvik.vm.isa.%s.features", isa).c_str(), "--instruction-set-features=", false, cmd); std::string error_msg; bool result = Exec(cmd, &error_msg); if (!result) { LOG(ERROR) << "Could not generate boot image: " << error_msg; } return result; } static const char* ParseNull(const char* arg) { return (strcmp(arg, "!") == 0) ? nullptr : arg; } int RunPreopt() { int ret = dexopt(package_parameters_[0], // apk_path atoi(package_parameters_[1]), // uid package_parameters_[2], // pkgname package_parameters_[3], // instruction_set atoi(package_parameters_[4]), // dexopt_needed package_parameters_[5], // oat_dir atoi(package_parameters_[6]), // dexopt_flags package_parameters_[7], // compiler_filter ParseNull(package_parameters_[8]), // volume_uuid ParseNull(package_parameters_[9])); // shared_libraries return ret; } //////////////////////////////////// // Helpers, mostly taken from ART // //////////////////////////////////// // Wrapper on fork/execv to run a command in a subprocess. bool Exec(const std::vector& arg_vector, std::string* error_msg) { const std::string command_line(Join(arg_vector, ' ')); CHECK_GE(arg_vector.size(), 1U) << command_line; // Convert the args to char pointers. const char* program = arg_vector[0].c_str(); std::vector args; for (size_t i = 0; i < arg_vector.size(); ++i) { const std::string& arg = arg_vector[i]; char* arg_str = const_cast(arg.c_str()); CHECK(arg_str != nullptr) << i; args.push_back(arg_str); } args.push_back(nullptr); // Fork and exec. pid_t pid = fork(); if (pid == 0) { // No allocation allowed between fork and exec. // Change process groups, so we don't get reaped by ProcessManager. setpgid(0, 0); execv(program, &args[0]); PLOG(ERROR) << "Failed to execv(" << command_line << ")"; // _exit to avoid atexit handlers in child. _exit(1); } else { if (pid == -1) { *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", command_line.c_str(), strerror(errno)); return false; } // wait for subprocess to finish int status; pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (got_pid != pid) { *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " "wanted %d, got %d: %s", command_line.c_str(), pid, got_pid, strerror(errno)); return false; } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", command_line.c_str()); return false; } } return true; } // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc. static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) { constexpr size_t kPageSize = PAGE_SIZE; CHECK_EQ(min_delta % kPageSize, 0u); CHECK_EQ(max_delta % kPageSize, 0u); CHECK_LT(min_delta, max_delta); std::default_random_engine generator; generator.seed(GetSeed()); std::uniform_int_distribution distribution(min_delta, max_delta); int32_t r = distribution(generator); if (r % 2 == 0) { r = RoundUp(r, kPageSize); } else { r = RoundDown(r, kPageSize); } CHECK_LE(min_delta, r); CHECK_GE(max_delta, r); CHECK_EQ(r % kPageSize, 0u); return r; } static uint64_t GetSeed() { #ifdef __BIONIC__ // Bionic exposes arc4random, use it. uint64_t random_data; arc4random_buf(&random_data, sizeof(random_data)); return random_data; #else #error "This is only supposed to run with bionic. Otherwise, implement..." #endif } void AddCompilerOptionFromSystemProperty(const char* system_property, const char* prefix, bool runtime, std::vector& out) { const std::string* value = system_properties_.GetProperty(system_property); if (value != nullptr) { if (runtime) { out.push_back("--runtime-arg"); } if (prefix != nullptr) { out.push_back(StringPrintf("%s%s", prefix, value->c_str())); } else { out.push_back(*value); } } } // Stores the system properties read out of the B partition. We need to use these properties // to compile, instead of the A properties we could get from init/get_property. SystemProperties system_properties_; const char* package_parameters_[10]; // Store environment values we need to set. std::vector environ_; }; OTAPreoptService gOps; //////////////////////// // Plug-in functions. // //////////////////////// int get_property(const char *key, char *value, const char *default_value) { // TODO: Replace with system-properties map. return gOps.GetProperty(key, value, default_value); } // Compute the output path of bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set) { // TODO: Insert B directory. char *file_name_start; char *file_name_end; file_name_start = strrchr(apk_path, '/'); if (file_name_start == nullptr) { ALOGE("apk_path '%s' has no '/'s in it\n", apk_path); return false; } file_name_end = strrchr(file_name_start, '.'); if (file_name_end == nullptr) { ALOGE("apk_path '%s' has no extension\n", apk_path); return false; } // Calculate file_name file_name_start++; // Move past '/', is valid as file_name_end is valid. size_t file_name_len = file_name_end - file_name_start; std::string file_name(file_name_start, file_name_len); // /oat//.odex.b snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex.b", oat_dir, instruction_set, file_name.c_str()); return true; } /* * Computes the odex file for the given apk_path and instruction_set. * /system/framework/whatever.jar -> /system/framework/oat//whatever.odex * * Returns false if it failed to determine the odex file path. */ bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path, const char *instruction_set) { if (StringPrintf("%soat/%s/odex.b", apk_path, instruction_set).length() + 1 > PKG_PATH_MAX) { ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path); return false; } const char *path_end = strrchr(apk_path, '/'); if (path_end == nullptr) { ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path); return false; } std::string path_component(apk_path, path_end - apk_path); const char *name_begin = path_end + 1; const char *extension_start = strrchr(name_begin, '.'); if (extension_start == nullptr) { ALOGE("apk_path '%s' has no extension.\n", apk_path); return false; } std::string name_component(name_begin, extension_start - name_begin); std::string new_path = StringPrintf("%s/oat/%s/%s.odex.b", path_component.c_str(), instruction_set, name_component.c_str()); CHECK_LT(new_path.length(), PKG_PATH_MAX); strcpy(path, new_path.c_str()); return true; } bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) { size_t srclen = strlen(src); /* demand that we are an absolute path */ if ((src == 0) || (src[0] != '/') || strstr(src,"..")) { return false; } if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX? return false; } std::string from_src = std::string(src + 1); std::replace(from_src.begin(), from_src.end(), '/', '@'); std::string assembled_path = StringPrintf("%s/%s/%s/%s%s", OTAPreoptService::kOTADataDirectory, DALVIK_CACHE, instruction_set, from_src.c_str(), DALVIK_CACHE_POSTFIX2); if (assembled_path.length() + 1 > PKG_PATH_MAX) { return false; } strcpy(path, assembled_path.c_str()); return true; } bool initialize_globals() { const char* data_path = getenv("ANDROID_DATA"); if (data_path == nullptr) { ALOGE("Could not find ANDROID_DATA"); return false; } return init_globals_from_data_and_root(data_path, kOTARootDirectory); } static bool initialize_directories() { // This is different from the normal installd. We only do the base // directory, the rest will be created on demand when each app is compiled. mode_t old_umask = umask(0); LOG(INFO) << "Old umask: " << old_umask; if (access(OTAPreoptService::kOTADataDirectory, R_OK) < 0) { ALOGE("Could not access %s\n", OTAPreoptService::kOTADataDirectory); return false; } return true; } static int log_callback(int type, const char *fmt, ...) { va_list ap; int priority; switch (type) { case SELINUX_WARNING: priority = ANDROID_LOG_WARN; break; case SELINUX_INFO: priority = ANDROID_LOG_INFO; break; default: priority = ANDROID_LOG_ERROR; break; } va_start(ap, fmt); LOG_PRI_VA(priority, "SELinux", fmt, ap); va_end(ap); return 0; } static int otapreopt_main(const int argc, char *argv[]) { int selinux_enabled = (is_selinux_enabled() > 0); setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv); ALOGI("otapreopt firing up\n"); if (argc < 2) { ALOGE("Expecting parameters"); exit(1); } union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); if (!initialize_globals()) { ALOGE("Could not initialize globals; exiting.\n"); exit(1); } if (!initialize_directories()) { ALOGE("Could not create directories; exiting.\n"); exit(1); } if (selinux_enabled && selinux_status_open(true) < 0) { ALOGE("Could not open selinux status; exiting.\n"); exit(1); } int ret = android::installd::gOps.Main(argc, argv); return ret; } } // namespace installd } // namespace android int main(const int argc, char *argv[]) { return android::installd::otapreopt_main(argc, argv); } cmds/installd/otapreopt_chroot.cpp0100644 0000000 0000000 00000005473 13077405420 016457 0ustar000000000 0000000 /* ** Copyright 2016, 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 #include #include #include #include #include #ifndef LOG_TAG #define LOG_TAG "otapreopt" #endif using android::base::StringPrintf; namespace android { namespace installd { static int otapreopt_chroot(const int argc, char **arg) { // We need to run the otapreopt tool from the postinstall partition. As such, set up a // mount namespace and change root. // Create our own mount namespace. if (unshare(CLONE_NEWNS) != 0) { PLOG(ERROR) << "Failed to unshare() for otapreopt."; exit(200); } // Make postinstall private, so that our changes don't propagate. if (mount("", "/postinstall", nullptr, MS_PRIVATE, nullptr) != 0) { PLOG(ERROR) << "Failed to mount private."; exit(201); } // Bind mount necessary directories. constexpr const char* kBindMounts[] = { "/data", "/dev", "/proc", "/sys" }; for (size_t i = 0; i < arraysize(kBindMounts); ++i) { std::string trg = StringPrintf("/postinstall%s", kBindMounts[i]); if (mount(kBindMounts[i], trg.c_str(), nullptr, MS_BIND, nullptr) != 0) { PLOG(ERROR) << "Failed to bind-mount " << kBindMounts[i]; exit(202); } } // Chdir into /postinstall. if (chdir("/postinstall") != 0) { PLOG(ERROR) << "Unable to chdir into /postinstall."; exit(203); } // Make /postinstall the root in our mount namespace. if (chroot(".") != 0) { PLOG(ERROR) << "Failed to chroot"; exit(204); } if (chdir("/") != 0) { PLOG(ERROR) << "Unable to chdir into /."; exit(205); } // Now go on and run otapreopt. const char* argv[1 + 9 + 1]; CHECK_EQ(argc, 10); argv[0] = "/system/bin/otapreopt"; for (size_t i = 1; i <= 9; ++i) { argv[i] = arg[i]; } argv[10] = nullptr; execv(argv[0], (char * const *)argv); PLOG(ERROR) << "execv(OTAPREOPT) failed."; exit(99); } } // namespace installd } // namespace android int main(const int argc, char *argv[]) { return android::installd::otapreopt_chroot(argc, argv); } cmds/installd/otapreopt_script.sh0100644 0000000 0000000 00000002247 13077405420 016311 0ustar000000000 0000000 #!/system/bin/sh # # Copyright (C) 2016 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. # # This script will run as a postinstall step to drive otapreopt. # Maximum number of packages/steps. MAXIMUM_PACKAGES=1000 PREPARE=$(cmd otadexopt prepare) if [ "$PREPARE" != "Success" ] ; then echo "Failed to prepare." exit 1 fi i=0 while ((i #include #include namespace android { namespace installd { static inline bool StringStartsWith(const std::string& target, const char* prefix) { return target.compare(0, strlen(prefix), prefix) == 0; } // Split the input according to the separator character. Doesn't honor quotation. static inline std::vector Split(const std::string& in, const char separator) { if (in.empty()) { return std::vector(); } std::vector ret; std::stringstream strstr(in); std::string token; while (std::getline(strstr, token, separator)) { ret.push_back(token); } return ret; } template static inline std::string Join(const std::vector& strings, char separator) { if (strings.empty()) { return ""; } std::string result(strings[0]); for (size_t i = 1; i < strings.size(); ++i) { result += separator; result += strings[i]; } return result; } } // namespace installd } // namespace android #endif // ART_OTAPREOPT_STRING_HELPERS_H_ cmds/installd/system_properties.h0100644 0000000 0000000 00000004274 13077405420 016327 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef OTAPREOPT_SYSTEM_PROPERTIES_H_ #define OTAPREOPT_SYSTEM_PROPERTIES_H_ #include #include #include #include namespace android { namespace installd { // Helper class to read system properties into and manage as a string->string map. class SystemProperties { public: bool Load(const std::string& strFile) { return ParseFile(strFile, [&](const std::string& line) { size_t equals_pos = line.find('='); if (equals_pos == std::string::npos || equals_pos == 0) { // Did not find equals sign, or it's the first character - isn't a valid line. return true; } std::string key = line.substr(0, equals_pos); std::string value = line.substr(equals_pos + 1, line.length() - equals_pos + 1); properties_.insert(std::make_pair(key, value)); return true; }); } // Look up the key in the map. Returns null if the key isn't mapped. const std::string* GetProperty(const std::string& key) const { auto it = properties_.find(key); if (it != properties_.end()) { return &it->second; } return nullptr; } void SetProperty(const std::string& key, const std::string& value) { properties_.insert(std::make_pair(key, value)); } private: // The actual map. std::unordered_map properties_; }; } // namespace installd } // namespace android #endif // OTAPREOPT_SYSTEM_PROPERTIES_H_ cmds/installd/tests/0040755 0000000 0000000 00000000000 13077405420 013514 5ustar000000000 0000000 cmds/installd/tests/Android.mk0100644 0000000 0000000 00000001460 13077405420 015423 0ustar000000000 0000000 # Build the unit tests for installd LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk # Build the unit tests. test_src_files := \ installd_utils_test.cpp shared_libraries := \ libbase \ libutils \ libcutils \ static_libraries := \ libinstalld \ libdiskusage \ c_includes := \ frameworks/native/cmds/installd $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_C_INCLUDES := $(c_includes)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ $(eval LOCAL_CLANG := true) \ $(eval include $(BUILD_NATIVE_TEST)) \ ) cmds/installd/tests/installd_utils_test.cpp0100644 0000000 0000000 00000045706 13077405420 020322 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #undef LOG_TAG #define LOG_TAG "utils_test" #define TEST_DATA_DIR "/data/" #define TEST_APP_DIR "/data/app/" #define TEST_APP_PRIVATE_DIR "/data/app-private/" #define TEST_ASEC_DIR "/mnt/asec/" #define TEST_EXPAND_DIR "/mnt/expand/" #define TEST_SYSTEM_DIR1 "/system/app/" #define TEST_SYSTEM_DIR2 "/vendor/app/" #define REALLY_LONG_APP_NAME "com.example." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" #define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" namespace android { namespace installd { class UtilsTest : public testing::Test { protected: virtual void SetUp() { android_app_dir.path = (char*) TEST_APP_DIR; android_app_dir.len = strlen(TEST_APP_DIR); android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR; android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR); android_data_dir.path = (char*) TEST_DATA_DIR; android_data_dir.len = strlen(TEST_DATA_DIR); android_asec_dir.path = (char*) TEST_ASEC_DIR; android_asec_dir.len = strlen(TEST_ASEC_DIR); android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR; android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR); android_system_dirs.count = 2; android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t)); android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1; android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1); android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2; android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2); } virtual void TearDown() { free(android_system_dirs.dirs); } }; TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { // Bad prefixes directories const char *badprefix1 = "/etc/passwd"; EXPECT_EQ(-1, validate_apk_path(badprefix1)) << badprefix1 << " should be allowed as a valid path"; const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah"; EXPECT_EQ(-1, validate_apk_path(badprefix2)) << badprefix2 << " should be allowed as a valid path"; const char *badprefix3 = "init.rc"; EXPECT_EQ(-1, validate_apk_path(badprefix3)) << badprefix3 << " should be allowed as a valid path"; const char *badprefix4 = "/init.rc"; EXPECT_EQ(-1, validate_apk_path(badprefix4)) << badprefix4 << " should be allowed as a valid path"; } TEST_F(UtilsTest, IsValidApkPath_Internal) { // Internal directories const char *internal1 = TEST_APP_DIR "example.apk"; EXPECT_EQ(0, validate_apk_path(internal1)) << internal1 << " should be allowed as a valid path"; // b/16888084 const char *path2 = TEST_APP_DIR "example.com/example.apk"; EXPECT_EQ(0, validate_apk_path(path2)) << path2 << " should be allowed as a valid path"; const char *badint1 = TEST_APP_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badint1)) << badint1 << " should be rejected as a invalid path"; const char *badint2 = TEST_APP_DIR "/../example.apk"; EXPECT_EQ(-1, validate_apk_path(badint2)) << badint2 << " should be rejected as a invalid path"; // Only one subdir should be allowed. const char *bad_path3 = TEST_APP_DIR "example.com/subdir/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path3)) << bad_path3 << " should be rejected as a invalid path"; const char *bad_path4 = TEST_APP_DIR "example.com/subdir/../pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path4)) << bad_path4 << " should be rejected as a invalid path"; const char *bad_path5 = TEST_APP_DIR "example.com1/../example.com2/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path5)) << bad_path5 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_Private) { // Internal directories const char *private1 = TEST_APP_PRIVATE_DIR "example.apk"; EXPECT_EQ(0, validate_apk_path(private1)) << private1 << " should be allowed as a valid path"; // b/16888084 const char *path2 = TEST_APP_DIR "example.com/example.apk"; EXPECT_EQ(0, validate_apk_path(path2)) << path2 << " should be allowed as a valid path"; const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badpriv1)) << badpriv1 << " should be rejected as a invalid path"; const char *badpriv2 = TEST_APP_PRIVATE_DIR "/../example.apk"; EXPECT_EQ(-1, validate_apk_path(badpriv2)) << badpriv2 << " should be rejected as a invalid path"; // Only one subdir should be allowed. const char *bad_path3 = TEST_APP_PRIVATE_DIR "example.com/subdir/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path3)) << bad_path3 << " should be rejected as a invalid path"; const char *bad_path4 = TEST_APP_PRIVATE_DIR "example.com/subdir/../pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path4)) << bad_path4 << " should be rejected as a invalid path"; const char *bad_path5 = TEST_APP_PRIVATE_DIR "example.com1/../example.com2/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(bad_path5)) << bad_path5 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_AsecGood1) { const char *asec1 = TEST_ASEC_DIR "example.apk"; EXPECT_EQ(0, validate_apk_path(asec1)) << asec1 << " should be allowed as a valid path"; } TEST_F(UtilsTest, IsValidApkPath_AsecGood2) { const char *asec2 = TEST_ASEC_DIR "com.example.asec/pkg.apk"; EXPECT_EQ(0, validate_apk_path(asec2)) << asec2 << " should be allowed as a valid path"; } TEST_F(UtilsTest, IsValidApkPath_EscapeFail) { const char *badasec1 = TEST_ASEC_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badasec1)) << badasec1 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) { const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk"; EXPECT_EQ(-1, validate_apk_path(badasec2)) << badasec2 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) { const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk"; EXPECT_EQ(-1, validate_apk_path(badasec3)) << badasec3 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_SlashEscapeFail) { const char *badasec4 = TEST_ASEC_DIR "/../example.apk"; EXPECT_EQ(-1, validate_apk_path(badasec4)) << badasec4 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_CrazyDirFail) { const char *badasec5 = TEST_ASEC_DIR ".//../.."; EXPECT_EQ(-1, validate_apk_path(badasec5)) << badasec5 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeSingleFail) { const char *badasec6 = TEST_ASEC_DIR "com.example.asec/../pkg.apk"; EXPECT_EQ(-1, validate_apk_path(badasec6)) << badasec6 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, IsValidApkPath_TwoSubdirFail) { const char *badasec7 = TEST_ASEC_DIR "com.example.asec/subdir1/pkg.apk"; EXPECT_EQ(-1, validate_apk_path(badasec7)) << badasec7 << " should be rejected as a invalid path"; } TEST_F(UtilsTest, CheckSystemApp_Dir1) { const char *sysapp1 = TEST_SYSTEM_DIR1 "Voice.apk"; EXPECT_EQ(0, validate_system_app_path(sysapp1)) << sysapp1 << " should be allowed as a system path"; } TEST_F(UtilsTest, CheckSystemApp_Dir2) { const char *sysapp2 = TEST_SYSTEM_DIR2 "com.example.myapp.apk"; EXPECT_EQ(0, validate_system_app_path(sysapp2)) << sysapp2 << " should be allowed as a system path"; } TEST_F(UtilsTest, CheckSystemApp_EscapeFail) { const char *badapp1 = TEST_SYSTEM_DIR1 "../com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp1)) << badapp1 << " should be rejected not a system path"; } TEST_F(UtilsTest, CheckSystemApp_DoubleEscapeFail) { const char *badapp2 = TEST_SYSTEM_DIR2 "/../../com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp2)) << badapp2 << " should be rejected not a system path"; } TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) { const char *badapp3 = TEST_APP_DIR "/../../com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp3)) << badapp3 << " should be rejected not a system path"; } TEST_F(UtilsTest, CheckSystemApp_Subdir) { const char *sysapp = TEST_SYSTEM_DIR1 "com.example/com.example.apk"; EXPECT_EQ(0, validate_system_app_path(sysapp)) << sysapp << " should be allowed as a system path"; const char *badapp = TEST_SYSTEM_DIR1 "com.example/subdir/com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp)) << badapp << " should be rejected not a system path"; const char *badapp1 = TEST_SYSTEM_DIR1 "com.example/subdir/../com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp1)) << badapp1 << " should be rejected not a system path"; const char *badapp2 = TEST_SYSTEM_DIR1 "com.example1/../com.example2/com.example.apk"; EXPECT_EQ(-1, validate_system_app_path(badapp2)) << badapp2 << " should be rejected not a system path"; } TEST_F(UtilsTest, GetPathFromString_NullPathFail) { dir_rec_t test1; EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL)) << "Should not allow NULL as a path."; } TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) { dir_rec_t test1; EXPECT_EQ(-1, get_path_from_string(&test1, "")) << "Should not allow empty paths."; } TEST_F(UtilsTest, GetPathFromString_RelativePathFail) { dir_rec_t test1; EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec")) << "Should not allow relative paths."; } TEST_F(UtilsTest, GetPathFromString_NonCanonical) { dir_rec_t test1; EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec")) << "Should be able to canonicalize directory /mnt/asec"; EXPECT_STREQ("/mnt/asec/", test1.path) << "/mnt/asec should be canonicalized to /mnt/asec/"; EXPECT_EQ(10, (ssize_t) test1.len) << "path len should be equal to the length of /mnt/asec/ (10)"; free(test1.path); } TEST_F(UtilsTest, GetPathFromString_CanonicalPath) { dir_rec_t test3; EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/")) << "Should be able to canonicalize directory /data/app/"; EXPECT_STREQ("/data/app/", test3.path) << "/data/app/ should be canonicalized to /data/app/"; EXPECT_EQ(10, (ssize_t) test3.len) << "path len should be equal to the length of /data/app/ (10)"; free(test3.path); } TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) { char path[PKG_PATH_MAX]; // Create long packagename of "aaaaa..." size_t pkgnameSize = PKG_NAME_MAX; char pkgname[pkgnameSize + 1]; memset(pkgname, 'a', pkgnameSize); pkgname[pkgnameSize] = '\0'; EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0)) << "Should successfully be able to create package name."; std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX; size_t offset = prefix.length(); EXPECT_STREQ(pkgname, path + offset) << "Package path should be a really long string of a's"; } TEST_F(UtilsTest, CreatePkgPath_LongPkgNameFail) { char path[PKG_PATH_MAX]; // Create long packagename of "aaaaa..." size_t pkgnameSize = PKG_NAME_MAX + 1; char pkgname[pkgnameSize + 1]; memset(pkgname, 'a', pkgnameSize); pkgname[pkgnameSize] = '\0'; EXPECT_EQ(-1, create_pkg_path(path, pkgname, "", 0)) << "Should return error because package name is too long."; } TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) { char path[PKG_PATH_MAX]; // Create long packagename of "aaaaa..." size_t postfixSize = PKG_PATH_MAX; char postfix[postfixSize + 1]; memset(postfix, 'a', postfixSize); postfix[postfixSize] = '\0'; EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0)) << "Should return error because postfix is too long."; } TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) { char path[PKG_PATH_MAX]; EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0)) << "Should return error because postfix is too long."; std::string p = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX + "com.example.package"; EXPECT_STREQ(p.c_str(), path) << "Package path should be in /data/data/"; } TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) { char path[PKG_PATH_MAX]; EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1)) << "Should successfully create package path."; std::string p = std::string(TEST_DATA_DIR) + SECONDARY_USER_PREFIX + "1/com.example.package"; EXPECT_STREQ(p.c_str(), path) << "Package path should be in /data/user/"; } TEST_F(UtilsTest, CreateMovePath_Primary) { char path[PKG_PATH_MAX]; EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0)) << "Should be able to create move path for primary user"; EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path) << "Primary user package directory should be created correctly"; } TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { char path[PKG_PATH_MAX]; EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) << "Should fail to create move path for primary user"; } TEST_F(UtilsTest, CopyAndAppend_Normal) { //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix) dir_rec_t dst; dir_rec_t src; src.path = (char*) "/data/"; src.len = strlen(src.path); EXPECT_EQ(0, copy_and_append(&dst, &src, "app/")) << "Should return error because postfix is too long."; EXPECT_STREQ("/data/app/", dst.path) << "Appended path should be correct"; EXPECT_EQ(10, (ssize_t) dst.len) << "Appended path should be length of '/data/app/' (10)"; } TEST_F(UtilsTest, AppendAndIncrement_Normal) { size_t dst_size = 10; char dst[dst_size]; char *dstp = dst; const char* src = "FOO"; EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) << "String should append successfully"; EXPECT_STREQ("FOO", dst) << "String should append correctly"; EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) << "String should append successfully again"; EXPECT_STREQ("FOOFOO", dst) << "String should append correctly again"; } TEST_F(UtilsTest, AppendAndIncrement_TooBig) { size_t dst_size = 5; char dst[dst_size]; char *dstp = dst; const char* src = "FOO"; EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) << "String should append successfully"; EXPECT_STREQ("FOO", dst) << "String should append correctly"; EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size)) << "String should fail because it's too large to fit"; } TEST_F(UtilsTest, CreateDataPath) { EXPECT_EQ("/data", create_data_path(nullptr)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b", create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b")); } TEST_F(UtilsTest, CreateDataAppPath) { EXPECT_EQ("/data/app", create_data_app_path(nullptr)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app", create_data_app_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b")); } TEST_F(UtilsTest, CreateDataUserPath) { EXPECT_EQ("/data/data", create_data_user_ce_path(nullptr, 0)); EXPECT_EQ("/data/user/10", create_data_user_ce_path(nullptr, 10)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0", create_data_user_ce_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10", create_data_user_ce_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10)); } TEST_F(UtilsTest, CreateDataMediaPath) { EXPECT_EQ("/data/media/0", create_data_media_path(nullptr, 0)); EXPECT_EQ("/data/media/10", create_data_media_path(nullptr, 10)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/0", create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0)); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/10", create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10)); } TEST_F(UtilsTest, CreateDataAppPackagePath) { EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example")); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example", create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example")); } TEST_F(UtilsTest, CreateDataUserPackagePath) { EXPECT_EQ("/data/data/com.example", create_data_user_ce_package_path(nullptr, 0, "com.example")); EXPECT_EQ("/data/user/10/com.example", create_data_user_ce_package_path(nullptr, 10, "com.example")); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example", create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example")); EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example", create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example")); } } // namespace installd } // namespace android cmds/installd/utils.cpp0100644 0000000 0000000 00000112355 13077405420 014222 0ustar000000000 0000000 /* ** Copyright 2008, 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 "utils.h" #include #include #include #include #include #if defined(__APPLE__) #include #else #include #endif #include #include #include #include #include #include "globals.h" // extern variables. #ifndef LOG_TAG #define LOG_TAG "installd" #endif #define CACHE_NOISY(x) //x using android::base::StringPrintf; namespace android { namespace installd { /** * Check that given string is valid filename, and that it attempts no * parent or child directory traversal. */ static bool is_valid_filename(const std::string& name) { if (name.empty() || (name == ".") || (name == "..") || (name.find('/') != std::string::npos)) { return false; } else { return true; } } static void check_package_name(const char* package_name) { CHECK(is_valid_filename(package_name)); CHECK(is_valid_package_name(package_name) == 0); } /** * Create the path name where package app contents should be stored for * the given volume UUID and package name. An empty UUID is assumed to * be internal storage. */ std::string create_data_app_package_path(const char* volume_uuid, const char* package_name) { check_package_name(package_name); return StringPrintf("%s/%s", create_data_app_path(volume_uuid).c_str(), package_name); } /** * Create the path name where package data should be stored for the given * volume UUID, package name, and user ID. An empty UUID is assumed to be * internal storage. */ std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user, const char* package_name) { check_package_name(package_name); return StringPrintf("%s/%s", create_data_user_ce_path(volume_uuid, user).c_str(), package_name); } std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user, const char* package_name, ino_t ce_data_inode) { // For testing purposes, rely on the inode when defined; this could be // optimized to use access() in the future. auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name); if (ce_data_inode != 0) { auto user_path = create_data_user_ce_path(volume_uuid, user); DIR* dir = opendir(user_path.c_str()); if (dir == nullptr) { PLOG(ERROR) << "Failed to opendir " << user_path; return fallback; } struct dirent* ent; while ((ent = readdir(dir))) { if (ent->d_ino == ce_data_inode) { auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name); if (resolved != fallback) { LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode << " instead of " << fallback; } closedir(dir); return resolved; } } LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback; closedir(dir); return fallback; } else { return fallback; } } std::string create_data_user_de_package_path(const char* volume_uuid, userid_t user, const char* package_name) { check_package_name(package_name); return StringPrintf("%s/%s", create_data_user_de_path(volume_uuid, user).c_str(), package_name); } int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, const char *postfix, userid_t userid) { if (is_valid_package_name(pkgname) != 0) { path[0] = '\0'; return -1; } std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix); const char* tmp = _tmp.c_str(); if (strlen(tmp) >= PKG_PATH_MAX) { path[0] = '\0'; return -1; } else { strcpy(path, tmp); return 0; } } std::string create_data_path(const char* volume_uuid) { if (volume_uuid == nullptr) { return "/data"; } else { CHECK(is_valid_filename(volume_uuid)); return StringPrintf("/mnt/expand/%s", volume_uuid); } } /** * Create the path name for app data. */ std::string create_data_app_path(const char* volume_uuid) { return StringPrintf("%s/app", create_data_path(volume_uuid).c_str()); } /** * Create the path name for user data for a certain userid. */ std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) { std::string data(create_data_path(volume_uuid)); if (volume_uuid == nullptr) { if (userid == 0) { return StringPrintf("%s/data", data.c_str()); } else { return StringPrintf("%s/user/%u", data.c_str(), userid); } } else { return StringPrintf("%s/user/%u", data.c_str(), userid); } } /** * Create the path name for device encrypted user data for a certain userid. */ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) { std::string data(create_data_path(volume_uuid)); return StringPrintf("%s/user_de/%u", data.c_str(), userid); } /** * Create the path name for media for a certain userid. */ std::string create_data_media_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid); } std::string create_data_misc_legacy_path(userid_t userid) { return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid); } std::string create_data_user_profiles_path(userid_t userid) { return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid); } std::string create_data_user_profile_package_path(userid_t user, const char* package_name) { check_package_name(package_name); return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name); } std::string create_data_ref_profile_package_path(const char* package_name) { check_package_name(package_name); return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name); } std::vector get_known_users(const char* volume_uuid) { std::vector users; // We always have an owner users.push_back(0); std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX); DIR* dir = opendir(path.c_str()); if (dir == NULL) { // Unable to discover other users, but at least return owner PLOG(ERROR) << "Failed to opendir " << path; return users; } struct dirent* ent; while ((ent = readdir(dir))) { if (ent->d_type != DT_DIR) { continue; } char* end; userid_t user = strtol(ent->d_name, &end, 10); if (*end == '\0' && user != 0) { LOG(DEBUG) << "Found valid user " << user; users.push_back(user); } } closedir(dir); return users; } int create_move_path(char path[PKG_PATH_MAX], const char* pkgname, const char* leaf, userid_t userid ATTRIBUTE_UNUSED) { if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) { return -1; } sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); return 0; } /** * Checks whether the package name is valid. Returns -1 on error and * 0 on success. */ int is_valid_package_name(const char* pkgname) { const char *x = pkgname; int alpha = -1; if (strlen(pkgname) > PKG_NAME_MAX) { return -1; } while (*x) { if (isalnum(*x) || (*x == '_')) { /* alphanumeric or underscore are fine */ } else if (*x == '.') { if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) { /* periods must not be first, last, or doubled */ ALOGE("invalid package name '%s'\n", pkgname); return -1; } } else if (*x == '-') { /* Suffix -X is fine to let versioning of packages. But whatever follows should be alphanumeric.*/ alpha = 1; } else { /* anything not A-Z, a-z, 0-9, _, or . is invalid */ ALOGE("invalid package name '%s'\n", pkgname); return -1; } x++; } if (alpha == 1) { // Skip current character x++; while (*x) { if (!isalnum(*x)) { ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname); return -1; } x++; } } return 0; } static int _delete_dir_contents(DIR *d, int (*exclusion_predicate)(const char *name, const int is_dir)) { int result = 0; struct dirent *de; int dfd; dfd = dirfd(d); if (dfd < 0) return -1; while ((de = readdir(d))) { const char *name = de->d_name; /* check using the exclusion predicate, if provided */ if (exclusion_predicate && exclusion_predicate(name, (de->d_type == DT_DIR))) { continue; } if (de->d_type == DT_DIR) { int subfd; DIR *subdir; /* always skip "." and ".." */ if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); if (subfd < 0) { ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); result = -1; continue; } subdir = fdopendir(subfd); if (subdir == NULL) { ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(subfd); result = -1; continue; } if (_delete_dir_contents(subdir, exclusion_predicate)) { result = -1; } closedir(subdir); if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); result = -1; } } else { if (unlinkat(dfd, name, 0) < 0) { ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); result = -1; } } } return result; } int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) { return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing); } int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) { return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing); } int delete_dir_contents(const char *pathname, int also_delete_dir, int (*exclusion_predicate)(const char*, const int), bool ignore_if_missing) { int res = 0; DIR *d; d = opendir(pathname); if (d == NULL) { if (ignore_if_missing && (errno == ENOENT)) { return 0; } ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); return -errno; } res = _delete_dir_contents(d, exclusion_predicate); closedir(d); if (also_delete_dir) { if (rmdir(pathname)) { ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); res = -1; } } return res; } int delete_dir_contents_fd(int dfd, const char *name) { int fd, res; DIR *d; fd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); if (fd < 0) { ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); return -1; } d = fdopendir(fd); if (d == NULL) { ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(fd); return -1; } res = _delete_dir_contents(d, 0); closedir(d); return res; } static int _copy_owner_permissions(int srcfd, int dstfd) { struct stat st; if (fstat(srcfd, &st) != 0) { return -1; } if (fchmod(dstfd, st.st_mode) != 0) { return -1; } return 0; } static int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group) { int result = 0; if (_copy_owner_permissions(sdfd, ddfd) != 0) { ALOGE("_copy_dir_files failed to copy dir permissions\n"); } if (fchown(ddfd, owner, group) != 0) { ALOGE("_copy_dir_files failed to change dir owner\n"); } DIR *ds = fdopendir(sdfd); if (ds == NULL) { ALOGE("Couldn't fdopendir: %s\n", strerror(errno)); return -1; } struct dirent *de; while ((de = readdir(ds))) { if (de->d_type != DT_REG) { continue; } const char *name = de->d_name; int fsfd = openat(sdfd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); int fdfd = openat(ddfd, name, O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0600); if (fsfd == -1 || fdfd == -1) { ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); } else { if (_copy_owner_permissions(fsfd, fdfd) != 0) { ALOGE("Failed to change file permissions\n"); } if (fchown(fdfd, owner, group) != 0) { ALOGE("Failed to change file owner\n"); } char buf[8192]; ssize_t size; while ((size = read(fsfd, buf, sizeof(buf))) > 0) { write(fdfd, buf, size); } if (size < 0) { ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); result = -1; } } close(fdfd); close(fsfd); } return result; } int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, uid_t group) { int res = 0; DIR *ds = NULL; DIR *dd = NULL; ds = opendir(srcname); if (ds == NULL) { ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno)); return -errno; } mkdir(dstname, 0600); dd = opendir(dstname); if (dd == NULL) { ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno)); closedir(ds); return -errno; } int sdfd = dirfd(ds); int ddfd = dirfd(dd); if (sdfd != -1 && ddfd != -1) { res = _copy_dir_files(sdfd, ddfd, owner, group); } else { res = -errno; } closedir(dd); closedir(ds); return res; } int64_t data_disk_free(const std::string& data_path) { struct statfs sfs; if (statfs(data_path.c_str(), &sfs) == 0) { return sfs.f_bavail * sfs.f_bsize; } else { PLOG(ERROR) << "Couldn't statfs " << data_path; return -1; } } cache_t* start_cache_collection() { cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t)); return cache; } #define CACHE_BLOCK_SIZE (512*1024) static void* _cache_malloc(cache_t* cache, size_t len) { len = (len+3)&~3; if (len > (CACHE_BLOCK_SIZE/2)) { // It doesn't make sense to try to put this allocation into one // of our blocks, because it is so big. Instead, make a new dedicated // block for it. int8_t* res = (int8_t*)malloc(len+sizeof(void*)); if (res == NULL) { return NULL; } CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len)); // Link it into our list of blocks, not disrupting the current one. if (cache->memBlocks == NULL) { *(void**)res = NULL; cache->memBlocks = res; } else { *(void**)res = *(void**)cache->memBlocks; *(void**)cache->memBlocks = res; } return res + sizeof(void*); } int8_t* res = cache->curMemBlockAvail; int8_t* nextPos = res + len; if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) { int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE); if (newBlock == NULL) { return NULL; } CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock)); *(void**)newBlock = cache->memBlocks; cache->memBlocks = newBlock; res = cache->curMemBlockAvail = newBlock + sizeof(void*); cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE; nextPos = res + len; } CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p", res, len, cache->memBlocks, nextPos)); cache->curMemBlockAvail = nextPos; return res; } static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len) { // This isn't really a realloc, but it is good enough for our purposes here. void* alloc = _cache_malloc(cache, len); if (alloc != NULL && cur != NULL) { memcpy(alloc, cur, origLen < len ? origLen : len); } return alloc; } static void _inc_num_cache_collected(cache_t* cache) { cache->numCollected++; if ((cache->numCollected%20000) == 0) { ALOGI("Collected cache so far: %zd directories, %zd files", cache->numDirs, cache->numFiles); } } static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name) { size_t nameLen = strlen(name); cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1); if (dir != NULL) { dir->parent = parent; dir->childCount = 0; dir->hiddenCount = 0; dir->deleted = 0; strcpy(dir->name, name); if (cache->numDirs >= cache->availDirs) { size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2; cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs, cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*)); if (newDirs == NULL) { ALOGE("Failure growing cache dirs array for %s\n", name); return NULL; } cache->availDirs = newAvail; cache->dirs = newDirs; } cache->dirs[cache->numDirs] = dir; cache->numDirs++; if (parent != NULL) { parent->childCount++; } _inc_num_cache_collected(cache); } else { ALOGE("Failure allocating cache_dir_t for %s\n", name); } return dir; } static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime, const char *name) { size_t nameLen = strlen(name); cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1); if (file != NULL) { file->dir = dir; file->modTime = modTime; strcpy(file->name, name); if (cache->numFiles >= cache->availFiles) { size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2; cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files, cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*)); if (newFiles == NULL) { ALOGE("Failure growing cache file array for %s\n", name); return NULL; } cache->availFiles = newAvail; cache->files = newFiles; } CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file, cache->numFiles, cache->files)); cache->files[cache->numFiles] = file; cache->numFiles++; dir->childCount++; _inc_num_cache_collected(cache); } else { ALOGE("Failure allocating cache_file_t for %s\n", name); } return file; } static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName, DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen) { struct dirent *de; cache_dir_t* cacheDir = NULL; int dfd; CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s", parentDir, dirName, dir, pathBase)); dfd = dirfd(dir); if (dfd < 0) return 0; // Sub-directories always get added to the data structure, so if they // are empty we will know about them to delete them later. cacheDir = _add_cache_dir_t(cache, parentDir, dirName); while ((de = readdir(dir))) { const char *name = de->d_name; if (de->d_type == DT_DIR) { int subfd; DIR *subdir; /* always skip "." and ".." */ if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); if (subfd < 0) { ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); continue; } subdir = fdopendir(subfd); if (subdir == NULL) { ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(subfd); continue; } if (cacheDir == NULL) { cacheDir = _add_cache_dir_t(cache, parentDir, dirName); } if (cacheDir != NULL) { // Update pathBase for the new path... this may change dirName // if that is also pointing to the path, but we are done with it // now. size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name); CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase)); if (finallen < pathAvailLen) { _add_cache_files(cache, cacheDir, name, subdir, pathBase, pathPos+finallen, pathAvailLen-finallen); } else { // Whoops, the final path is too long! We'll just delete // this directory. ALOGW("Cache dir %s truncated in path %s; deleting dir\n", name, pathBase); _delete_dir_contents(subdir, NULL); if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); } } } closedir(subdir); } else if (de->d_type == DT_REG) { // Skip files that start with '.'; they will be deleted if // their entire directory is deleted. This allows for metadata // like ".nomedia" to remain in the directory until the entire // directory is deleted. if (cacheDir == NULL) { cacheDir = _add_cache_dir_t(cache, parentDir, dirName); } if (name[0] == '.') { cacheDir->hiddenCount++; continue; } if (cacheDir != NULL) { // Build final full path for file... this may change dirName // if that is also pointing to the path, but we are done with it // now. size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name); CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase)); if (finallen < pathAvailLen) { struct stat s; if (stat(pathBase, &s) >= 0) { _add_cache_file_t(cache, cacheDir, s.st_mtime, name); } else { ALOGW("Unable to stat cache file %s; deleting\n", pathBase); if (unlink(pathBase) < 0) { ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno)); } } } else { // Whoops, the final path is too long! We'll just delete // this file. ALOGW("Cache file %s truncated in path %s; deleting\n", name, pathBase); if (unlinkat(dfd, name, 0) < 0) { *pathPos = 0; ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase, strerror(errno)); } } } } else { cacheDir->hiddenCount++; } } return 0; } void add_cache_files(cache_t* cache, const std::string& data_path) { DIR *d; struct dirent *de; char dirname[PATH_MAX]; const char* basepath = data_path.c_str(); CACHE_NOISY(ALOGI("add_cache_files: basepath=%s\n", basepath)); d = opendir(basepath); if (d == NULL) { return; } while ((de = readdir(d))) { if (de->d_type == DT_DIR) { DIR* subdir; const char *name = de->d_name; char* pathpos; /* always skip "." and ".." */ if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } strcpy(dirname, basepath); pathpos = dirname + strlen(dirname); if ((*(pathpos-1)) != '/') { *pathpos = '/'; pathpos++; *pathpos = 0; } // TODO: also try searching using xattr when CE is locked snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/cache", name); CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname)); subdir = opendir(dirname); if (subdir != NULL) { size_t dirnameLen = strlen(dirname); _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen, PATH_MAX - dirnameLen); closedir(subdir); } } } closedir(d); } static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir) { char *pos = path; if (dir->parent != NULL) { pos = create_dir_path(path, dir->parent); } // Note that we don't need to worry about going beyond the buffer, // since when we were constructing the cache entries our maximum // buffer size for full paths was PATH_MAX. strcpy(pos, dir->name); pos += strlen(pos); *pos = '/'; pos++; *pos = 0; return pos; } static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir) { if (dir->parent != NULL) { create_dir_path(path, dir); ALOGI("DEL DIR %s\n", path); if (dir->hiddenCount <= 0) { if (rmdir(path)) { ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno)); return; } } else { // The directory contains hidden files so we need to delete // them along with the directory itself. if (delete_dir_contents(path, 1, NULL)) { return; } } dir->parent->childCount--; dir->deleted = 1; if (dir->parent->childCount <= 0) { delete_cache_dir(path, dir->parent); } } else if (dir->hiddenCount > 0) { // This is a root directory, but it has hidden files. Get rid of // all of those files, but not the directory itself. create_dir_path(path, dir); ALOGI("DEL CONTENTS %s\n", path); delete_dir_contents(path, 0, NULL); } } static int cache_modtime_sort(const void *lhsP, const void *rhsP) { const cache_file_t *lhs = *(const cache_file_t**)lhsP; const cache_file_t *rhs = *(const cache_file_t**)rhsP; return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0); } void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size) { size_t i; int skip = 0; char path[PATH_MAX]; ALOGI("Collected cache files: %zd directories, %zd files", cache->numDirs, cache->numFiles); CACHE_NOISY(ALOGI("Sorting files...")); qsort(cache->files, cache->numFiles, sizeof(cache_file_t*), cache_modtime_sort); CACHE_NOISY(ALOGI("Cleaning empty directories...")); for (i=cache->numDirs; i>0; i--) { cache_dir_t* dir = cache->dirs[i-1]; if (dir->childCount <= 0 && !dir->deleted) { delete_cache_dir(path, dir); } } CACHE_NOISY(ALOGI("Trimming files...")); for (i=0; inumFiles; i++) { skip++; if (skip > 10) { if (data_disk_free(data_path) > free_size) { return; } skip = 0; } cache_file_t* file = cache->files[i]; strcpy(create_dir_path(path, file->dir), file->name); ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path); if (unlink(path) < 0) { ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno)); } file->dir->childCount--; if (file->dir->childCount <= 0) { delete_cache_dir(path, file->dir); } } } void finish_cache_collection(cache_t* cache) { CACHE_NOISY(size_t i;) CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles)); CACHE_NOISY( for (i=0; inumDirs; i++) { cache_dir_t* dir = cache->dirs[i]; ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent); }) CACHE_NOISY( for (i=0; inumFiles; i++) { cache_file_t* file = cache->files[i]; ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name, (int)file->modTime, file->dir); }) void* block = cache->memBlocks; while (block != NULL) { void* nextBlock = *(void**)block; CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block)); free(block); block = nextBlock; } free(cache); } /** * Validate that the path is valid in the context of the provided directory. * The path is allowed to have at most one subdirectory and no indirections * to top level directories (i.e. have ".."). */ static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) { size_t dir_len = dir->len; const char* subdir = strchr(path + dir_len, '/'); // Only allow the path to have at most one subdirectory. if (subdir != NULL) { ++subdir; if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) { ALOGE("invalid apk path '%s' (subdir?)\n", path); return -1; } } // Directories can't have a period directly after the directory markers to prevent "..". if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) { ALOGE("invalid apk path '%s' (trickery)\n", path); return -1; } return 0; } /** * Checks whether a path points to a system app (.apk file). Returns 0 * if it is a system app or -1 if it is not. */ int validate_system_app_path(const char* path) { size_t i; for (i = 0; i < android_system_dirs.count; i++) { const size_t dir_len = android_system_dirs.dirs[i].len; if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) { return validate_path(android_system_dirs.dirs + i, path, 1); } } return -1; } /** * Get the contents of a environment variable that contains a path. Caller * owns the string that is inserted into the directory record. Returns * 0 on success and -1 on error. */ int get_path_from_env(dir_rec_t* rec, const char* var) { const char* path = getenv(var); int ret = get_path_from_string(rec, path); if (ret < 0) { ALOGW("Problem finding value for environment variable %s\n", var); } return ret; } /** * Puts the string into the record as a directory. Appends '/' to the end * of all paths. Caller owns the string that is inserted into the directory * record. A null value will result in an error. * * Returns 0 on success and -1 on error. */ int get_path_from_string(dir_rec_t* rec, const char* path) { if (path == NULL) { return -1; } else { const size_t path_len = strlen(path); if (path_len <= 0) { return -1; } // Make sure path is absolute. if (path[0] != '/') { return -1; } if (path[path_len - 1] == '/') { // Path ends with a forward slash. Make our own copy. rec->path = strdup(path); if (rec->path == NULL) { return -1; } rec->len = path_len; } else { // Path does not end with a slash. Generate a new string. char *dst; // Add space for slash and terminating null. size_t dst_size = path_len + 2; rec->path = (char*) malloc(dst_size); if (rec->path == NULL) { return -1; } dst = rec->path; if (append_and_increment(&dst, path, &dst_size) < 0 || append_and_increment(&dst, "/", &dst_size)) { ALOGE("Error canonicalizing path"); return -1; } rec->len = dst - rec->path; } } return 0; } int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { dst->len = src->len + strlen(suffix); const size_t dstSize = dst->len + 1; dst->path = (char*) malloc(dstSize); if (dst->path == NULL || snprintf(dst->path, dstSize, "%s%s", src->path, suffix) != (ssize_t) dst->len) { ALOGE("Could not allocate memory to hold appended path; aborting\n"); return -1; } return 0; } /** * Check whether path points to a valid path for an APK file. The path must * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within * that path. Returns -1 when an invalid path is encountered and 0 when a valid path * is encountered. */ static int validate_apk_path_internal(const char *path, int maxSubdirs) { const dir_rec_t* dir = NULL; if (!strncmp(path, android_app_dir.path, android_app_dir.len)) { dir = &android_app_dir; } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) { dir = &android_app_private_dir; } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) { dir = &android_app_ephemeral_dir; } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) { dir = &android_asec_dir; } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) { dir = &android_mnt_expand_dir; if (maxSubdirs < 2) { maxSubdirs = 2; } } else { return -1; } return validate_path(dir, path, maxSubdirs); } int validate_apk_path(const char* path) { return validate_apk_path_internal(path, 1 /* maxSubdirs */); } int validate_apk_path_subdirs(const char* path) { return validate_apk_path_internal(path, 3 /* maxSubdirs */); } int append_and_increment(char** dst, const char* src, size_t* dst_size) { ssize_t ret = strlcpy(*dst, src, *dst_size); if (ret < 0 || (size_t) ret >= *dst_size) { return -1; } *dst += ret; *dst_size -= ret; return 0; } char *build_string2(const char *s1, const char *s2) { if (s1 == NULL || s2 == NULL) return NULL; int len_s1 = strlen(s1); int len_s2 = strlen(s2); int len = len_s1 + len_s2 + 1; char *result = (char *) malloc(len); if (result == NULL) return NULL; strcpy(result, s1); strcpy(result + len_s1, s2); return result; } char *build_string3(const char *s1, const char *s2, const char *s3) { if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL; int len_s1 = strlen(s1); int len_s2 = strlen(s2); int len_s3 = strlen(s3); int len = len_s1 + len_s2 + len_s3 + 1; char *result = (char *) malloc(len); if (result == NULL) return NULL; strcpy(result, s1); strcpy(result + len_s1, s2); strcpy(result + len_s1 + len_s2, s3); return result; } int ensure_config_user_dirs(userid_t userid) { // writable by system, readable by any app within the same user const int uid = multiuser_get_uid(userid, AID_SYSTEM); const int gid = multiuser_get_uid(userid, AID_EVERYBODY); // Ensure /data/misc/user/ exists auto path = create_data_misc_legacy_path(userid); return fs_prepare_dir(path.c_str(), 0750, uid, gid); } int wait_child(pid_t pid) { int status; pid_t got_pid; while (1) { got_pid = waitpid(pid, &status, 0); if (got_pid == -1 && errno == EINTR) { printf("waitpid interrupted, retrying\n"); } else { break; } } if (got_pid != pid) { ALOGW("waitpid failed: wanted %d, got %d: %s\n", (int) pid, (int) got_pid, strerror(errno)); return 1; } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { return 0; } else { return status; /* always nonzero */ } } } // namespace installd } // namespace android cmds/installd/utils.h0100644 0000000 0000000 00000011007 13077405420 013657 0ustar000000000 0000000 /* ** ** Copyright 2008, 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 UTILS_H_ #define UTILS_H_ #include #include #include #include #include #include #include #include namespace android { namespace installd { struct dir_rec_t; typedef struct cache_dir_struct { struct cache_dir_struct* parent; int32_t childCount; int32_t hiddenCount; int32_t deleted; char name[]; } cache_dir_t; typedef struct { cache_dir_t* dir; time_t modTime; char name[]; } cache_file_t; typedef struct { size_t numDirs; size_t availDirs; cache_dir_t** dirs; size_t numFiles; size_t availFiles; cache_file_t** files; size_t numCollected; void* memBlocks; int8_t* curMemBlockAvail; int8_t* curMemBlockEnd; } cache_t; int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, const char *postfix, userid_t userid); std::string create_data_path(const char* volume_uuid); std::string create_data_app_path(const char* volume_uuid); std::string create_data_app_package_path(const char* volume_uuid, const char* package_name); std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid); std::string create_data_user_de_path(const char* volume_uuid, userid_t userid); std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user, const char* package_name); std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user, const char* package_name, ino_t ce_data_inode); std::string create_data_user_de_package_path(const char* volume_uuid, userid_t user, const char* package_name); std::string create_data_media_path(const char* volume_uuid, userid_t userid); std::string create_data_misc_legacy_path(userid_t userid); std::string create_data_user_profiles_path(userid_t userid); std::string create_data_user_profile_package_path(userid_t user, const char* package_name); std::string create_data_ref_profile_package_path(const char* package_name); std::vector get_known_users(const char* volume_uuid); int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); int create_move_path(char path[PKG_PATH_MAX], const char* pkgname, const char* leaf, userid_t userid); int is_valid_package_name(const char* pkgname); int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false); int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false); int delete_dir_contents(const char *pathname, int also_delete_dir, int (*exclusion_predicate)(const char *name, const int is_dir), bool ignore_if_missing = false); int delete_dir_contents_fd(int dfd, const char *name); int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t group); int64_t data_disk_free(const std::string& data_path); cache_t* start_cache_collection(); void add_cache_files(cache_t* cache, const std::string& data_path); void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size); void finish_cache_collection(cache_t* cache); int validate_system_app_path(const char* path); int get_path_from_env(dir_rec_t* rec, const char* var); int get_path_from_string(dir_rec_t* rec, const char* path); int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix); int validate_apk_path(const char *path); int validate_apk_path_subdirs(const char *path); int append_and_increment(char** dst, const char* src, size_t* dst_size); char *build_string2(const char *s1, const char *s2); char *build_string3(const char *s1, const char *s2, const char *s3); int ensure_config_user_dirs(userid_t userid); int wait_child(pid_t pid); } // namespace installd } // namespace android #endif // UTILS_H_ cmds/ip-up-vpn/0040755 0000000 0000000 00000000000 13077405420 012373 5ustar000000000 0000000 cmds/ip-up-vpn/Android.mk0100644 0000000 0000000 00000001533 13077405420 014303 0ustar000000000 0000000 # # 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. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := ip-up-vpn.c LOCAL_SHARED_LIBRARIES := libcutils liblog LOCAL_MODULE := ip-up-vpn LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) cmds/ip-up-vpn/ip-up-vpn.c0100644 0000000 0000000 00000010471 13077405420 014372 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "ip-up-vpn" #include #define DIR "/data/misc/vpn/" static const char *env(const char *name) { const char *value = getenv(name); return value ? value : ""; } static int set_address(struct sockaddr *sa, const char *address) { sa->sa_family = AF_INET; errno = EINVAL; return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr); } /* * The primary goal is to create a file with VPN parameters. Currently they * are interface, addresses, routes, DNS servers, and search domains and VPN * server address. Each parameter occupies one line in the file, and it can be * an empty string or space-separated values. The order and the format must be * consistent with com.android.server.connectivity.Vpn. Here is an example. * * ppp0 * 192.168.1.100/24 * 0.0.0.0/0 * 192.168.1.1 192.168.1.2 * example.org * 192.0.2.1 * * The secondary goal is to unify the outcome of VPN. The current baseline * is to have an interface configured with the given address and netmask * and maybe add a host route to protect the tunnel. PPP-based VPN already * does this, but others might not. Routes, DNS servers, and search domains * are handled by the framework since they can be overridden by the users. */ int main(int argc, char **argv) { FILE *state = fopen(DIR ".tmp", "wb"); if (!state) { ALOGE("Cannot create state: %s", strerror(errno)); return 1; } if (argc >= 6) { /* Invoked by pppd. */ fprintf(state, "%s\n", argv[1]); fprintf(state, "%s/32\n", argv[4]); fprintf(state, "0.0.0.0/0\n"); fprintf(state, "%s %s\n", env("DNS1"), env("DNS2")); fprintf(state, "\n"); fprintf(state, "\n"); } else if (argc == 2) { /* Invoked by racoon. */ const char *interface = env("INTERFACE"); const char *address = env("INTERNAL_ADDR4"); const char *routes = env("SPLIT_INCLUDE_CIDR"); int s = socket(AF_INET, SOCK_DGRAM, 0); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); /* Bring up the interface. */ ifr.ifr_flags = IFF_UP; strncpy(ifr.ifr_name, interface, IFNAMSIZ); if (ioctl(s, SIOCSIFFLAGS, &ifr)) { ALOGE("Cannot bring up %s: %s", interface, strerror(errno)); return 1; } /* Set the address. */ if (!set_address(&ifr.ifr_addr, address) || ioctl(s, SIOCSIFADDR, &ifr)) { ALOGE("Cannot set address: %s", strerror(errno)); return 1; } /* Set the netmask. */ if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) { if (ioctl(s, SIOCSIFNETMASK, &ifr)) { ALOGE("Cannot set netmask: %s", strerror(errno)); return 1; } } /* TODO: Send few packets to trigger phase 2? */ fprintf(state, "%s\n", interface); fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4")); fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0"); fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST")); fprintf(state, "%s\n", env("DEFAULT_DOMAIN")); fprintf(state, "%s\n", env("REMOTE_ADDR")); } else { ALOGE("Cannot parse parameters"); return 1; } fclose(state); if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) { ALOGE("Cannot write state: %s", strerror(errno)); return 1; } return 0; } cmds/rawbu/0040755 0000000 0000000 00000000000 13077405420 011660 5ustar000000000 0000000 cmds/rawbu/Android.mk0100644 0000000 0000000 00000000463 13077405420 013571 0ustar000000000 0000000 # Copyright 2009 The Android Open Source Project LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= backup.cpp LOCAL_SHARED_LIBRARIES := libcutils libc LOCAL_MODULE:= rawbu LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE) cmds/rawbu/NOTICE0100644 0000000 0000000 00000024707 13077405420 012573 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS cmds/rawbu/backup.cpp0100644 0000000 0000000 00000051376 13077405420 013642 0ustar000000000 0000000 // Copyright 2009 The Android Open Source Project #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 4096 #endif // First version. #define FILE_VERSION_1 0xffff0001 // Introduces backup all option to header. #define FILE_VERSION_2 0xffff0002 #define FILE_VERSION FILE_VERSION_2 namespace android { static char nameBuffer[PATH_MAX]; static struct stat statBuffer; static char copyBuffer[8192]; static char *backupFilePath = NULL; static uint32_t inputFileVersion; static int opt_backupAll; #define SPECIAL_NO_TOUCH 0 #define SPECIAL_NO_BACKUP 1 struct special_dir { const char* path; int type; }; /* Directory paths that we will not backup/restore */ static const struct special_dir SKIP_PATHS[] = { { "/data/misc", SPECIAL_NO_TOUCH }, { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH }, { "/data/system/location", SPECIAL_NO_TOUCH }, { "/data/dalvik-cache", SPECIAL_NO_BACKUP }, { NULL, 0 }, }; /* This is just copied from the shell's built-in wipe command. */ static int wipe (const char *path) { DIR *dir; struct dirent *de; int ret; int i; dir = opendir(path); if (dir == NULL) { fprintf (stderr, "Error opendir'ing %s: %s\n", path, strerror(errno)); return 0; } char *filenameOffset; strcpy(nameBuffer, path); strcat(nameBuffer, "/"); filenameOffset = nameBuffer + strlen(nameBuffer); for (;;) { de = readdir(dir); if (de == NULL) { break; } if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, "..") || 0 == strcmp(de->d_name, "lost+found") ) { continue; } strcpy(filenameOffset, de->d_name); bool noBackup = false; /* See if this is a path we should skip. */ for (i = 0; SKIP_PATHS[i].path; i++) { if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) { if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) { // In this case we didn't back up the directory -- // we do want to wipe its contents, but not the // directory itself, since the restore file won't // contain the directory. noBackup = true; } break; } } if (!noBackup && SKIP_PATHS[i].path != NULL) { // This is a SPECIAL_NO_TOUCH directory. continue; } ret = lstat (nameBuffer, &statBuffer); if (ret != 0) { fprintf(stderr, "warning -- stat() error on '%s': %s\n", nameBuffer, strerror(errno)); continue; } if(S_ISDIR(statBuffer.st_mode)) { int i; char *newpath; newpath = strdup(nameBuffer); if (wipe(newpath) == 0) { free(newpath); closedir(dir); return 0; } if (!noBackup) { ret = rmdir(newpath); if (ret != 0) { fprintf(stderr, "warning -- rmdir() error on '%s': %s\n", newpath, strerror(errno)); } } free(newpath); strcpy(nameBuffer, path); strcat(nameBuffer, "/"); } else { // Don't delete the backup file if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) { continue; } ret = unlink(nameBuffer); if (ret != 0) { fprintf(stderr, "warning -- unlink() error on '%s': %s\n", nameBuffer, strerror(errno)); } } } closedir(dir); return 1; } static int write_int32(FILE* fh, int32_t val) { int res = fwrite(&val, 1, sizeof(val), fh); if (res != sizeof(val)) { fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno)); return 0; } return 1; } static int write_int64(FILE* fh, int64_t val) { int res = fwrite(&val, 1, sizeof(val), fh); if (res != sizeof(val)) { fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno)); return 0; } return 1; } static int copy_file(FILE* dest, FILE* src, off_t size, const char* destName, const char* srcName) { errno = 0; off_t origSize = size; while (size > 0) { int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size; int readLen = fread(copyBuffer, 1, amt, src); if (readLen <= 0) { if (srcName != NULL) { fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n", amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF"); } else { fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n", amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF"); } return 0; } int writeLen = fwrite(copyBuffer, 1, readLen, dest); if (writeLen != readLen) { if (destName != NULL) { fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n", writeLen, readLen, destName, strerror(errno)); } else { fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n", writeLen, readLen, strerror(errno)); } return 0; } size -= readLen; } return 1; } #define TYPE_END 0 #define TYPE_DIR 1 #define TYPE_FILE 2 static int write_header(FILE* fh, int type, const char* path, const struct stat* st) { int pathLen = strlen(path); if (!write_int32(fh, type)) return 0; if (!write_int32(fh, pathLen)) return 0; if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) { fprintf(stderr, "unable to write: %s\n", strerror(errno)); return 0; } if (!write_int32(fh, st->st_uid)) return 0; if (!write_int32(fh, st->st_gid)) return 0; if (!write_int32(fh, st->st_mode)) return 0; if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0; if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0; if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0; return 1; } static int backup_dir(FILE* fh, const char* srcPath) { DIR *dir; struct dirent *de; char* fullPath = NULL; int srcLen = strlen(srcPath); int result = 1; int i; dir = opendir(srcPath); if (dir == NULL) { fprintf (stderr, "error opendir'ing '%s': %s\n", srcPath, strerror(errno)); return 0; } for (;;) { de = readdir(dir); if (de == NULL) { break; } if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, "..") || 0 == strcmp(de->d_name, "lost+found") ) { continue; } if (fullPath != NULL) { free(fullPath); } fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2); strcpy(fullPath, srcPath); fullPath[srcLen] = '/'; strcpy(fullPath+srcLen+1, de->d_name); /* See if this is a path we should skip. */ if (!opt_backupAll) { for (i = 0; SKIP_PATHS[i].path; i++) { if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) { break; } } if (SKIP_PATHS[i].path != NULL) { continue; } } int ret = lstat(fullPath, &statBuffer); if (ret != 0) { fprintf(stderr, "stat() error on '%s': %s\n", fullPath, strerror(errno)); result = 0; goto done; } if(S_ISDIR(statBuffer.st_mode)) { printf("Saving dir %s...\n", fullPath); if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) { result = 0; goto done; } if (backup_dir(fh, fullPath) == 0) { result = 0; goto done; } } else if (S_ISREG(statBuffer.st_mode)) { // Skip the backup file if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) { printf("Skipping backup file %s...\n", backupFilePath); continue; } else { printf("Saving file %s...\n", fullPath); } if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) { result = 0; goto done; } off_t size = statBuffer.st_size; if (!write_int64(fh, size)) { result = 0; goto done; } FILE* src = fopen(fullPath, "r"); if (src == NULL) { fprintf(stderr, "unable to open source file '%s': %s\n", fullPath, strerror(errno)); result = 0; goto done; } int copyres = copy_file(fh, src, size, NULL, fullPath); fclose(src); if (!copyres) { result = 0; goto done; } } } done: if (fullPath != NULL) { free(fullPath); } closedir(dir); return result; } static int backup_data(const char* destPath) { int res = -1; FILE* fh = fopen(destPath, "w"); if (fh == NULL) { fprintf(stderr, "unable to open destination '%s': %s\n", destPath, strerror(errno)); return -1; } printf("Backing up /data to %s...\n", destPath); // The path that shouldn't be backed up backupFilePath = strdup(destPath); if (!write_int32(fh, FILE_VERSION)) goto done; if (!write_int32(fh, opt_backupAll)) goto done; if (!backup_dir(fh, "/data")) goto done; if (!write_int32(fh, 0)) goto done; res = 0; done: if (fflush(fh) != 0) { fprintf(stderr, "error flushing destination '%s': %s\n", destPath, strerror(errno)); res = -1; goto donedone; } if (fsync(fileno(fh)) != 0) { fprintf(stderr, "error syncing destination '%s': %s\n", destPath, strerror(errno)); res = -1; goto donedone; } fclose(fh); sync(); donedone: return res; } static int32_t read_int32(FILE* fh, int32_t defVal) { int32_t val; if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { fprintf(stderr, "unable to read: %s\n", strerror(errno)); return defVal; } return val; } static int64_t read_int64(FILE* fh, int64_t defVal) { int64_t val; if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { fprintf(stderr, "unable to read: %s\n", strerror(errno)); return defVal; } return val; } static int read_header(FILE* fh, int* type, char** path, struct stat* st) { *type = read_int32(fh, -1); if (*type == TYPE_END) { return 1; } if (*type < 0) { fprintf(stderr, "bad token %d in restore file\n", *type); return 0; } int32_t pathLen = read_int32(fh, -1); if (pathLen <= 0) { fprintf(stderr, "bad path length %d in restore file\n", pathLen); return 0; } char* readPath = (char*)malloc(pathLen+1); if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) { fprintf(stderr, "truncated path in restore file\n"); free(readPath); return 0; } readPath[pathLen] = 0; *path = readPath; st->st_uid = read_int32(fh, -1); if (st->st_uid == (uid_t)-1) { fprintf(stderr, "bad uid in restore file at '%s'\n", readPath); return 0; } st->st_gid = read_int32(fh, -1); if (st->st_gid == (gid_t)-1) { fprintf(stderr, "bad gid in restore file at '%s'\n", readPath); return 0; } st->st_mode = read_int32(fh, -1); if (st->st_mode == (mode_t)-1) { fprintf(stderr, "bad mode in restore file at '%s'\n", readPath); return 0; } int64_t ltime = read_int64(fh, -1); if (ltime < 0) { fprintf(stderr, "bad atime in restore file at '%s'\n", readPath); return 0; } st->st_atime = (time_t)(ltime/1000/1000/1000); ltime = read_int64(fh, -1); if (ltime < 0) { fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath); return 0; } st->st_mtime = (time_t)(ltime/1000/1000/1000); ltime = read_int64(fh, -1); if (ltime < 0) { fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath); return 0; } st->st_ctime = (time_t)(ltime/1000/1000/1000); st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO); return 1; } static int restore_data(const char* srcPath) { int res = -1; FILE* fh = fopen(srcPath, "r"); if (fh == NULL) { fprintf(stderr, "Unable to open source '%s': %s\n", srcPath, strerror(errno)); return -1; } inputFileVersion = read_int32(fh, 0); if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) { fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion); goto done; } if (inputFileVersion >= FILE_VERSION_2) { opt_backupAll = read_int32(fh, 0); } else { opt_backupAll = 0; } // The path that shouldn't be deleted backupFilePath = strdup(srcPath); printf("Wiping contents of /data...\n"); if (!wipe("/data")) { goto done; } printf("Restoring from %s to /data...\n", srcPath); while (1) { int type; char* path = NULL; if (read_header(fh, &type, &path, &statBuffer) == 0) { goto done; } if (type == 0) { break; } const char* typeName = "?"; if (type == TYPE_DIR) { typeName = "dir"; printf("Restoring dir %s...\n", path); if (mkdir(path, statBuffer.st_mode) != 0) { if (errno != EEXIST) { fprintf(stderr, "unable to create directory '%s': %s\n", path, strerror(errno)); free(path); goto done; } } } else if (type == TYPE_FILE) { typeName = "file"; off_t size = read_int64(fh, -1); if (size < 0) { fprintf(stderr, "bad file size %ld in restore file\n", size); free(path); goto done; } printf("Restoring file %s...\n", path); FILE* dest = fopen(path, "w"); if (dest == NULL) { fprintf(stderr, "unable to open destination file '%s': %s\n", path, strerror(errno)); free(path); goto done; } int copyres = copy_file(dest, fh, size, path, NULL); fclose(dest); if (!copyres) { free(path); goto done; } } else { fprintf(stderr, "unknown node type %d\n", type); goto done; } // Do this even for directories, since the dir may have already existed // so we need to make sure it gets the correct mode. if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) { fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n", typeName, path, statBuffer.st_mode, strerror(errno)); free(path); goto done; } if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) { fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n", typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno)); free(path); goto done; } struct utimbuf timbuf; timbuf.actime = statBuffer.st_atime; timbuf.modtime = statBuffer.st_mtime; if (utime(path, &timbuf) != 0) { fprintf(stderr, "unable to utime destination %s '%s': %s\n", typeName, path, strerror(errno)); free(path); goto done; } free(path); } res = 0; done: fclose(fh); return res; } static void show_help(const char *cmd) { fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd); fprintf(stderr, "commands are:\n" " help Show this help text.\n" " backup Perform a backup of /data.\n" " restore Perform a restore of /data.\n"); fprintf(stderr, "options include:\n" " -h Show this help text.\n" " -a Backup all files.\n"); fprintf(stderr, "\n backup-file-path Defaults to /sdcard/backup.dat .\n" " On devices that emulate the sdcard, you will need to\n" " explicitly specify the directory it is mapped to,\n" " to avoid recursive backup or deletion of the backup file\n" " during restore.\n\n" " Eg. /data/media/0/backup.dat\n"); fprintf(stderr, "\nThe %s command allows you to perform low-level\n" "backup and restore of the /data partition. This is\n" "where all user data is kept, allowing for a fairly\n" "complete restore of a device's state. Note that\n" "because this is low-level, it will only work across\n" "builds of the same (or very similar) device software.\n", cmd); } } /* namespace android */ int main (int argc, char **argv) { int restore = 0; if (getuid() != AID_ROOT) { fprintf(stderr, "error -- %s must run as root\n", argv[0]); exit(-1); } if (argc < 2) { fprintf(stderr, "No command specified.\n"); android::show_help(argv[0]); exit(-1); } if (0 == strcmp(argv[1], "restore")) { restore = 1; } else if (0 == strcmp(argv[1], "help")) { android::show_help(argv[0]); exit(0); } else if (0 != strcmp(argv[1], "backup")) { fprintf(stderr, "Unknown command: %s\n", argv[1]); android::show_help(argv[0]); exit(-1); } android::opt_backupAll = 0; optind = 2; for (;;) { int ret; ret = getopt(argc, argv, "ah"); if (ret < 0) { break; } switch(ret) { case 'a': android::opt_backupAll = 1; if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n"); break; case 'h': android::show_help(argv[0]); exit(0); break; default: fprintf(stderr,"Unrecognized Option\n"); android::show_help(argv[0]); exit(-1); break; } } const char* backupFile = "/sdcard/backup.dat"; if (argc > optind) { backupFile = argv[optind]; optind++; if (argc != optind) { fprintf(stderr, "Too many arguments\n"); android::show_help(argv[0]); exit(-1); } } printf("Stopping system...\n"); property_set("ctl.stop", "runtime"); property_set("ctl.stop", "zygote"); sleep(1); int res; if (restore) { res = android::restore_data(backupFile); if (res != 0) { // Don't restart system, since the data partition is hosed. return res; } printf("Restore complete! Restarting system, cross your fingers...\n"); } else { res = android::backup_data(backupFile); if (res == 0) { printf("Backup complete! Restarting system...\n"); } else { printf("Restarting system...\n"); } } property_set("ctl.start", "zygote"); property_set("ctl.start", "runtime"); } cmds/service/0040755 0000000 0000000 00000000000 13077405420 012200 5ustar000000000 0000000 cmds/service/Android.mk0100644 0000000 0000000 00000000425 13077405420 014107 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ service.cpp LOCAL_SHARED_LIBRARIES := libutils libbinder ifeq ($(TARGET_OS),linux) LOCAL_CFLAGS += -DXP_UNIX #LOCAL_SHARED_LIBRARIES += librt endif LOCAL_MODULE:= service include $(BUILD_EXECUTABLE) cmds/service/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 015320 0ustar000000000 0000000 cmds/service/NOTICE0100644 0000000 0000000 00000024707 13077405420 013113 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS cmds/service/service.cpp0100644 0000000 0000000 00000030226 13077405420 014344 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include #include #include #include #include #include #include using namespace android; void writeString16(Parcel& parcel, const char* string) { if (string != NULL) { parcel.writeString16(String16(string)); } else { parcel.writeInt32(-1); } } // get the name of the generic interface we hold a reference to static String16 get_interface_name(sp service) { if (service != NULL) { Parcel data, reply; status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply); if (err == NO_ERROR) { return reply.readString16(); } } return String16(); } static String8 good_old_string(const String16& src) { String8 name8; char ch8[2]; ch8[1] = 0; for (unsigned j = 0; j < src.size(); j++) { char16_t ch = src[j]; if (ch < 128) ch8[0] = (char)ch; name8.append(ch8); } return name8; } int main(int argc, char* const argv[]) { sp sm = defaultServiceManager(); fflush(stdout); if (sm == NULL) { aerr << "service: Unable to get default service manager!" << endl; return 20; } bool wantsUsage = false; int result = 0; while (1) { int ic = getopt(argc, argv, "h?"); if (ic < 0) break; switch (ic) { case 'h': case '?': wantsUsage = true; break; default: aerr << "service: Unknown option -" << ic << endl; wantsUsage = true; result = 10; break; } } if (optind >= argc) { wantsUsage = true; } else if (!wantsUsage) { if (strcmp(argv[optind], "check") == 0) { optind++; if (optind < argc) { sp service = sm->checkService(String16(argv[optind])); aout << "Service " << argv[optind] << (service == NULL ? ": not found" : ": found") << endl; } else { aerr << "service: No service specified for check" << endl; wantsUsage = true; result = 10; } } else if (strcmp(argv[optind], "list") == 0) { Vector services = sm->listServices(); aout << "Found " << services.size() << " services:" << endl; for (unsigned i = 0; i < services.size(); i++) { String16 name = services[i]; sp service = sm->checkService(name); aout << i << "\t" << good_old_string(name) << ": [" << good_old_string(get_interface_name(service)) << "]" << endl; } } else if (strcmp(argv[optind], "call") == 0) { optind++; if (optind+1 < argc) { int serviceArg = optind; sp service = sm->checkService(String16(argv[optind++])); String16 ifName = get_interface_name(service); int32_t code = atoi(argv[optind++]); if (service != NULL && ifName.size() > 0) { Parcel data, reply; // the interface name is first data.writeInterfaceToken(ifName); // then the rest of the call arguments while (optind < argc) { if (strcmp(argv[optind], "i32") == 0) { optind++; if (optind >= argc) { aerr << "service: no integer supplied for 'i32'" << endl; wantsUsage = true; result = 10; break; } data.writeInt32(atoi(argv[optind++])); } else if (strcmp(argv[optind], "i64") == 0) { optind++; if (optind >= argc) { aerr << "service: no integer supplied for 'i64'" << endl; wantsUsage = true; result = 10; break; } data.writeInt64(atoll(argv[optind++])); } else if (strcmp(argv[optind], "s16") == 0) { optind++; if (optind >= argc) { aerr << "service: no string supplied for 's16'" << endl; wantsUsage = true; result = 10; break; } data.writeString16(String16(argv[optind++])); } else if (strcmp(argv[optind], "f") == 0) { optind++; if (optind >= argc) { aerr << "service: no number supplied for 'f'" << endl; wantsUsage = true; result = 10; break; } data.writeFloat(atof(argv[optind++])); } else if (strcmp(argv[optind], "d") == 0) { optind++; if (optind >= argc) { aerr << "service: no number supplied for 'd'" << endl; wantsUsage = true; result = 10; break; } data.writeDouble(atof(argv[optind++])); } else if (strcmp(argv[optind], "null") == 0) { optind++; data.writeStrongBinder(NULL); } else if (strcmp(argv[optind], "intent") == 0) { char* action = NULL; char* dataArg = NULL; char* type = NULL; int launchFlags = 0; char* component = NULL; int categoryCount = 0; char* categories[16]; char* context1 = NULL; optind++; while (optind < argc) { char* key = strtok_r(argv[optind], "=", &context1); char* value = strtok_r(NULL, "=", &context1); // we have reached the end of the XXX=XXX args. if (key == NULL) break; if (strcmp(key, "action") == 0) { action = value; } else if (strcmp(key, "data") == 0) { dataArg = value; } else if (strcmp(key, "type") == 0) { type = value; } else if (strcmp(key, "launchFlags") == 0) { launchFlags = atoi(value); } else if (strcmp(key, "component") == 0) { component = value; } else if (strcmp(key, "categories") == 0) { char* context2 = NULL; int categoryCount = 0; categories[categoryCount] = strtok_r(value, ",", &context2); while (categories[categoryCount] != NULL) { categoryCount++; categories[categoryCount] = strtok_r(NULL, ",", &context2); } } optind++; } writeString16(data, action); writeString16(data, dataArg); writeString16(data, type); data.writeInt32(launchFlags); writeString16(data, component); if (categoryCount > 0) { data.writeInt32(categoryCount); for (int i = 0 ; i < categoryCount ; i++) { writeString16(data, categories[i]); } } else { data.writeInt32(0); } // for now just set the extra field to be null. data.writeInt32(-1); } else { aerr << "service: unknown option " << argv[optind] << endl; wantsUsage = true; result = 10; break; } } service->transact(code, data, &reply); aout << "Result: " << reply << endl; } else { aerr << "service: Service " << argv[serviceArg] << " does not exist" << endl; result = 10; } } else { if (optind < argc) { aerr << "service: No service specified for call" << endl; } else { aerr << "service: No code specified for call" << endl; } wantsUsage = true; result = 10; } } else { aerr << "service: Unknown command " << argv[optind] << endl; wantsUsage = true; result = 10; } } if (wantsUsage) { aout << "Usage: service [-h|-?]\n" " service list\n" " service check SERVICE\n" " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" "Options:\n" " i32: Write the 32-bit integer N into the send parcel.\n" " i64: Write the 64-bit integer N into the send parcel.\n" " f: Write the 32-bit single-precision number N into the send parcel.\n" " d: Write the 64-bit double-precision number N into the send parcel.\n" " s16: Write the UTF-16 string STR into the send parcel.\n"; // " intent: Write and Intent int the send parcel. ARGS can be\n" // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; return result; } return result; } cmds/servicemanager/0040755 0000000 0000000 00000000000 13077405420 013533 5ustar000000000 0000000 cmds/servicemanager/Android.mk0100644 0000000 0000000 00000001207 13077405420 015441 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) svc_c_flags = \ -Wall -Wextra -Werror \ ifneq ($(TARGET_USES_64_BIT_BINDER),true) ifneq ($(TARGET_IS_64_BIT),true) svc_c_flags += -DBINDER_IPC_32BIT=1 endif endif include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := bctest.c binder.c LOCAL_CFLAGS += $(svc_c_flags) LOCAL_MODULE := bctest LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := liblog libcutils libselinux LOCAL_SRC_FILES := service_manager.c binder.c LOCAL_CFLAGS += $(svc_c_flags) LOCAL_MODULE := servicemanager LOCAL_INIT_RC := servicemanager.rc include $(BUILD_EXECUTABLE) cmds/servicemanager/bctest.c0100644 0000000 0000000 00000005232 13077405420 015162 0ustar000000000 0000000 /* Copyright 2008 The Android Open Source Project */ #include #include #include #include #include "binder.h" uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) { uint32_t handle; unsigned iodata[512/4]; struct binder_io msg, reply; bio_init(&msg, iodata, sizeof(iodata), 4); bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, SVC_MGR_NAME); bio_put_string16_x(&msg, name); if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) return 0; handle = bio_get_ref(&reply); if (handle) binder_acquire(bs, handle); binder_done(bs, &msg, &reply); return handle; } int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) { int status; unsigned iodata[512/4]; struct binder_io msg, reply; bio_init(&msg, iodata, sizeof(iodata), 4); bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, SVC_MGR_NAME); bio_put_string16_x(&msg, name); bio_put_obj(&msg, ptr); if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) return -1; status = bio_get_uint32(&reply); binder_done(bs, &msg, &reply); return status; } unsigned token; int main(int argc, char **argv) { struct binder_state *bs; uint32_t svcmgr = BINDER_SERVICE_MANAGER; uint32_t handle; bs = binder_open(128*1024); if (!bs) { fprintf(stderr, "failed to open binder driver\n"); return -1; } argc--; argv++; while (argc > 0) { if (!strcmp(argv[0],"alt")) { handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); if (!handle) { fprintf(stderr,"cannot find alt_svc_mgr\n"); return -1; } svcmgr = handle; fprintf(stderr,"svcmgr is via %x\n", handle); } else if (!strcmp(argv[0],"lookup")) { if (argc < 2) { fprintf(stderr,"argument required\n"); return -1; } handle = svcmgr_lookup(bs, svcmgr, argv[1]); fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); argc--; argv++; } else if (!strcmp(argv[0],"publish")) { if (argc < 2) { fprintf(stderr,"argument required\n"); return -1; } svcmgr_publish(bs, svcmgr, argv[1], &token); argc--; argv++; } else { fprintf(stderr,"unknown command %s\n", argv[0]); return -1; } argc--; argv++; } return 0; } cmds/servicemanager/binder.c0100644 0000000 0000000 00000041510 13077405420 015140 0ustar000000000 0000000 /* Copyright 2008 The Android Open Source Project */ #include #include #include #include #include #include #include #include #include "binder.h" #define MAX_BIO_SIZE (1 << 30) #define TRACE 0 #define LOG_TAG "Binder" #include void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); #if TRACE void hexdump(void *_data, size_t len) { unsigned char *data = _data; size_t count; for (count = 0; count < len; count++) { if ((count & 15) == 0) fprintf(stderr,"%04zu:", count); fprintf(stderr," %02x %c", *data, (*data < 32) || (*data > 126) ? '.' : *data); data++; if ((count & 15) == 15) fprintf(stderr,"\n"); } if ((count & 15) != 0) fprintf(stderr,"\n"); } void binder_dump_txn(struct binder_transaction_data *txn) { struct flat_binder_object *obj; binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; size_t count = txn->offsets_size / sizeof(binder_size_t); fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); while (count--) { obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); } } #define NAME(n) case n: return #n const char *cmd_name(uint32_t cmd) { switch(cmd) { NAME(BR_NOOP); NAME(BR_TRANSACTION_COMPLETE); NAME(BR_INCREFS); NAME(BR_ACQUIRE); NAME(BR_RELEASE); NAME(BR_DECREFS); NAME(BR_TRANSACTION); NAME(BR_REPLY); NAME(BR_FAILED_REPLY); NAME(BR_DEAD_REPLY); NAME(BR_DEAD_BINDER); default: return "???"; } } #else #define hexdump(a,b) do{} while (0) #define binder_dump_txn(txn) do{} while (0) #endif #define BIO_F_SHARED 0x01 /* needs to be buffer freed */ #define BIO_F_OVERFLOW 0x02 /* ran out of space */ #define BIO_F_IOERROR 0x04 #define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ struct binder_state { int fd; void *mapped; size_t mapsize; }; struct binder_state *binder_open(size_t mapsize) { struct binder_state *bs; struct binder_version vers; bs = malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return NULL; } bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC); if (bs->fd < 0) { fprintf(stderr,"binder: cannot open device (%s)\n", strerror(errno)); goto fail_open; } if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { fprintf(stderr, "binder: kernel driver version (%d) differs from user space version (%d)\n", vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); goto fail_open; } bs->mapsize = mapsize; bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); if (bs->mapped == MAP_FAILED) { fprintf(stderr,"binder: cannot map device (%s)\n", strerror(errno)); goto fail_map; } return bs; fail_map: close(bs->fd); fail_open: free(bs); return NULL; } void binder_close(struct binder_state *bs) { munmap(bs->mapped, bs->mapsize); close(bs->fd); free(bs); } int binder_become_context_manager(struct binder_state *bs) { return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); } int binder_write(struct binder_state *bs, void *data, size_t len) { struct binder_write_read bwr; int res; bwr.write_size = len; bwr.write_consumed = 0; bwr.write_buffer = (uintptr_t) data; bwr.read_size = 0; bwr.read_consumed = 0; bwr.read_buffer = 0; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno)); } return res; } void binder_free_buffer(struct binder_state *bs, binder_uintptr_t buffer_to_free) { struct { uint32_t cmd_free; binder_uintptr_t buffer; } __attribute__((packed)) data; data.cmd_free = BC_FREE_BUFFER; data.buffer = buffer_to_free; binder_write(bs, &data, sizeof(data)); } void binder_send_reply(struct binder_state *bs, struct binder_io *reply, binder_uintptr_t buffer_to_free, int status) { struct { uint32_t cmd_free; binder_uintptr_t buffer; uint32_t cmd_reply; struct binder_transaction_data txn; } __attribute__((packed)) data; data.cmd_free = BC_FREE_BUFFER; data.buffer = buffer_to_free; data.cmd_reply = BC_REPLY; data.txn.target.ptr = 0; data.txn.cookie = 0; data.txn.code = 0; if (status) { data.txn.flags = TF_STATUS_CODE; data.txn.data_size = sizeof(int); data.txn.offsets_size = 0; data.txn.data.ptr.buffer = (uintptr_t)&status; data.txn.data.ptr.offsets = 0; } else { data.txn.flags = 0; data.txn.data_size = reply->data - reply->data0; data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); data.txn.data.ptr.buffer = (uintptr_t)reply->data0; data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; } binder_write(bs, &data, sizeof(data)); } int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func) { int r = 1; uintptr_t end = ptr + (uintptr_t) size; while (ptr < end) { uint32_t cmd = *(uint32_t *) ptr; ptr += sizeof(uint32_t); #if TRACE fprintf(stderr,"%s:\n", cmd_name(cmd)); #endif switch(cmd) { case BR_NOOP: break; case BR_TRANSACTION_COMPLETE: break; case BR_INCREFS: case BR_ACQUIRE: case BR_RELEASE: case BR_DECREFS: #if TRACE fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); #endif ptr += sizeof(struct binder_ptr_cookie); break; case BR_TRANSACTION: { struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; if ((end - ptr) < sizeof(*txn)) { ALOGE("parse: txn too small!\n"); return -1; } binder_dump_txn(txn); if (func) { unsigned rdata[256/4]; struct binder_io msg; struct binder_io reply; int res; bio_init(&reply, rdata, sizeof(rdata), 4); bio_init_from_txn(&msg, txn); res = func(bs, txn, &msg, &reply); if (txn->flags & TF_ONE_WAY) { binder_free_buffer(bs, txn->data.ptr.buffer); } else { binder_send_reply(bs, &reply, txn->data.ptr.buffer, res); } } ptr += sizeof(*txn); break; } case BR_REPLY: { struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; if ((end - ptr) < sizeof(*txn)) { ALOGE("parse: reply too small!\n"); return -1; } binder_dump_txn(txn); if (bio) { bio_init_from_txn(bio, txn); bio = 0; } else { /* todo FREE BUFFER */ } ptr += sizeof(*txn); r = 0; break; } case BR_DEAD_BINDER: { struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; ptr += sizeof(binder_uintptr_t); death->func(bs, death->ptr); break; } case BR_FAILED_REPLY: r = -1; break; case BR_DEAD_REPLY: r = -1; break; default: ALOGE("parse: OOPS %d\n", cmd); return -1; } } return r; } void binder_acquire(struct binder_state *bs, uint32_t target) { uint32_t cmd[2]; cmd[0] = BC_ACQUIRE; cmd[1] = target; binder_write(bs, cmd, sizeof(cmd)); } void binder_release(struct binder_state *bs, uint32_t target) { uint32_t cmd[2]; cmd[0] = BC_RELEASE; cmd[1] = target; binder_write(bs, cmd, sizeof(cmd)); } void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) { struct { uint32_t cmd; struct binder_handle_cookie payload; } __attribute__((packed)) data; data.cmd = BC_REQUEST_DEATH_NOTIFICATION; data.payload.handle = target; data.payload.cookie = (uintptr_t) death; binder_write(bs, &data, sizeof(data)); } int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply, uint32_t target, uint32_t code) { int res; struct binder_write_read bwr; struct { uint32_t cmd; struct binder_transaction_data txn; } __attribute__((packed)) writebuf; unsigned readbuf[32]; if (msg->flags & BIO_F_OVERFLOW) { fprintf(stderr,"binder: txn buffer overflow\n"); goto fail; } writebuf.cmd = BC_TRANSACTION; writebuf.txn.target.handle = target; writebuf.txn.code = code; writebuf.txn.flags = 0; writebuf.txn.data_size = msg->data - msg->data0; writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; bwr.write_size = sizeof(writebuf); bwr.write_consumed = 0; bwr.write_buffer = (uintptr_t) &writebuf; hexdump(msg->data0, msg->data - msg->data0); for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (uintptr_t) readbuf; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); goto fail; } res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); if (res == 0) return 0; if (res < 0) goto fail; } fail: memset(reply, 0, sizeof(*reply)); reply->flags |= BIO_F_IOERROR; return -1; } void binder_loop(struct binder_state *bs, binder_handler func) { int res; struct binder_write_read bwr; uint32_t readbuf[32]; bwr.write_size = 0; bwr.write_consumed = 0; bwr.write_buffer = 0; readbuf[0] = BC_ENTER_LOOPER; binder_write(bs, readbuf, sizeof(uint32_t)); for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (uintptr_t) readbuf; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); break; } res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); if (res == 0) { ALOGE("binder_loop: unexpected reply?!\n"); break; } if (res < 0) { ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); break; } } } void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) { bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; bio->data_avail = txn->data_size; bio->offs_avail = txn->offsets_size / sizeof(size_t); bio->flags = BIO_F_SHARED; } void bio_init(struct binder_io *bio, void *data, size_t maxdata, size_t maxoffs) { size_t n = maxoffs * sizeof(size_t); if (n > maxdata) { bio->flags = BIO_F_OVERFLOW; bio->data_avail = 0; bio->offs_avail = 0; return; } bio->data = bio->data0 = (char *) data + n; bio->offs = bio->offs0 = data; bio->data_avail = maxdata - n; bio->offs_avail = maxoffs; bio->flags = 0; } static void *bio_alloc(struct binder_io *bio, size_t size) { size = (size + 3) & (~3); if (size > bio->data_avail) { bio->flags |= BIO_F_OVERFLOW; return NULL; } else { void *ptr = bio->data; bio->data += size; bio->data_avail -= size; return ptr; } } void binder_done(struct binder_state *bs, __unused struct binder_io *msg, struct binder_io *reply) { struct { uint32_t cmd; uintptr_t buffer; } __attribute__((packed)) data; if (reply->flags & BIO_F_SHARED) { data.cmd = BC_FREE_BUFFER; data.buffer = (uintptr_t) reply->data0; binder_write(bs, &data, sizeof(data)); reply->flags = 0; } } static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) { struct flat_binder_object *obj; obj = bio_alloc(bio, sizeof(*obj)); if (obj && bio->offs_avail) { bio->offs_avail--; *bio->offs++ = ((char*) obj) - ((char*) bio->data0); return obj; } bio->flags |= BIO_F_OVERFLOW; return NULL; } void bio_put_uint32(struct binder_io *bio, uint32_t n) { uint32_t *ptr = bio_alloc(bio, sizeof(n)); if (ptr) *ptr = n; } void bio_put_obj(struct binder_io *bio, void *ptr) { struct flat_binder_object *obj; obj = bio_alloc_obj(bio); if (!obj) return; obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj->type = BINDER_TYPE_BINDER; obj->binder = (uintptr_t)ptr; obj->cookie = 0; } void bio_put_ref(struct binder_io *bio, uint32_t handle) { struct flat_binder_object *obj; if (handle) obj = bio_alloc_obj(bio); else obj = bio_alloc(bio, sizeof(*obj)); if (!obj) return; obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj->type = BINDER_TYPE_HANDLE; obj->handle = handle; obj->cookie = 0; } void bio_put_string16(struct binder_io *bio, const uint16_t *str) { size_t len; uint16_t *ptr; if (!str) { bio_put_uint32(bio, 0xffffffff); return; } len = 0; while (str[len]) len++; if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { bio_put_uint32(bio, 0xffffffff); return; } /* Note: The payload will carry 32bit size instead of size_t */ bio_put_uint32(bio, (uint32_t) len); len = (len + 1) * sizeof(uint16_t); ptr = bio_alloc(bio, len); if (ptr) memcpy(ptr, str, len); } void bio_put_string16_x(struct binder_io *bio, const char *_str) { unsigned char *str = (unsigned char*) _str; size_t len; uint16_t *ptr; if (!str) { bio_put_uint32(bio, 0xffffffff); return; } len = strlen(_str); if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { bio_put_uint32(bio, 0xffffffff); return; } /* Note: The payload will carry 32bit size instead of size_t */ bio_put_uint32(bio, len); ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); if (!ptr) return; while (*str) *ptr++ = *str++; *ptr++ = 0; } static void *bio_get(struct binder_io *bio, size_t size) { size = (size + 3) & (~3); if (bio->data_avail < size){ bio->data_avail = 0; bio->flags |= BIO_F_OVERFLOW; return NULL; } else { void *ptr = bio->data; bio->data += size; bio->data_avail -= size; return ptr; } } uint32_t bio_get_uint32(struct binder_io *bio) { uint32_t *ptr = bio_get(bio, sizeof(*ptr)); return ptr ? *ptr : 0; } uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) { size_t len; /* Note: The payload will carry 32bit size instead of size_t */ len = (size_t) bio_get_uint32(bio); if (sz) *sz = len; return bio_get(bio, (len + 1) * sizeof(uint16_t)); } static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) { size_t n; size_t off = bio->data - bio->data0; /* TODO: be smarter about this? */ for (n = 0; n < bio->offs_avail; n++) { if (bio->offs[n] == off) return bio_get(bio, sizeof(struct flat_binder_object)); } bio->data_avail = 0; bio->flags |= BIO_F_OVERFLOW; return NULL; } uint32_t bio_get_ref(struct binder_io *bio) { struct flat_binder_object *obj; obj = _bio_get_obj(bio); if (!obj) return 0; if (obj->type == BINDER_TYPE_HANDLE) return obj->handle; return 0; } cmds/servicemanager/binder.h0100644 0000000 0000000 00000005717 13077405420 015156 0ustar000000000 0000000 /* Copyright 2008 The Android Open Source Project */ #ifndef _BINDER_H_ #define _BINDER_H_ #include #include struct binder_state; struct binder_io { char *data; /* pointer to read/write from */ binder_size_t *offs; /* array of offsets */ size_t data_avail; /* bytes available in data buffer */ size_t offs_avail; /* entries available in offsets array */ char *data0; /* start of data buffer */ binder_size_t *offs0; /* start of offsets buffer */ uint32_t flags; uint32_t unused; }; struct binder_death { void (*func)(struct binder_state *bs, void *ptr); void *ptr; }; /* the one magic handle */ #define BINDER_SERVICE_MANAGER 0U #define SVC_MGR_NAME "android.os.IServiceManager" enum { /* Must match definitions in IBinder.h and IServiceManager.h */ PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), SVC_MGR_GET_SERVICE = 1, SVC_MGR_CHECK_SERVICE, SVC_MGR_ADD_SERVICE, SVC_MGR_LIST_SERVICES, }; typedef int (*binder_handler)(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply); struct binder_state *binder_open(size_t mapsize); void binder_close(struct binder_state *bs); /* initiate a blocking binder call * - returns zero on success */ int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply, uint32_t target, uint32_t code); /* release any state associate with the binder_io * - call once any necessary data has been extracted from the * binder_io after binder_call() returns * - can safely be called even if binder_call() fails */ void binder_done(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply); /* manipulate strong references */ void binder_acquire(struct binder_state *bs, uint32_t target); void binder_release(struct binder_state *bs, uint32_t target); void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); void binder_loop(struct binder_state *bs, binder_handler func); int binder_become_context_manager(struct binder_state *bs); /* allocate a binder_io, providing a stack-allocated working * buffer, size of the working buffer, and how many object * offset entries to reserve from the buffer */ void bio_init(struct binder_io *bio, void *data, size_t maxdata, size_t maxobjects); void bio_put_obj(struct binder_io *bio, void *ptr); void bio_put_ref(struct binder_io *bio, uint32_t handle); void bio_put_uint32(struct binder_io *bio, uint32_t n); void bio_put_string16(struct binder_io *bio, const uint16_t *str); void bio_put_string16_x(struct binder_io *bio, const char *_str); uint32_t bio_get_uint32(struct binder_io *bio); uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); uint32_t bio_get_ref(struct binder_io *bio); #endif cmds/servicemanager/service_manager.c0100644 0000000 0000000 00000024213 13077405420 017030 0ustar000000000 0000000 /* Copyright 2008 The Android Open Source Project */ #include #include #include #include #include #include #include #include #include #include #include "binder.h" #if 0 #define ALOGI(x...) fprintf(stderr, "svcmgr: " x) #define ALOGE(x...) fprintf(stderr, "svcmgr: " x) #else #define LOG_TAG "ServiceManager" #include #endif struct audit_data { pid_t pid; uid_t uid; const char *name; }; const char *str8(const uint16_t *x, size_t x_len) { static char buf[128]; size_t max = 127; char *p = buf; if (x_len < max) { max = x_len; } if (x) { while ((max > 0) && (*x != '\0')) { *p++ = *x++; max--; } } *p++ = 0; return buf; } int str16eq(const uint16_t *a, const char *b) { while (*a && *b) if (*a++ != *b++) return 0; if (*a || *b) return 0; return 1; } static int selinux_enabled; static char *service_manager_context; static struct selabel_handle* sehandle; static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name) { char *sctx = NULL; const char *class = "service_manager"; bool allowed; struct audit_data ad; if (getpidcon(spid, &sctx) < 0) { ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); return false; } ad.pid = spid; ad.uid = uid; ad.name = name; int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad); allowed = (result == 0); freecon(sctx); return allowed; } static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm) { if (selinux_enabled <= 0) { return true; } return check_mac_perms(spid, uid, service_manager_context, perm, NULL); } static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name) { bool allowed; char *tctx = NULL; if (selinux_enabled <= 0) { return true; } if (!sehandle) { ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); abort(); } if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { ALOGE("SELinux: No match for %s in service_contexts.\n", name); return false; } allowed = check_mac_perms(spid, uid, tctx, perm, name); freecon(tctx); return allowed; } static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid) { const char *perm = "add"; if (multiuser_get_app_id(uid) >= AID_APP) { return 0; /* Don't allow apps to register services */ } return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0; } static int svc_can_list(pid_t spid, uid_t uid) { const char *perm = "list"; return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0; } static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid) { const char *perm = "find"; return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0; } struct svcinfo { struct svcinfo *next; uint32_t handle; struct binder_death death; int allow_isolated; size_t len; uint16_t name[0]; }; struct svcinfo *svclist = NULL; struct svcinfo *find_svc(const uint16_t *s16, size_t len) { struct svcinfo *si; for (si = svclist; si; si = si->next) { if ((len == si->len) && !memcmp(s16, si->name, len * sizeof(uint16_t))) { return si; } } return NULL; } void svcinfo_death(struct binder_state *bs, void *ptr) { struct svcinfo *si = (struct svcinfo* ) ptr; ALOGI("service '%s' died\n", str8(si->name, si->len)); if (si->handle) { binder_release(bs, si->handle); si->handle = 0; } } uint16_t svcmgr_id[] = { 'a','n','d','r','o','i','d','.','o','s','.', 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' }; uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid) { struct svcinfo *si = find_svc(s, len); if (!si || !si->handle) { return 0; } if (!si->allow_isolated) { // If this service doesn't allow access from isolated processes, // then check the uid to see if it is isolated. uid_t appid = uid % AID_USER; if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { return 0; } } if (!svc_can_find(s, len, spid, uid)) { return 0; } return si->handle; } int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, pid_t spid) { struct svcinfo *si; //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); if (!handle || (len == 0) || (len > 127)) return -1; if (!svc_can_register(s, len, spid, uid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; } si = find_svc(s, len); if (si) { if (si->handle) { ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid); svcinfo_death(bs, si); } si->handle = handle; } else { si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid); return -1; } si->handle = handle; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = (void*) svcinfo_death; si->death.ptr = si; si->allow_isolated = allow_isolated; si->next = svclist; svclist = si; } binder_acquire(bs, handle); binder_link_to_death(bs, handle, &si->death); return 0; } int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply) { struct svcinfo *si; uint16_t *s; size_t len; uint32_t handle; uint32_t strict_policy; int allow_isolated; //ALOGI("target=%p code=%d pid=%d uid=%d\n", // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); if (txn->target.ptr != BINDER_SERVICE_MANAGER) return -1; if (txn->code == PING_TRANSACTION) return 0; // Equivalent to Parcel::enforceInterface(), reading the RPC // header with the strict mode policy mask and the interface name. // Note that we ignore the strict_policy and don't propagate it // further (since we do no outbound RPCs anyway). strict_policy = bio_get_uint32(msg); s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { fprintf(stderr,"invalid id %s\n", str8(s, len)); return -1; } if (sehandle && selinux_status_updated() > 0) { struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); if (tmp_sehandle) { selabel_close(sehandle); sehandle = tmp_sehandle; } } switch(txn->code) { case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid); if (!handle) break; bio_put_ref(reply, handle); return 0; case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid)) return -1; break; case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); if (!svc_can_list(txn->sender_pid, txn->sender_euid)) { ALOGE("list_service() uid=%d - PERMISSION DENIED\n", txn->sender_euid); return -1; } si = svclist; while ((n-- > 0) && si) si = si->next; if (si) { bio_put_string16(reply, si->name); return 0; } return -1; } default: ALOGE("unknown code %d\n", txn->code); return -1; } bio_put_uint32(reply, 0); return 0; } static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) { struct audit_data *ad = (struct audit_data *)data; if (!ad || !ad->name) { ALOGE("No service manager audit data"); return 0; } snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); return 0; } int main() { struct binder_state *bs; bs = binder_open(128*1024); if (!bs) { ALOGE("failed to open binder driver\n"); return -1; } if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } selinux_enabled = is_selinux_enabled(); sehandle = selinux_android_service_context_handle(); selinux_status_open(true); if (selinux_enabled > 0) { if (sehandle == NULL) { ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); abort(); } if (getcon(&service_manager_context) != 0) { ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); abort(); } } union selinux_callback cb; cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); cb.func_log = selinux_log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); binder_loop(bs, svcmgr_handler); return 0; } cmds/servicemanager/servicemanager.rc0100644 0000000 0000000 00000000650 13077405420 017052 0ustar000000000 0000000 service servicemanager /system/bin/servicemanager class core user system group system readproc critical onrestart restart healthd onrestart restart zygote onrestart restart audioserver onrestart restart media onrestart restart surfaceflinger onrestart restart inputflinger onrestart restart drm onrestart restart cameraserver writepid /dev/cpuset/system-background/tasks data/0040755 0000000 0000000 00000000000 13077405420 010523 5ustar000000000 0000000 data/etc/0040755 0000000 0000000 00000000000 13077405420 011276 5ustar000000000 0000000 data/etc/android.hardware.audio.low_latency.xml0100644 0000000 0000000 00000001634 13077405420 020654 0ustar000000000 0000000 data/etc/android.hardware.audio.output.xml0100644 0000000 0000000 00000001661 13077405420 017674 0ustar000000000 0000000 data/etc/android.hardware.audio.pro.xml0100644 0000000 0000000 00000001625 13077405420 017134 0ustar000000000 0000000 data/etc/android.hardware.bluetooth.xml0100644 0000000 0000000 00000001464 13077405420 017242 0ustar000000000 0000000 data/etc/android.hardware.bluetooth_le.xml0100644 0000000 0000000 00000001476 13077405420 017725 0ustar000000000 0000000 data/etc/android.hardware.camera.autofocus.xml0100644 0000000 0000000 00000001643 13077405420 020473 0ustar000000000 0000000 data/etc/android.hardware.camera.external.xml0100644 0000000 0000000 00000001645 13077405420 020307 0ustar000000000 0000000 data/etc/android.hardware.camera.flash-autofocus.xml0100644 0000000 0000000 00000002034 13077405420 021561 0ustar000000000 0000000 data/etc/android.hardware.camera.front.xml0100644 0000000 0000000 00000001555 13077405420 017615 0ustar000000000 0000000 data/etc/android.hardware.camera.full.xml0100644 0000000 0000000 00000002025 13077405420 017420 0ustar000000000 0000000 data/etc/android.hardware.camera.manual_postprocessing.xml0100644 0000000 0000000 00000001662 13077405420 023103 0ustar000000000 0000000 data/etc/android.hardware.camera.manual_sensor.xml0100644 0000000 0000000 00000001640 13077405420 021326 0ustar000000000 0000000 data/etc/android.hardware.camera.raw.xml0100644 0000000 0000000 00000001620 13077405420 017247 0ustar000000000 0000000 data/etc/android.hardware.camera.xml0100644 0000000 0000000 00000001555 13077405420 016466 0ustar000000000 0000000 data/etc/android.hardware.consumerir.xml0100644 0000000 0000000 00000001560 13077405420 017420 0ustar000000000 0000000 data/etc/android.hardware.ethernet.xml0100644 0000000 0000000 00000001502 13077405420 017044 0ustar000000000 0000000 data/etc/android.hardware.faketouch.multitouch.distinct.xml0100644 0000000 0000000 00000002014 13077405420 023212 0ustar000000000 0000000 data/etc/android.hardware.faketouch.multitouch.jazzhand.xml0100644 0000000 0000000 00000002117 13077405420 023206 0ustar000000000 0000000 data/etc/android.hardware.faketouch.xml0100644 0000000 0000000 00000001637 13077405420 017210 0ustar000000000 0000000 data/etc/android.hardware.fingerprint.xml0100644 0000000 0000000 00000001502 13077405420 017555 0ustar000000000 0000000 data/etc/android.hardware.gamepad.xml0100644 0000000 0000000 00000001547 13077405420 016635 0ustar000000000 0000000 data/etc/android.hardware.hdmi.cec.xml0100644 0000000 0000000 00000001502 13077405420 016700 0ustar000000000 0000000 data/etc/android.hardware.location.gps.xml0100644 0000000 0000000 00000001656 13077405420 017640 0ustar000000000 0000000 data/etc/android.hardware.location.xml0100644 0000000 0000000 00000001665 13077405420 017050 0ustar000000000 0000000 data/etc/android.hardware.nfc.hce.xml0100644 0000000 0000000 00000001510 13077405420 016531 0ustar000000000 0000000 data/etc/android.hardware.nfc.hcef.xml0100644 0000000 0000000 00000001513 13077405420 016702 0ustar000000000 0000000 data/etc/android.hardware.nfc.xml0100644 0000000 0000000 00000001551 13077405420 016000 0ustar000000000 0000000 data/etc/android.hardware.opengles.aep.xml0100644 0000000 0000000 00000001546 13077405420 017616 0ustar000000000 0000000 data/etc/android.hardware.screen.landscape.xml0100644 0000000 0000000 00000001503 13077405420 020437 0ustar000000000 0000000 data/etc/android.hardware.screen.portrait.xml0100644 0000000 0000000 00000001501 13077405420 020347 0ustar000000000 0000000 data/etc/android.hardware.sensor.accelerometer.xml0100644 0000000 0000000 00000001470 13077405420 021354 0ustar000000000 0000000 data/etc/android.hardware.sensor.ambient_temperature.xml0100644 0000000 0000000 00000001504 13077405420 022574 0ustar000000000 0000000 data/etc/android.hardware.sensor.barometer.xml0100644 0000000 0000000 00000001446 13077405420 020525 0ustar000000000 0000000 data/etc/android.hardware.sensor.compass.xml0100644 0000000 0000000 00000001444 13077405420 020210 0ustar000000000 0000000 data/etc/android.hardware.sensor.gyroscope.xml0100644 0000000 0000000 00000001446 13077405420 020557 0ustar000000000 0000000 data/etc/android.hardware.sensor.heartrate.ecg.xml0100644 0000000 0000000 00000001507 13077405420 021257 0ustar000000000 0000000 data/etc/android.hardware.sensor.heartrate.xml0100644 0000000 0000000 00000001466 13077405420 020526 0ustar000000000 0000000 data/etc/android.hardware.sensor.hifi_sensors.xml0100644 0000000 0000000 00000001456 13077405420 021241 0ustar000000000 0000000 data/etc/android.hardware.sensor.light.xml0100644 0000000 0000000 00000001460 13077405420 017650 0ustar000000000 0000000 data/etc/android.hardware.sensor.proximity.xml0100644 0000000 0000000 00000001457 13077405420 020613 0ustar000000000 0000000 data/etc/android.hardware.sensor.relative_humidity.xml0100644 0000000 0000000 00000001477 13077405420 022300 0ustar000000000 0000000 data/etc/android.hardware.sensor.stepcounter.xml0100644 0000000 0000000 00000001462 13077405420 021116 0ustar000000000 0000000 data/etc/android.hardware.sensor.stepdetector.xml0100644 0000000 0000000 00000001453 13077405420 021250 0ustar000000000 0000000 data/etc/android.hardware.telephony.cdma.xml0100644 0000000 0000000 00000001563 13077405420 020147 0ustar000000000 0000000 data/etc/android.hardware.telephony.gsm.xml0100644 0000000 0000000 00000001561 13077405420 020027 0ustar000000000 0000000 data/etc/android.hardware.touchscreen.multitouch.distinct.xml0100644 0000000 0000000 00000002064 13077405420 023570 0ustar000000000 0000000 data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml0100644 0000000 0000000 00000002170 13077405420 023556 0ustar000000000 0000000 data/etc/android.hardware.touchscreen.multitouch.xml0100644 0000000 0000000 00000002013 13077405420 021742 0ustar000000000 0000000 data/etc/android.hardware.touchscreen.xml0100644 0000000 0000000 00000001615 13077405420 017555 0ustar000000000 0000000 data/etc/android.hardware.type.automotive.xml0100644 0000000 0000000 00000001500 13077405420 020400 0ustar000000000 0000000 data/etc/android.hardware.usb.accessory.xml0100644 0000000 0000000 00000001717 13077405420 020021 0ustar000000000 0000000 data/etc/android.hardware.usb.host.xml0100644 0000000 0000000 00000001544 13077405420 017001 0ustar000000000 0000000 data/etc/android.hardware.vr.high_performance.xml0100644 0000000 0000000 00000001561 13077405420 021161 0ustar000000000 0000000 data/etc/android.hardware.vulkan.level-0.xml0100644 0000000 0000000 00000001541 13077405420 017774 0ustar000000000 0000000 data/etc/android.hardware.vulkan.level-1.xml0100644 0000000 0000000 00000001541 13077405420 017775 0ustar000000000 0000000 data/etc/android.hardware.vulkan.version-1_0_3.xml0100644 0000000 0000000 00000001610 13077405420 021011 0ustar000000000 0000000 data/etc/android.hardware.wifi.direct.xml0100644 0000000 0000000 00000001513 13077405420 017437 0ustar000000000 0000000 data/etc/android.hardware.wifi.nan.xml0100644 0000000 0000000 00000001501 13077405420 016736 0ustar000000000 0000000 data/etc/android.hardware.wifi.xml0100644 0000000 0000000 00000001475 13077405420 016175 0ustar000000000 0000000 data/etc/android.software.app_widgets.xml0100644 0000000 0000000 00000001360 13077405420 017573 0ustar000000000 0000000 data/etc/android.software.backup.xml0100644 0000000 0000000 00000001353 13077405420 016534 0ustar000000000 0000000 data/etc/android.software.connectionservice.xml0100644 0000000 0000000 00000001530 13077405420 021004 0ustar000000000 0000000 data/etc/android.software.device_admin.xml0100644 0000000 0000000 00000001361 13077405420 017675 0ustar000000000 0000000 data/etc/android.software.freeform_window_management.xml0100644 0000000 0000000 00000001377 13077405420 022665 0ustar000000000 0000000 data/etc/android.software.live_tv.xml0100644 0000000 0000000 00000001354 13077405420 016740 0ustar000000000 0000000 data/etc/android.software.managed_users.xml0100644 0000000 0000000 00000001513 13077405420 020102 0ustar000000000 0000000 data/etc/android.software.midi.xml0100644 0000000 0000000 00000001351 13077405420 016207 0ustar000000000 0000000 data/etc/android.software.picture_in_picture.xml0100644 0000000 0000000 00000001367 13077405420 021170 0ustar000000000 0000000 data/etc/android.software.print.xml0100644 0000000 0000000 00000001352 13077405420 016422 0ustar000000000 0000000 data/etc/android.software.securely_removes_users.xml0100644 0000000 0000000 00000001372 13077405420 022104 0ustar000000000 0000000 data/etc/android.software.sip.voip.xml0100644 0000000 0000000 00000001560 13077405420 017036 0ustar000000000 0000000 data/etc/android.software.sip.xml0100644 0000000 0000000 00000001474 13077405420 016066 0ustar000000000 0000000 data/etc/android.software.verified_boot.xml0100644 0000000 0000000 00000001361 13077405420 020106 0ustar000000000 0000000 data/etc/android.software.voice_recognizers.xml0100644 0000000 0000000 00000001407 13077405420 021006 0ustar000000000 0000000 data/etc/android.software.vr.xml0100644 0000000 0000000 00000001465 13077405420 015722 0ustar000000000 0000000 data/etc/android.software.webview.xml0100644 0000000 0000000 00000001354 13077405420 016740 0ustar000000000 0000000 data/etc/car_core_hardware.xml0100644 0000000 0000000 00000007246 13077405420 015460 0ustar000000000 0000000 data/etc/com.android.nfc_extras.xml0100644 0000000 0000000 00000001452 13077405420 016347 0ustar000000000 0000000 data/etc/com.nxp.mifare.xml0100644 0000000 0000000 00000001456 13077405420 014647 0ustar000000000 0000000 data/etc/handheld_core_hardware.xml0100644 0000000 0000000 00000010202 13077405420 016444 0ustar000000000 0000000 data/etc/tablet_core_hardware.xml0100644 0000000 0000000 00000006505 13077405420 016163 0ustar000000000 0000000 data/etc/wearable_core_hardware.xml0100644 0000000 0000000 00000006157 13077405420 016475 0ustar000000000 0000000 docs/0040755 0000000 0000000 00000000000 13077405420 010542 5ustar000000000 0000000 docs/Doxyfile0100644 0000000 0000000 00000240562 13077405420 012256 0ustar000000000 0000000 # Doxyfile 1.8.3.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = "NDK API" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented classes, # or namespaces to their corresponding documentation. Such a link can be # prevented in individual cases by by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = YES # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if section-label ... \endif # and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 26 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. Do not use # file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../include/android ../../av/include/ndk ../../av/include/camera/ndk # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page (index.html). # This can be useful if you have a project on for instance GitHub and want reuse # the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = $(HTML_OUTPUT) # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = $(HTML_HEADER) # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = $(HTML_FOOTER) # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 0 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = YES # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and # SVG. The default value is HTML-CSS, which is slower, but has the best # compatibility. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. # There are two flavours of web server based search depending on the # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # searching and an index file used by the script. When EXTERNAL_SEARCH is # enabled the indexing and searching needs to be provided by external tools. # See the manual for details. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain # the search results. Doxygen ships with an example indexer (doxyindexer) and # search engine (doxysearch.cgi) which are based on the open source search engine # library Xapian. See the manual for configuration details. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will returned the search results when EXTERNAL_SEARCH is enabled. # Doxygen ships with an example search engine (doxysearch) which is based on # the open source search engine library Xapian. See the manual for configuration # details. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id # of to a relative location where the documentation can be found. # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES docs/Makefile0100644 0000000 0000000 00000000472 13077405420 012202 0ustar000000000 0000000 HEADERS := $(wildcard ../include/android/*.h) all: html jd html: $(HEADERS) Doxyfile mkdir -p html doxygen jd: $(HEADERS) Doxyfile header.jd mkdir -p jd HTML_HEADER=header.jd HTML_FOOTER=footer.jd HTML_OUTPUT=jd doxygen for file in jd/*.html; do mv "$${file}" "$${file/.html/.jd}"; done rm -f jd/index.jd docs/footer.jd0100644 0000000 0000000 00000000000 13077405420 012342 0ustar000000000 0000000 docs/header.jd0100644 0000000 0000000 00000000155 13077405420 012307 0ustar000000000 0000000 page.title=$title page.customHeadTag= @jd:body docs/images/0040755 0000000 0000000 00000000000 13077405420 012007 5ustar000000000 0000000 docs/images/camera2/0040755 0000000 0000000 00000000000 13077405420 013321 5ustar000000000 0000000 docs/images/camera2/metadata/0040755 0000000 0000000 00000000000 13077405420 015101 5ustar000000000 0000000 docs/images/camera2/metadata/android.colorCorrection.mode/0040755 0000000 0000000 00000000000 13077405420 022611 5ustar000000000 0000000 docs/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png0100644 0000000 0000000 00000062003 13077405420 027356 0ustar000000000 0000000 PNG  IHDRRcIDATx {.pS }xXPH ㊊ׅ%jTxH58F]/G`lȑ/x4koI$. կᝢg:9ϙ}7ϓJIho}jjj>R$I$)7fΜ]wueggqT$I$IywZ (J$I$ $I$IB$I$IP$I$IJ$I$IBI$I$I@(I$I$ %I*m\=ɲ HBI*W[_ {Se\H,ӧ AC??}$I@( h׿8ҙx_:o2YVv >;^4Ӽwb]} JP@(I-Qޅ_-{i[.~vwCap[P$PJfW9Z[[)tc?.X~ozg?G#IBd &F1ʒ`\F05!*/I  ©IVoer-w²'ya{"z$I@( ve8d};XI aC<G?Cx{}o )[$ RD6{E!++O!bt$PJ:R1zW iЭHB)I@j㷜dvI z_8K.dj$7V$IB _nUƬ:>.ammmm;r5V:K#m$IBԫ@.1ݾ+W;(+{ $ JR߿+ۼc;jKP@(I=sigNR쒹W~$ JRbы*ȡRjI 2$~^Hux5Q]G 4w'4k~ p1$L}+F?I8_}ퟖ=νhv[If#O{Cgۈ>{]}CAJ\${ ǜ4ѫPI $hXFߣ!vHGNz%^T dųr ~{[t8IBpN%{ ;,_9W\\;B<PcKrw;3L!I ԐKu~_;p>~2ܧ@86}!мQ}i1ެytIH|7=qwŶ͎eсW,>~.!78h,|K7i>` hNvwxӨg/v/b'=s?r3a& 48646cOֻ`uσZp !$}jBx@B(phcZ7U04!Q+ "PHL@7@sC 2m̷\,^k1m!6S( $I@(I3ٷS]Y%H!i B}8R8XYX a Ec~s~v^}1g︱hjvKtfxN(d\g`wsievYtPBI۽2qCNzaY X6]hN"L@(Ir‘ghFvBYW I gTjkkkL,6T#uuuZMMuqg5L*p?BY%lLH8.5PH6mjٸq]* ,Zjkk3ƛ3gwM7yeE0 oȑ ˟WSHx*$:;"U@(XJRap6@   ~1w/ao۶mڵkg^<\zW^_S@( "^6V`7_<`?eʔ ̒|%B.6D^[~,㷜ڃYgoIrX& *ݸRIk>:l+C.!$O_\μLE mMq˪bԬ)Y‰y[jr6XbRCuއ[cɞ祼P@<1oԩC O ?s[>>LN+B`3pn5 #rO'_XA[@h!1HDժHNmZ0Bd:PJ,~AͿ P@_ ڻeWmŊ5 [.@H1'MaP o?f%ۀ%^|[@( ?`Vnv޽u=>) K,\PUv'oûR9&Sj NQ B`<j<@s ?/ #\^¸931y@?=̼^`X|LUSMz  \ g% `vܹlP\8׀$rbxStCvByFqcg^4΃ki¬dW|njs=14oaڹe\ʸxfx+ V'kqj9 9LR|뭟AaP[[)s[c(BiBp a A1 lK*1-xapcV:<>`xlA faG 1NFV̀m?mi33W\_<9567ׁV+\CwM 6=o<y:n, l@sm#l =@~,̌~\01A?\WrM책y r9kG<}\#fZO:2V,Wo %Cn`P@ZJ  ?'s='TL.|S۰rP5 x g̕3qoП8U4.-0x|l}2lPR{4 Zc|(1|ۜN`*1$U˖- +W\) eeob4<J`6l7c L@( %2gPa]$ gyr7ydObwPV@H )1nS@( %)1jkkk- ;vlF#, ޘY*ǵx{TJ7M1k׮-g BTT1![BL@(IЦMZbj +tqI';\ٰa7~g\`n&/#L0v{  RҤ&ϖ %C7{ VWSOn6a=zFc܅ v1z_-Z=ٷwRHB:`queBzFnV`7_EBV3%SL/zMMMy̙n&M]dI9}.aWʶmڴiAx9xu8xTe_Ø1cP5/&pxemb@@?-] 2|>. LY,'`F>>"bW ^orFhD$vK뙑grX! *ݸGu3s8ۛ g$t_曃/d6rћ3gnݺ`z |Gz/`lŊ\&7x|wyW__\oqnO<mܼQ ĆZkY$ $|<:2P@y,Yr.9HZ\ !6YU.$}⼈#qt(eB)PtVqy):(, {0s>ڻ+ /^:jx3!s2 gdwU/x/mE,`e/H}z8>:pW 'b㰕̇_y, x&1q+1X*e, ,#e/KB{ɸv}P@(I=3ᣏ>3~衇6Ƌ 7r%FebAIpJ#w\}@&1$xIKeVO@IMg\@8zP׀35c Yeqَ'Yt~#s--!NBI*sE.-5Ya;voÊ2m#P!,>y\%!V.`P&0cg!bK (9rPs-eʩ.G\]rZlѕx )vXHC ׈Fx k6t+n>oB&(,>#^KKK$Ζ-[D Է1?BBSÞBbUH(/V ,dɒ 3QؒE"$f[$&!0ߓt7TIal(v91p^#1!~؟Um>0{Ll΅}~Q@^?0e ̻s*墐1oq-hX-^!JHW# nܣ:|۹sۏ¢!?O,\  r֘[8伀X9߀<*TS\8#lFр qJ%F<p6 qIJY8N0Pi3-` ̀M+KйI>G9`j۾@a4 H>:n,q/ Y<9Vs.BXR00(5<+bBB"!uB)k  $gv ~ Kϖ [sՖG~Tw>~˷|R1l^90s7 spd1&uav׀ͅ9[b/<{ /Gci xڽfox~-v5|?'iccak ?]x{0 ]qV&@-d?uq1ُ݅R ]nT4 YVΝ7\7 %// ksw8?S,(X: @,<:jͣ1&Xr ]yMhv(@\bakk d9/3tX$ 9;֘&e=Ц-v6C .O̯3ƣ|bUSJhd/Cy5$Oa\<khgJ q1><@JBYm޼OZdn믿>TspH3s饗g eL i<n' x*kB >µx F07} N- ܷvQ8l{48幀0nߞNOAS@|8}zꗐ5X V>Ǭ{ m +YDyviW* ex(4  hc2rlI' 2֦Mftx  6!kvBI<1'!B󷮮.x]@EC2a!ee 2ll,xPo$ i`1@- 0!׊܏VW@(I¼Ĵ裏 m; ' =ۋw O /@ mIbsB.Zrv -:';7،9Zq1`!Fx؀ck' $auNj/sE):1fY 9j~`Sm+VܰiУULF121Ph9 ygy&8bk?/2`rМW%-yYb}Sw>s\8 AXz<'$BB(rҟcu/k)_ؓrQX-̱= UwĀ$U{Jخ]G0^,Ї455c_tE\BQ( yn@ `@ظ~/^\цA'pI<@[Q ȾqX)6w@>uWJ t2πǜƗ+xrAz>@a 9{s CHbں뮻x SRu!nA@t!P8aIsrrBP uO_ <,0yk!rQc@#F蒨Z@H(!@<.?׆0/_;K ö1cۘhZc0g:cL@HL:i_@( ,1w 'y\BB!1 {@"+{{1;oѮP*+5?Te͛7OJQ $ 5mO=``t~yW\q0 4 !c@ 9xƶ0x ‹/8$Vc lof21^BE8o~)U&X*D6m/aÆ~<  $2/~~/,TXJ7U rݔ3n]`b!atۢYl3y .FgVM 0_Kj%*+ @<]}C@P*Dk֬'A5(Ԣ<>x`pdU*I$$meC<B!aNοozp熂_45!ae7 eBI*GÄXEL—n);b`tN,(wsE朣J0W $5)Xs4RtCc7dՄ 33fkɥIC;I" $aN*UnrB¨* W>Z@X=@hsHCHdЌ_F Q DyIT}BI ,N? ,F(>VQ:έO*u͒Kg d.^8OcB7_L@(I?s2D@XֿӻVW,.-M1r B&.6@,yWVj`P@(IyI@XP]rɒozN}{ɫV d19=y⌄ѹˠLFs Rg@ 1 -*ӷ!Hmy<BI2jӦM-1yjРA%H~F +߮g01 /15)5횗cΟ%z]!"^'m J}d@.`|K uzIR`iP@'ɕ\7I4BxY:g^=Džxpx>{JU+vl=[< kd]].ʭ ߫{nˆQE[7@heqP[>ܪ;N{oh:(SafW2J(ƍ[SS ׀'¯*0EBT@ǟ}^6&L~&mP&JU ۼy?kg&\!,fԼo߰a5m * eBIBmmm> ͖m\ok[7o<)ݏ0oXO޹`uW\)+=SA}bĉwuשj2)P& $)$/aÆ~<SoӁYqm{x[$Ef͚zTaܵq!̖Ś}cqTBPx%I@( %I@( $L& $P2PBIdBI %?|lBVq;tϗ$Pz|' df_-v$ ^N\ymYٹͶ{0}%I@( :̿.igxaPIBIFzGYٱ'm$ JRzqO~mYؚWxu^}>+$PR*7\}%I@( L] !;,=%$ JRցÆ"UקoE}%I@( ++*\,IB$e!m:|6oT~ c׷;g^_mI %);]꛿%\OWZBI^ mظk .degsA~$ Z0ڙ/ȐSx^}:J2J$ JR|yUeU cO KP@(Iу|W.{'(%X3 WWBI*O<ߗS)|,KjxIz*Q'IB$ O!s A,1jSJ1#IB$U7ФqvR(O7m\qmPnD_QI %4j}CoWEYoACx߾ ')IB$VCGz^,ߴDV#y;AJ;-RXBIEQn~泼 <ϻۂ?|le}v LbPj#,f}鋇IBIJ e:Ց(}$I@( a*-j}ŷ*6=🌑*IP@(IRp2ƽE=moRI$ J$$I %IJ$ $3"$I@( $^.$IPa@Iy(,79sPKM}$IPs[)I@I$)?(,ħSJP$I$I<dNr$I$IRu CX$Rg$I$I$I$I%<虊 %I$I@I$I$$I$ITP$I$po}K%I$I$$I$IP|Ʒ}&$I$I %I$I$I$IR%n~+$I$I.o56@J$I$I(I$I$}ۍJ$I$UnJ$I$ $I$IU;$I$Ik|[Tzy#S Vd &F$I$`qD|׷Td2YҌ94OmF$IJBVDog+_[}wyZ_Ż+W~2q)iS绵9ՑzI*$I^5!%MCBJ0Îh?^sOYv,쟟yΛW7hp-zݚ$I$`f1Cp!+g{iVֻaiWS_%I$I۱`BVi`omsu $I ̳ca DX(Rna;9>#UxWpnk$IR5yM}w+[ _{;$IRXHgT<_t2k`AV5Bިc(~+|,I$ ]\z+s&Upȁ}~ߏ-Q$IX ;=@V«ٓ"I$ JGq=KP vۿĦLmS$O:ӎK)9\= :^WW_yF%I*}Ƶ3n⻂8|hrn$I%,Kf O2Y-{iܪ[$IRqE_#s+g$aShzi AX9eL8ULVV-IT<5^=`091lo1 dvq555Z$8"DkaSpH ?R-?$ًX&ky˟˶h;xtsA]nv]bamK$Nc S{R=0 oנؚ@]s#կrֿ;ıԹ5nymބ4*x2' ڝsŵ_:d9k5x0t].Xr!#ktc7x)t~vmjBreS'q^'3I_([1}!)^(F*Rv4lP"fkT^1m)vR_ehT5J%}ǸbQBQ45~nXP(!~:f@%X8νhvp TrKb}!=T+WK' Dͩ}Gs:* H*AN{RPv8Id$Exx 0`e׮HL97bu]T氒lv)Dq,*cv f|HlIha靐Hߌs9(Pٵ`lO|?bU/rNlg#Q5ql9Ͷq{x]0WK\GqheWh0me@}xgܴi^^!QǓkc|x3~5?cP|$ Nm3ps>nJ*4y,ت[*lrK?0wl ‰@ `?>vp$}<@P2>hxб>`Ī06!گkg5]ׂb,>Σ=rlsA?l )gdHeUWxJH?,o787,׀s1<Ud\|8/cxާ|=BPz^۔Tǂldɐ!4gn?PKaI@;jE€ɼO6`d薬Y}⸲u@go^ ˼x0Vg"4@<ݱq=]Az4o`Ix yͶs< qmyl?3'{@qcdtc煇`O@(JBY9Hmk,^ 9g'mxi} x_ xB΁] !Tn_(10A.xhcZڷc8g|=`.ÀǼ7\g>.A/x?{7n_ ڳSL R@(IBa}B'(DK.;~i\Dh fj[E,A <H 1F/ᦜ1Xy|8%&kT.wA alh 1?0b?7ozHA-=|sS0VŹڢh};k'[D{c׃qu3h{' L;# Ĺ %I@( b ɔ;W|`g>Z:c;裃OtQFyCxm;k,/ j!aq G& e2a!cXt s -3P㎝&L'\!ϯ*[./X9 wki* j©e +e2a!cx/,ivO.]N>`r6g+d, eTGё e2a)B=BnZ0 sh@3RfMRg$ >3|~P&x`rw=& =_%I7a~jmQ^cAHgF ʙQJTp X6@ j%=(uT|"RɃoG5>3!F2$ RƷ=)lZ.Ʊkquq3!0E6ڢ^qO}(=gBJQލR|@+{ hmA3' eBI@(v |,0޲1 kq0[H=cc|V؞\g& 2u %I7a+ |!; f2M9W\u7\@{PzsXhQތ2AK, R P@XL eQ aa·vl6c(Bkp)~mAǞ86S6}'Wye[g 뀗>iK@|~oFGe/ɢ|#0]{ 2wjh]YzRBmp}oT>@枇 ]:c%2/ڳ~1V:ob.}]cFn[)m|ǚW'}}xW}{߷} D@omD^J[n{Q7)3G$qnt<VO6|%a@whadF@zn6t/:97L^!/= ^@d7t3s39IJeG~*4XJ?|le'Pb@vh?bB7kr/#Hn v_cA?T`@6p'Hshn`>"%P sި1C}x-~0 נT@ $ e#X@X{ǷK Ϲgr?9P.0s~=̢>B~g#c!am7 >BI@X( @|iݛۆM,B+JBմK/#7w7^:S&Y|:û25fpzx9Umą $7 zǽ FOk& %a_Be_n!BдNܖ:7'`c37 !QVǸhqnAaqL>R>Y@S+)1u~os|ܫ9~A sSO78.uw@={6c{*Hc4gat[tI^.\B̌kW6r4}.eg}L9h;I, er3P߸ 1Hœ 2 ΝV}Y}uꞯZƒP@ث1uy'ZdeB =]څUTxlU@2[RpC=]5'9 {$f3)|(g+ %I7Wcc'lCƀY4awĦr&8e=¸>ۙ\T/ $׳BB ҏ JHSOP|$ Ŏ=ql<9n!ٞz F@E` hӷ!bCh79WB֌)P& $‚0Hؓ'9Z)k/R9Ju>\XuN[Rby)yCa!dq{ؓcN͹`?=>k$.ei$ +Gnls5Z4/l\~@ mtō5Q@( e*Bb{X@%KH;` J'EZiU95Jb6.U@( eBaZuZO"m>=f>_:<ӵE_` %2ۧ(̧OBQw}W\g sBjᑣVq\}c (ֽ ^4 ͙3'؏w̙v9m!]7dB{쎕c FrPBL@!@5[Ȗs?8(s!m@kx3 n ^BE:ujlll Q3 SO=% 2P&2pű@xGw͘Gpz:BFXwݺu׏9~WC ƀ1ZO1iѶP`N[TfsJV'|m ZɛCh@J7 , gs-m+/?yp<ӆ#dq,VX0W}9@c=dLD@( eBa.Wc]\!'׻PzBmyOt @<<}vshvg]C藰c>6 cl$lMx4[@( eBa' .zD-n%r& LX}\̺BXKw@9+qNa! >,L%WX s 1ɷ0&G =@眀{+dϋ2vB+/IEt>dedۍ7F 5ВQS֭ڒ1&Tn!`BեB$G6SclR5Y5+ɦO=9 &ˢʬ't.\V2!^%|*pfs7Ȣ*6p ')9v_:r}{X*u/C;swbkHmmm{4,6lذ{N%M[(w d j[M4<syr.f׍tãLlax' f%8OBOB '׈\Kz3V5 ggehÇRRտߒ)ݒ~Y\ba VF96νhv`x¬/^5@ Ps~0V(Z'=)4Jߘ&f<)}⩤OSKRf9eɶSN9V<Z(Sm!t@b\cg  جOO?>U =SO[a|)cn> xO^2&/ΛfaMBsCW, |zR@xʴ3O+*Q@س{~>}{+E˒6߿ޚ0ayaK.S{cL8lbPnQ}ч\XB?Wr^dR$ =_|IJv}e=<ձlJ}*eaO>tO=߫{T&6QdHjmm1ߛ e^KR/A u(qI;jԨǠ_~oUgN@(=uO=KrS U$2K LYa2R\ۅ z5wn]5L{@V=_*Goa}}tЫ$2 oJ"[]]ރ>5pK2*e|2d*Ke.>< o-5 2Y2P|%Iz+UP$IJ*<!U;B-0$I*ZL+[[ _:‘UH$I&~ιpl}!J$IRk}L?n-B$ISz2Yk֙w^"$Ij\~n{LaW^4"$IjaM>e2Ywr{MMGwAI$Z_ Ȫޖ=y I$Uȳ?jawq }RI$ X*(c3%\]*ժ[$IT:ʷ}/׽!8U1eoC=TG=aI$IJ]wÏ|[ 5l>3]wJ%I$)(? aN}%I$)SȜB-4Um DW^$IŜKy e`?/'M8 nM$I$u+V)iH^MEܩ,2sG!Nr J$IR4G\8C꾒퇏?o2YF<~x̜' AI$IrYʷLTc 1L_a)6( GAIENDB`docs/images/camera2/metadata/android.statistics.lensShadingMap/0040755 0000000 0000000 00000000000 13077405420 023606 5ustar000000000 0000000 docs/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png0100644 0000000 0000000 00000031267 13077405420 026746 0ustar000000000 0000000 PNG  IHDRRM7_sBIT|d pHYsaa?i IDATx|ud[K6$G̏\2\_-I~)问~~]]T~$nRMlLaˏ&bEcc~usy]p9Xm pxz%!.` q cKC\01%P͛7OC==J8; >\C{?s99m;pvRpJ*jذ~ZU4dZix`YV @Uei>z6lؠx}GZvZl q6۶==B*0(ebccl{5}tM:UBYq 7xzʀݻK\Phhh]Z 6{QZtUW^zzᇵ,ӣ>oQUTQM6 p8_?Tv@w}_W#FPPP|||M֑#G\?W^Tn]]uUYڵkWmk̙jѢ|||TV-9RG-rߔ9RM6UժU͛k„ -zuuWZ]sy ׵^+???uY_}UڿxլY|ξ>SN5jh_%I[lQxxU&EDD(==6oެ'xB-[T``|||Ըqco+<Ο]} Pץ5r +W$k}.t]q͝;W#G飺u꧟~Ҝ9stR_^۲ez_Uwu:tH/Vǎ~o,YjoV+W$edd]vVxx^j׮]?q\pe˖W^V:uȑ#[o9]Pgѧ~>}(,,LW֜9sO??wkQ!!!ݻrrrvZM8Q)))Zz SNر2224j(u|oڴIBBB4rH룏>R׮]7ߨI&=xڷo={s #eR\dջwo5J֭S||vܩɓ'{;m۶iҥڵk[s͞=[/wܡ=zԩSڸqjٲeڸq"㏵|rW]t7|>H)))ꫯԸqKz<P*Xe[eO0?~=~x{̘1vǎmaGFFǏwwޱ-˲9Vhhh6lmY^o>pWZe{yyw}K젠 ^n322:uصjղsss ?޶,ˮZ}v} d[eۦMf[eO6L'Nsrr.:{ddmYu">|? {-ܞo-˲7lϮ]=?o[e/\i{ttmYSO9mߴim[e9ֹsgp8mKII)\_N͜9Ӷ,5j(۲,{رN۷nj_uUŞ| քf͚Own[e_s5{ȑ#m˲O>i{zz}")x,'O.eIIIN]X\J8M8Q'NԩSn:_~u9|MkԩnҥzK*;;]vSHHm_yeffjժUE}'ԬY3mђ_9Tr9 ^+{366Vu-x"IRÆ =SO=%I ik4aiFȣ)SNEEEi?C ,е^^xrz疤Acǎ,pVZiN2d$i֭NիW쫦w9k׮ٳӶ4V^~-"eԩS5vX/?_-5ׯ/ruiOjݺe?--H(I?,I3uM;vTӦM]sȐ!JHHmݦO;wV\'IǏ״iӔ~IN8?:~A999j۶sΗYZR%]wuN-\:tМ9s.ҙ(>_=//O3g… wرc:}t]+pcǎڵkRSSU^=b@)㣶m?Vݺuk`\ÇK,KǏ/Z蒏_j"*U:󟮳C^z &(99Y~3~g5zDM2Eoz-Iglҥeϗ.]hƍjѢ5j[m+..N'O,}%@Z.x\`޳gعϷr_myyyN ŋ+((Ho@m[SNu92wϲ7at%PTZU77|-[nߊ=eY:zhoRd 4iD .ԩSuV\R׿cOÇ1z쩞={*''GׯWbb|My˥OqF >\sumEy]3,x9\q5\^6mڤŋ[nZ|l֫z}/<_|4\s ]jժi޽E:uJEWk߾l֗_~ifso^vsyyyuzg`Iŋ/>>> Ք)SɓZ|eTq7+r_|Qd[pp|||cǎw*Uo-:۵k׺Ssp KGi#fNڵkeYZjetV".2`ڽ{*W\ 1Źە^ /boZxG1c^x?Ck֬#""3f7о+f-[k͂W\yCϗ_~sQ}\UfիW;mߵk{"T cǎNuӦM?er1޺ow֭w۹/瘒aJJJr6}tڵK|=`Jk ^<~;-_\e_V5.z~Z+VPDD jժ髯ݻuwyoܹsf͚),,L7tgYF]wz\*U;S Q˖-뫽{jƍJKKӁ.;5k,uQ7xU;wjҥRx≋WFF:trڼyRRRT~}w}5$[5?Om߾]_g%%%W^Zpa}^~eZJSNզMԡC߿_|õdɒbʫ3yd^Z6lؠkZhõx"^ڶm:?VԡCeff*99YM4QڵHEFF*((HJNNV``x~$@E\eYNyyyf͚У>]qŋ+..N .W_ݻkѢE-ve˖2eRRR駟ꫯVڵuj.?ߢE mݺU?X)kV6m4i$^83h ꫯyfnݺ4hq)!!A6mʕ+p8T~}7NO>˞WWرck͚5 RllƌSl\jݺuztRmڴIM4[o:W>Y+=Zl6lؠ&M7ߔ/^538-YD/-[_[5n85m۷F_|QIII\W^yE522ɲMPa7NVXQm=ټyy]gtp\Qd۶m믫z~n$kq@nVtMj֬?!.^w8q (֨Qd-ZHGյ^={駟VN<=L^ veVVVX \wrrr{ny睪^W.WX!C(a|-. >Vj ^sd c͡?!(%}sVߝ ,])lۋJk%5g߇~l[R\DʷQD01%!.Kjk%5O=ⲔO 5ƚ'XVOP01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` qYJhǕ<]+Q.۷o-\8Y;w.QvZܹDTScݡPhJNwbcsi߮][jŊڻwNH^TXX7O]T*::Rޕ"Imۥ}~zTIf+,QļVnНccݡPҪWFwK _K\\r ׶m3fzP^^c5hPg7N]T(^z~JjĈ]޷O'Ӷի7)-m|rzE`ݡP*0p38bD]h-Z-1qv횣;{_2K/UnMSccݡP.qԩ:zO_ Ⲃhذի;vyzT ;4JeYr4~ 5n\[S~J ~-^xyyc'4u|O uƚCIIJ=ZIN8!C()i*=.l=䓪S|||ԪU+ X9sbRÆ*#㐧GBCIc͡$=Lk""^TR&xCY.˾}jӦMzWոqc͟?_ӧ5p@w͈+0k <. 6^k<=*Jk%iJL_7\lV\ hΝ;+==]<  K8Kٳc4|xo=D-XqPAPXsVXXkըQU8r &$$_w(##C6l0>.߬Y/hz街qPAPXs( :wn_VV1OR*\-ZHvءۛ }%IM_=ٳc4th"o_$iڴgs?;um ydRS,2uƚCI k#?#Ijڴ $%%mRn=1 EAAڷ/K0Ni4>jаa]׿6oqya5jԨۋOuζjWO]a͘1V_/7VMwmۺ>ڻIm+**BQQNܽ;C9oƺCIc͘͡?Yg\57B{f,\;A>koƍ?WJNGcm")㜭y.o.fvƍըQ#-[iUN+z oٲEmڴD@U==*>*i6oެ֭[_._sX쫓G)qy-_om6IR͋ ql}N͛:un3>ݻkԨQ:v옂`}駚?E.z>c7N:r䈂pB{e%ťNSka|_#!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\0O% 3'\'\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\0,|5y8%'/Pf6SlS.[?┒^4th7OO'}TVoNVޤzzZVe`YW RwG~(|ӧOkwծ];ժU(gXs(i KI:p KrPu45VG\0yol߶m$Yf%=9J ^ZڱcG)5KFȑ#El ,Pαi^^^zX M:zgգGըQCCqqq T,Ks($ UF!OTj\R\feeiSdd$pÇPd{ÇH(XsY^w&(1q)U. 4Я*i̙㖡=۶m-Rd{-$I۷o/Pα)ghzZ :}%l'I&j۶m6/// a}dY>?u*??__-Ijڴ $I9MIDAT%%RnnfϞCQPP{ۗQon$['r$I}TeLXX/Ijڴ'IJJJsСCt'I;wyd>`:tFzD7twǃҏ5"??J6 R~]%IIIk{RghpEh߾3Q6EEEhO}Nv[c<Km9[O eUYOS͘?Rm߿l֍7ަ{3pXr8E> gm=zF.۶}CI> 13f̺j޽r8_xyyy֭^}5oF={ޥkz `͘͡1V_/`uS\s}wb\^d۶"tݻ3Ԩʲ$9_l'$e~;++K5kԄ -[M6(a==֞DA\n޼Y[_x901%7,_\Ǐ.Iڱc>CIRxx||x8@Euq#(==]ҙoYh-Z$˲ze%eZZ;@9501%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\J?E? P(@ PaKKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\Ⲕɓ+9y23U~'ϥ}vm+&jy:q#>{Qaam<5:??M+3s7*66ڥ} 'k%^;(>~yje94_ݏ,WFwK _Kl۵}m[ƌ=b3X ٍS^ZEGGۻR$I 駇Jʚ4iULjfm<_ 960JϯgٮmٲEmڴIU0u໊[I^1ڵkv: OXdxzr! \4iE_i[ZՕTIz5* 4_]gG%͛պu ޗW.˺c:uZGP~+?*޹Ot@~֭ij,c94_݃,,˒C_qښ:O a:WvQPAPx~J4^=z$8qRCLQRFOKo?S{zT9_/\j__~Qjt뭷*66{gC=:wn_VV1Orj֬4|xo=KO8Xs( x~uvEo9zl٢nݺg k#?#Ijڴ $%%mRn=1 EAAڷ/K0Ni4>jаa]׿6oŨB#_IRӦAׯ$))irsOj ۗ)I6EEEhO}Nv[c<KL`͡^WGVNNƍw{m{,ΕB1aկc۶տAmGh,99gu[G 5ߎkƟիD%'oУAY1cXկuMws޽\w%իlVTT"{w5r`͡za~!I_7襗^#o =* %^zI/ra 2..cǺc&Q&MR\\bbb㮙PF)Sh SϞ=~zovlq9.eY!eԩSƇ@r\snq8%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\0,lO ƶxzT09xϯG\Zίk01%oٲmw<˓me OPFmCIb]9'.ϯ'[s{-.ou `@@Ú2.ϯkСcٶ{^WҊ+ԠA(JKKӝwީի_nKT<01%!.Kl=䓪S|||ԪU+ Xvv}YC5jԐP\\B9j* 6L7֭[[lh(RSSW ==ZE\"}U||&LdmVԂ <=ʩ,͞=[yyy$YP͜9S{ј1c|rM6M߮OrѣW^y-_\jР~K\⣈Je˖W^Z` P;Ԏ;g9]saըQC&LPllA9uAլYiըQ#5o\}&CEӾ}{edd(==ӣ;J) i< mذC( 熥$)88XDU۾B#.K۷+88ȫ-Z$رc=zT[lQf<= 1۶C7Њ+O{zrd/%>FPx;GGVNNƍQP5Jf͒$yyy5j(OU>{ァӧUVظq4rHl Y|?]ҙO&(KNxx|||<9ʙ)Sh SϞ=~zovMjȑZڶm뮻NYYYZh>=\v|z)rq7N|9`׽P5lذC-*K˲zyr<3/\U˲t)Ll޼yzw~W_/1b %p%!.` q cKC\01%?RLamIENDB`docs/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png0100644 0000000 0000000 00000036123 13077405420 027417 0ustar000000000 0000000 PNG  IHDRRM7_sBIT|d pHYsaa?i IDATxy|Mw%=]V-%E-UUK#ҩ4*5cvJfhQRec)Eb-ZϕDɕ|<<|r?O}su1F.Op kp kp kp kp xXTT|||tAOtx_~%C͚5K.K}Q&Uvg=_\.x\Y4xĎ;K/{U…7o^q1bvÇo t9HDž =zm-8|A:;d\"O3f|||dɒ4$(QBSLQDDx9SF *(_|ӧO< zU\9(88X;vԆ |$jР ( ծ][N/R>}o>= ֭Ee?Μ9nݺtuGUŕ/_>*UJ<>6_J/_>8q"3F.KxFQFriʕ?ׯ/9ן_ p;'ԩS6l*V(___M6ꫯֵk.\.mիݦ :T.K_uط~nݺt)E͚55p@%%%-뮻̙3ӽͷٯO?~)444幬Ry+&???ժU糦ugn޼YڵSBf͚o:|飢E>>[nfȐ!7{\x1]^^^CfС3sISR%8iРyWM~L2J(aBBB{=8q\fԨQnԩcRoM|޽>|yM6mL|̹sRmC.]8f>m<_… oooөS'3l03p@ӡC?~}߭=&&8cMDD1b0`i֬)^ۼ{6㘮] 'x¼+vqӬYT 3e˖5={4C 1/Uq&))mٔ+W.eMDD5?qDEE-ӬY3r8}ϴj <}ԩS}3=#y.]FqL&Mիy衇MXXqTV\rm}O?)V֭yW̠AL&M8RJ_M;t`Mn̈#L۶m8&((ڵ+]\p,Ӽys8okpYfMs i.]2?qv!b/nSƓߤ 䶓|y'8?OO7x1.]j1=PL2& 1f׮]s=ȑ#nӖ/_nLNR[nuY8c}є?|,X0U ѣq|75///tTo1=]LL޼y޽{SÍ8O{G]wejԨa6m2~IrLVR d1_|EZN:koq̙33ׇˬx&Md1&MJUͅ ~Ν;q̖-[RMw19\)S8p e<)))%[m={Ç7㘹s纍'/6ap8vq̀k1Æ s߲eɗ/mKooojժ+W|8c (`>z45>>>^Mޖǧ㘘i}Ӳetm p=>GIN5mΝ5jۿ?0 tў={ /QFn. )[lx%I˖-KtfϞ hԨQnשSG={IiӦz'+///Z7͙3G JQ3ؒԣG5i$gqRUw6) [lq/UTڿ=kٲڶm6|Ɗ+ C-)ߝ6~%;w{9sFW\I~5kjrI&ڳg6oެRJ.e+;wԩSN0>>^e˖=n<'X7oMq;wm1UMkxoFo%yMnْ\o}u\__Ν?XƍҢEt) 4b>_Kk乺+|MחŋK#i׏_aH%T|y\RƘ#}-[TB'O-_\mڴU`AիW/eujժU3f͛hIW/5j{Tu$މY:*UJ4j(Ʀdɒ2d{߭sZx&L3f݂zFtZh׫z޽)"oooc/̟n7rkǾ<~sui.]r֭>ss)c4qD1=uYI&ZrVXnn%ypBo>?#f``ǹ镺Ş>}ZO:}}}յkW͜9S˖-S6mRB'_JY fɵWۢE M6M7nU|ԯ__˖-Çk.=éAZh.] 6(66VSLI ;͛7w?+RmlfPR%͝;W/_֖-[W_iʔ)z ii۶ڶm .hڵZx{=kN~*Ut[}Z~"""R]}T,$?gGMs}y o66lؠ?\ZҒ%K2iFZ~ﹼYns.e"""~ Jt_re*THk֬IuRJȑ#ilذ1ޞd!>?%Kf͚QFKRJ-[5RNH֪U+IҥKzjs*[lNsMfհaCEEEi2/H5_rep _V^^^] 9sH> W͛7ׄ 4|p]xQK,횒owӥKTV\jr͛u̙Tӯm+Ww-RرcG`)]n$]|YW8UZ.eBCCSތz衛^qԩ cǎ ;s75k֤\^xA֋/ÙM6Յ uTӞyy{{kРA)]~ӪU\gr_._Q>_Y[zҙ3g6mݚ6ٞ={4tTɓ'?nSpaӺuklٲ.?8cTڴic\.ySMmcTb ,hMJK/vdG;vlט[osf֭3 05k4TP7]7P7Ƙ>tTPϟ(PT^ݼknFDDeS'y>0={4!!!TVͼ&))) ntӷo_SHkjժe>#_i~ެdeʔ1e˖M5~Aӻwoǎ67ɓ'DV=qnvIϚ2eS|y3bs4{Ę Spa裏1]1ŸrnˠA4yd޽Cz''h߾}}0r#FhܸqZt|AOf͚}j֬Y}N -s xаa秷zӥ <ٳgg%XRJ5uVMiF7>_tzY@Ӽ2-\&Ue$=zqI%<]rzY'w'QҾ-dZLK5exސ9d5z@gQ[!\%!\ީ {:=O2r1=FG5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXC5KXCCk;5VG:Id}#;~v/ܭj݊\5;YCV2\(X;wo-[ I2ƤkW_O^>Zaχ)Hպ6ިe+gf;d5zY|y<]8^A̓$IկSt/a`?umlņڻhZswj=8r 8ol|I:r;EK* 9}F!spK )RKi.}F!s.s///9CUgOt9%;d5zYK[ٳg5p@Wjҧ~YqAjTzC?tI;d5zY ]#hÆ z7UbE͞=[ݻwו+WԽ{̪צC=ZjA.A!sjͥ;\~ꫯ4guMԬY3k֭\.>eL#OjNO\CV[Kw\`ԵkW>}СCZnp6MG1O+zqA.A!sjKm۶rʩNV^]}v5lnu\X0+/@T%"IYċ9]1T G$IORߎ}5ڶ{v_:/^ͻ6g ۠9d5z.s;\8qB˗O52=M %'0cʍJUZoڪ*cu(Grrݫ}2ƨoǾ۱:ڧS@2YCVn͜4/7 ^NIwUXQ˗ח_~6~ahܸq:thMTN$+sH;7vڷ7\ytɓ);\֨QC;vЕ+WƷn*IV;\vYgϞg͚w}7YE/ Ӄ>̙3 ՜9s[g 7_҈#4rH?Wg{nEVhLٝƏ9:4]]!k_8qRI I #7+vi;I92}='IEg豣Zj޼y&V_#+XHs-k7::}XLau2py .;-$cҵ+'FOnjSKgoT岕3ldsZ-Xߕ/S^=:PD,вȽտy{{k\޼yԼysKء=%KԴi,Xp`o_^ZZ)}=[5h lgyF.iѬGftH[x5$ TNҽltqVhsVkE*pH߭\Rk$ծ^[;uϔ+(Z_ܓO>UQF'I믵yf֛j԰QԌ-X_빀@kz歞6xb`OV~b#ـ8`)IGcUh [e!ss[6= HN;iΝ)R\VUxq%"#d\t%BE92(RV==] XQZ5}wƷn*IZjV\qytW]zxwEMb˺cx.#gjl@'OO ꒐KļֵZK_<^z)f}sdٳg5dnZERTTTf QF=|% r}usGl zpyqM>].]RΝ%qn՝nk3Zr'N(000x؉'$֦ݛ>Fꮯ|OOtYw 2e_~Q\\ƍY5p9s<]XuVըQ#x%I۶m꒐Kq RE<]/uwiMSzzӊ^r|J*^z)c^^^٫֮]Gz:&ͪ5/g3֒e= !@>N=aIR*Ҳ$)fu/&jzt WhP%M$MfNiU:7?EjԨQi~MTNY찧 @D{rƍ]-&p k&,YDΝӯ*Iھ}ϟ/Ij׮|}}Vl#gU||3o<͛7Oh޽*U"=d8\ݻ73@9p kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp kp k& tE~t5?+G.` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .PxNѯ*i}Fei掟 wڽpGG+Dh&W__:樒v$is뻐b!*q:v$)Sx^I- ;'VGURBFΞ+D;N*)!I]9 GC V[ H1ZWGVa|7R7rʙY6ص[+_zċ:wݽ>ߠF [  VznI{Ly|~ m!^AU\@둁[Rk\սӭ{e\fdh$9~DT%lQmtY?r9F22(RV==] I -.7^zCtY`Mnx.#gj쉞.Ъ47fv)__=tCoi-<]ay?p|rEGGk͚5:x .ujȑ]vfֈ?q}lG?C?tI^KW-Ux=muhA W,Pe`Gnϥc_נAdM4IǎS 54|ūr}}cIR=\ dܲK˩ShѢncaaa*_Ǝ͛[/x8BOt9-qA.}`)I\?nkpG{w[vZW#=O֦MԪU+[:aIR*Ҳ$)fu/&jzt WhP%' j3m6Wu^tQwmA4L~ wKk}3]*T Gʕ,'I['$s?%IM4ѰKWaZfqFnZsKk=a WhP%W_s1@6~.s9|A^4o<]Vjri&թSG/ KN`84G^[*-7$N7ƨ\r:pf>CS~N^TRi~whw,u g=]@{n&}ײ>cg(Sxɒv$zWtuRJiܸqZdUL=3fˑ/T5gu-eM6ھ}/yN8"EhԨQ9rAu1-Zmܹs*_Ue˖y26 6ԡCRrb P׮]Ciݺu g"+,%_+WVBB*Bnx```tȉ{9]pA#Ft) iӦIE pU91O4uTժU 1bz);vL ./D :ӥ8;DPPPG'O<2r(3Fcǎճ>rÕ,YR%K$IM߾}UHOpFڱc\6uVIRj 3g(44Tsѿo͞=[#,YDΝӯ* i׮|}}=Yr &_WXXڶmk׺MoР*CNSO`W+Ǐk޼y4dN;Dr91B}N<ʕ+W_c=Ґ-[6&ŽqݻWJdya7oo&:˗/{*df҇~;vԩSʟ?^O=zty9p%!\%!\%!\%!\%?S:U*Y3IENDB`docs/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png0100644 0000000 0000000 00000036737 13077405420 027444 0ustar000000000 0000000 PNG  IHDRRM7_sBIT|d pHYsaa?i IDATx}|lcq\͐o3%eEuҕ~uٗo*7JR+"S.RDRҌ C v~f3gǶv-?>g|Xm pxKC1KC1KC1KC1K&5i$ǀp8~VBCC=V~лロm"""ѣG+!!ARݻk׮]֭K -_oH҄ 4eU^]}4imxM>]^0>}ZSDD*Wr VZ)44Toz)o7(QB%Jv@ƕKxo)S_+W1XJRJohYN9;wNǏW͚5UhQ 8еN||}QU^] V׮]?丯t_߮%Jtqƚ9sf+}o>UppԴiS}gz>/^'NwW]磏>R6mTdIAzt_zڴi#өҥK\˛oz) @*Uң>z]>Ä 8P*To{=-[hѢ^nժ e|׮]r8߿k,55U&MRzTD /^\z޽{_Ն r}Wt_={V5j J*ҥV^VSO=[oUŊSɒ%UfM_{l۶M:uRRt:նm[}KHHɓժU+/_^EUHH_~5veO֨QTJf͚>}ze۶f̘uc)555g$%%iРA*_Nõ~zIqV^_9q^z%u]T-e˪k׮ڴi5zHe˖U``6m };r {^zf͚O=z֭[u*88Xʕ$ĨC:v:v_Gѧ~֭[kɒ%رqΟ?O_|ԩ|PZv{1m޼Y~ũE S>Hݺuӗ_~˭/$|z饗TlY=Cr:ZbƎh^Z~~~/^޽{_{V 7(<<\_rO<7xC+V԰a뫥KUhQ%SJJUD =m}7ߨC'Oᅲ$Y&~3t1,DFFSxx:v(___8p@_}6oެƍgyVZI n:W}諨(-ZH 4Pjƍ/\՜>}Zڷo:t蠮]ʶm۷O˗/W޽Uz,lٲEӧOWxx~aO>Qv?vڮukM>]wu7n,ө={hZl6nܘ'sС:N:WK,ѳ>3ghĉY1b+$$DÆ -[^*R5+?~\ZR%Էo_h…Ԇ 4|p8qB]vչspB[~Zhz_~Eնm[w}[o>-]T-[wZcǎu*Ucǎ?V~tA=ӹ:l"""l˲w}o۶mYNIIɲvXXhoܸ1˲;$$._0amY=rH;##5~{eY~-˲-˲'OeV-˲;vTV.VX}gڰamYj9r5nwɶ,˞2ekɓvPP]H{֭YkȑeY\7n-˲k֬i;v5flҵwe>7/\pCdzvZ۲,gq-_ܶ,СmYw^ײnݺٖemO?d[ew=Z/?LIIIeYv۶msuY|x$ԩS;&&v:vdddw}׶,~WZն,ԩS$TRvɒ%ϻƿk۲,vvjjkܹswq?W>'mY]D K.ٳg]˾5555g\\]|yvW޽ƺ~Gnp-Kx]:ul˲UVe[k.{„ Y̙eptl駶eYѣskf[eX¶' ;$$$cla5W6UT˔)s't۲,;,,,!wɶcW^5ؖe ȶ~jj]dlrȐ!eYܹsmW_]I?KxIKK&MFi-Z޴imY=k,۶/~/K*ez뭮ug۲,o߾no۶gW\ yW'N-˲[nvWZlmYs麙;ȶ󶯯ݬY3ݹsgNOOw]O/^+\:TTTmYsNXfo 9(VXp}v8vlllBCC G}Զ,>p@˶ĉm˲I&ZxY7ݻwkYZj~JK^l)l/yIүϽޫ={رc }ڽ{wn-O*W.BJJ$)(((?,qZj)$$DӉ'TD =m۶Ͷ~%tm믿2#˲r&ܪVox--[jJMMUɒ%vZ~ULYFCULLRSSէOc֫WO5҂ tuEZRӦMJp 9r$ǝ)/xgQFٳZn͛+00Э:NhڴiձcGjJvUM66rرcٖXB?(%%Eee)999--&{TR9'ƹ͜nhѢUoϹZjtfs8*WΜ9jժeۦbŊڲeK7jƌڴi9seY~AUT)X*UTjluwjҤIڶm[ ^W\9޽;»u릌 I= u'eE]ue?Ȳ-J,c3f_ez71/_>*TЁ%J鹹\k__C⟹ZO||xO[N֭S֭}vZn߲]vs8Zf&Oŋz*Q S222nhļ꫏>HӧOׇ~KZx]ŵyfM0A˖-Stt$L21bƎ-T] .d1cF o^UTQ``,Ғ%KO?ey^V{}tҹZ.d T&)áui9j2 L;Kx]֭~z]6]-p]K/e˖snߣĢ$˲tgwСlo,˵^s|Ç_uv'==]ɪRGtՂ;sz\o`YzΝ;'۶]]vO?i͚59~RNR+W^޽{~z[zuq͝;7[ǎSŊsu9_&LЄ Zsռyo>}W!!!z%]|ڵk5sLM8Q9tM8Q*TPLLLqlxݕLNpRRRܾ"lڸq~AzketJ{j-" 0@>>>Zxc[l)I^:uTRڴiSyGUTÇsٸqcٶcHP׉1sZOMMնm۲&MȶOP6lp*;r{<ŗaK(kjڵr:["2C7aÆW@4h _^NS~iuu…ïW*UR߾}j*믿suգ> ]JMMUxxx`y)K^Rfo4͛]K֭-Xfdd\sʬ+...x_F։‹p s=gϪcǎW{2'FIڵ4sL\2u6m7G=:\iii?tG?M6:s挶oߞm٠A$I?p႞~iٶƻv[nE~nݚ&N'NdGܼߡC}ڰaC9ZlgyQ]\R;wT6m4j(NSfR޽զM[˗׆ sNqٮꆇogϞҥKUtiUPGFx2kN˗/ב#GSwqr۶mS=Լysծ][+Vԑ#GtR]pAGζ̗k۷oC龊WƍՠA5h@+W։'|r%&&SbŮx_|FpլYSe˖U||.]*r8z5m45h@]tѹsn:?~<tw֬YT^=C~~~t-bŊq19RԸqcW]7nԮ]\oIÆ ߫I&j߾??X'NЋ/Ik뷧/؏?ݰaCdɒl>k׮ly睶&%%cƌׯoŊkժe˞?~O2vv\sUTnӦ /M2f9۝.wiTRv6m… ֭[ŋSN2GKuv``dwk0 TD|MN:vѢE퐐GSSSjժz +|پ}km۶eY`۲,H"٦}{9UVvEڕ+W^;:::~222,1{?nO<پ뮻쐐hѢvŊ툈{…nսk.6mj)S.Zj޴iSu3"59Izz+uֵ *QQQܹsmÑm*kĉma_>xFFꫯڵkζbŊٍ7zZ]ܹsnv:v2e=z;vdСC>h-[5ׂ >m{>mȑz׵w'AoԶm[9rM_խު>}h.-Cwy֮]RPp%p3f/zBm ý] 111ۛN>'|RԳgOo +WNF /c*$$%:?>s͙3ȂW_Ղ Zfx,\*/R%I*"Ps7;K"2. )ȇNIQn͇pdi:yCn2l[V =wC8\lY%ܲu.JwTD0p c0py*PskxJ]@GIY%yC^9=+4%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\%!\MԴ)h%nJTt1ޭmCʅ^Ѻ薣JߕnQ9vZJ|r|C^s85i~3Z%]ㇺs=ꡅjﲽ:.۫ySX0WԴ=9Z$*}iսkvZ5y=ӟ֡y?TdHW.oRkC%_.$ٶֶ5P}v6M+ZݿW-hkԑ7~w;RRϭ]=+H85ߪ:u_mz| gqTyiIRP 5m^Kk>\s3gh-_, y-PJG\깒Ad%O2,VO{R1h(Tϥ+!EiцEYƖoY]Ch+%|y|\;}s+$N>IUl%Se3{BNUzF %V%LG6g=d-Re !Rvۥ,K>U }'VZzmk.7[ P;:!Ϩuֺ+.o'zm>'zxΊ +ԡQI鳧jŖ^摫py)עEtQծ][cƌQ޽=Up@%$$3^6{&ǬҀhؔa|A!ն~[;uL'`P}rǎSN 4$ܹS-[4[]!&R@;K֬$jΦiي8޵mz+W$5mTNK>Y$u3l>Y'W"^Cf-_KK})gS/\X]lw6\q)Ja]xfA]i9ڍ@uIDATwZoz̳j _l)gQ\*u3RBi4ي+JaC|疌]msJ9Aտ]Qn@AvLIIQ5(I}xKV ^33'TՊU%]Ċ^+lVvu9,G?z#׿mֈ~#4'IJHJPFF&>6Q˶mٷGgワw }6sLUpYKs]r8\6e۶uA]ey} Tks I36SU^szWK=7$_9ˑe.̍lTV=hGU"q\[~ݢΓ;+zk8-]oonZjFϳ:tH!!!z4zhxLL4i"U,$ @TSmi֭jܸ5uҥKxuѣ( 6Ԯ]e|풤뛭 {:u/^e|ܹ Q-% k:q´`}?>s wGcǎuQթSG .<*\:Nkz.` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` z|{|/P(wί+*W.` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` .` & pjڰi~)Z&*}mֶ=衅j:}J{ռmݵUl_˧-7}HNM;M =Q{}R!DLzE>Y*=>]Q<\1;өiӧ)zU~!]ǻsTLywuImظAW#\ޤKkhӒoHlvkۧWH{ghN:ߛW-ik#` wVjT*lVYmQxkСӒ%"EhՊ?]*11Q+WM6,WvY8$)Dt].Y؅zדaY?sbnoqq*]R!}֫| O>K\\J]깠 ~ =h*Zկ__?s۷Kի%/>>>zg;:y^[ZeYw+h:gZ7hK ѣGg.]:KB!5g Nɓm6JIIф 4aOՇdY+!9! s~V}JqԥU-۸,/ _zuzY<99Ygս{wI~bӳԯ}? 6P77_~ Ij^'Klc)))y] ίW+ժUӱc$]}=R̘=jDkno ۷aÆ4h IڱcG^B]z6k, a/ӼUrm{K6O|ڵkYf1{6oެD/VzJAd-FD63%IuU϶=%I+6Pڹ45[QD)OKf<>C:Ҝs#vZmz̳jo$I֘~cO?i(Ev51kܾ̏%2"R@wgK}f4ي?Ja-6sUKTϜ$}⓼< #r:*^Rի=/܊K=lEEE)z/ܜ9sȈGgu dj֬w$[Jb0=.$8Az9SUUtJq;{םd۶Ip8Y.wnYmkPAqPwxj!IJHIP'*dl֞=?g^;PTf0SU+]wR.]:p@!Ñm.̏o۶5b0Bm˯_U/^ԫץ .sd]wynMq^uԽՆ u88^U֒fORvrrʖ-'9111jҤԘp<P:P(v(,2֭[ոqk$0p c0&oYrMѫ ?޽2ehλsNj `8z&\*XC["ImۭmzZEhkH[oU:,\pPw+sw5P}v6M+֬ն(5tPiɒ\"EzjEDDǟP.]+զMO|z,PJG$ ҐnC޶˓]|<9*X=I 0S麗 ~߭ߴ^$5nX}H(XT:Ri{nW[ᅲ$}W6Mq[{fo_=+eYZƗɇu0*d,prwYeR[nڽ{+XJRFF0_͛7WMg. АPU)_E;R6}vIRz$B_#\>>>zg;:y^#tlcKPp~͙r͚5߿jժ%өJ*[nd}Aeqo+/?$x$=ίWv|뭷~9R+WԌ3o]֭d>K:.IIIQPPP̱. ׫soʖ-e,22R5jԩSW&4{l oO ]}v5l0x $I;vPHp~6\^,֩SGFYp 2Lv9`ܧK>UڵլY3ט=O7oVbbCAEijԨQe111jҤTL"YÃg.۫Jqٶ]zg;]Fywpo{7UJWu yErt׿֯_wm{UUz.8w漣(g*S8];wV``~G7 ȟ8^}Ԗ]1xA)i֭jڍwrܸq2e|M=#ٖem $H"q7w%}ږv.kI&iʔ):ujSI\_cƌDMȧr.yM4IƍӸqv]{|*Cs[nioq~>bݙ3~ell .N +'u۷oZjuu,۶=ߓj*UVM@ZZbccu=(88z,\ =0p c0p c7SN'THHԨQ#}G. ةS3ϨC*S&MPYFWZt:UR%uM111. ԶmԩS'UZU*]5|oV`.o"=zмy4qDEGGYfӧ,XP@%''k:w.I,U {뭷~9R+WԌ3o]֭vy(RSSUJ Zr͛jժ顇Ҕ)S]^TD7?\;wւ Իwo=ܣ;wjr8[2ehĉ?~Aef?TF կ___~*CaӲeK%$$(..ۥ8Ē%KTxq+KL+$9NթSG^Uҥ*,7;vN:ٮN6h@sNoիWۥm[:riժUz駽]VDdIFƃ\ 1bΜ9cz`Ç׬Y$I>>>?Ç{p q?ԛoFy`cǎ?$-[LO=4zhoV.oKѣG] 4iLSGv9(*Wʕ+K"##%]fРA*S7K+p&ѰaCڵKYƷo.I_74ik̘1.Pf͔XoR.oݻwשSx,sUHHZh^&MҸq4n8oBjݺuQXXK)pxY&k:q´`}?>[cV\?C'Otqf?r:u꤀o_ք {W7oβoRe(~a,YR͚5Sr唜E?3ѽ{wntfϞ{quN;턖-[bwƙg_]C?~o~M6ᅬ/={D˖-;`xrG}tt <'F=+;v,;DrJ~~Ѻukxxg8=3\s >9~79眃o}[Q{3o&g#<35g<8蠃жmۨ'Nām[ƍ0}tuQС:ws9k֬#D]]A]]ڶmu֑8\wމ+K\lƎ]w-[N;턳: o˗/G]]>7|39DW\}:k,?>샎;M6w}q5`ƍ$_l0aAN;K -[{UVѣ~%Cf0`CE]]7 8SG p:B6mڄ {Zl_[opt6mڠG81}tNkq}aРA֭ZnwCţ>*_~=.rZ{nA(;a|}ѦMt~8z!?/ۣcǎ:t(.\(mۢk׮8{ u-ZÆ K~=e+W;@~ЦMO: k;#.Oƞ{vڡ]vw z-|kкukO~/R駟[b„ rnk(#9cʕ8C>[o'x?>FΝ;35k0qDwqx7뮻FzΝns  m7?~ ,;??ТE Dߎg}FB}}=LO>I'>'p.",X?0V^oz2d`̙]1c`ƍXp!:(ڵkK/ᨣB˖-V\\v`ܸqLs=ѣGc֭8ЧOZ _0yd̚5 p};-23Ƣi[ơ]~˗Cȑ#a̟?]wf͚3gYfJ_l0m4aРAR=pg`8ѡCL<7t>h ԩStR .fΜ<Ot~i'x"ve{3Oo!F^z <~1cc8sѺuk{X`N]O7x#v}w~ر#},Z9Bi& 6 |F͛'slذ!Z⋱裏F'`8sl27Iǐ!Cyf=}ŋQ__/BO?~??OxWdɒ0w\ 6 A`ݻ7,YOS̞='x"=XӦMÝwމ-[஻Jf͚aРAyc7nڿ0od ~_G|nk֬ :uiK. ڵkp23&`ztSN w~G[WW 2$cŊBݿ/X0iҤuY16nl2{ef c^~QG >W_}'h֬YD1?)gcw][|yТEo߾~1cFЬYओNo;Xzu"?cAgB}Ν;Ka.O?M|mX0bĈ`ƍ?8ԩSбcoI:Zh[FcO?3~hu1Xti"3 c>]۲eKЧO.xw}Զ ܫWߏon:~ܦM}7hٲe'q֭g0Ƃ^h[n;3s'W;hժ7?\f}ݹwމD0n޼9nc9lNZjl޼9vࡇ,X $вet֟UVEl¥7>'K4nݺ%y)c "J/*W_}5vus|Aa]pygAꫯ{  z衑%\0Ƃ F|֯\vmc, LXkioaڵkpg?O.X~}A?Y`O? c\\X"`̙3<_'Omذ!رcн{w~{c-[&^X>ЯN:)h֬YbqSOq_|E ?p8|];HnA]]脋 gϟ0Ƃ>?m|UWq>sGLB+-C8.\矯 h^|E!Q !VX4kL: 2$`I>lK(smKh۶m"Yf֭}]Nɓqw_իy(1O?4FZx1c֯_W_}ݺu-",vme˖i˼xbGcxᇱxbs9Z}Y@.뮻^p_vc xbq*u;ᮅI&O2&L3gb}̙34ٲe0~x|Wh۶-fΜ _9ŋsۍu˖-Kl׊n͜9?яꫯb͚5[_}Ə'xo֭[ =O>ХK㼌1xA>,֪U+z꩸{1ewq-[ GNͬYs6>clݺoF,'cL۷o#GgO>~8>`Ih⬳ߎ~SOőGC9;vwIx=)0 7܀3f`ժUذaC"=|`^~eQWW; Ix&Kc4hYVXzjx+V$ =Q] ~m|܃]vpm(e DE ռys|7kǏǸqХK :=z@6mOŭފw?z\h޼9F[n#>$tŊ8#ѱcG4k oxx TEWmw>stAcǢK.h޼9>3?^zrժUXv-G.ñ|E\ 6oތkݻw/ ,7Ň~ [lիf0`4)B]~0=|ZT6"#0L^p)ݻc=Ĝ9si&̝;7zp#@-0mڴnm"%Kpc=܃^z 3f@>}iӦ>1rD;=SXhƎ/>rBBE} ;0O?4 j &MBnp'd;v֮]vyߪU+\}ոbܹ0a|A\2z gå^K/| ϟI&믿KEVoY&L1ci'N~*,G}$'k| Kdeދ+Wk!.\K~Gc=a]^֭M嫈j~)֮]C=#֭/̑ 5*svڡ_~Xt)}cpka,.Ν;cժU-[W^ Y 3 C ڵkq]w/m۶!3f$˳Bf̈́@t4':OO2OkXd &M}_OΙ3Nj"nG\1flܸ&MɓfyA!om.3<SLA޽1wh_֭FG}x7kY׿τĢmٲE8B8N͛7Kۺu+gf[{OT+VUгgOw{r%(e bv@6mhѢv7|K/4 #\ 7_|]ߴi~_'?Mp l? Kzu2!^x<#ҥ>Cocڴivs"ѷo_" Fc,cy睇N:kŢE[ 'ߎuq2}hm3+VW\Am>`_%J?f0aqG?B-0n8;]7m$$*2|?]_n֭[͛G[ŦM;B| ֬Yz Ap}fʔ){fCE߾}1w\bX"t5k{D=܃7|j;.{oŸyǏ#n݊/Ap,_o[G-^ÏcEq'bӦM5k>ssQ#<?p=_~=z4Zhgy;wƷ-y睇^z wuzc=+֬Yz ϽgLv.rL:wj*h# [<N; wѷo_,_O>$:tMEDH>c?4x`\s5O}J?~ _|w?plvq 'K.x1j(r!cvȑ#ѧOzXt)sN8( c1b9MmpQGah޼9o?ݺ@ûC>ׯ=| y̛7;#uO. u]_+>#\r%~~zqӧ v 7nĴiӰl29{qqSO)ݻcҥ2e N=TKC'kW^̙31|pc {/O<1z%K0}twqxggƘ1cp7bܸq={67|'O'88СCL2K,g|СC3+O-\D_WѺuks=x'qz!?r ڵk?4i Sbڵ3%wqy 4ӧOǭފ/ ]v z‹/ /˗/7ߌ)Sǂ 0rHO>$I&ᡇEav3^Q3Ƹ$z'r|vn@>}pBǤIЩS'}܎ۿ̚5 zhu'^(s衇b޼y2d}Yqؼy3̙M;ꨣ0g}ј~݀%LpaaѢEXv-Zn]mw;vl X=Hy֯_v xꩧ26QF.!|Gk_֯_EEK(Q[ayvDņ z'L b5A,mq]w᫯Ro[Gyr­ފ';>C̘1FѣGW%J83f nfG?^,^+~mp6lz͛7cX`t邛o.f㦛n9#S4o}Ÿqp饗V۽%JxB%JN;1c`޼y3g6l؀ݻ .gϞv 3mڴ=MO1eٳIK(QD%:6l؀+Wc~A"SLg%J(QD9pYg)e2#݋+>ⲟ7}.5͓eRu`HoĥLcյϟg&@>mew]ԛ=})?i*)bWMlJ{ ~;\;C.e#UVO׺bZ>j ,\';!uاrmwMv&?q/~BZek;Ǜph/"Sz4O5 #UV/xl߾=O%/$?fZ#H^:o}eԤ%eg@. 0'}*$kseE/)/Ю};wߌȥM."Y6`e ʯQܫ&-lE6KɰT?e!A[b2?Kl5`j{9MY筙5C.YrKUMM[2|" )2OVp`t|`Cw.4isP̝l~?K[5C.ؿ5% ʫkM7Ȓ=9HāDr7?5TzNPxajm#aϣCk>%ɦVm*oWè^8 ^=_T32t0tٕ3 ngo~Jr|cp?^xqjFe xD~GZSSI;|l@ǭ~k\v~Z 56-b_i2?bhspa> fr:"v,ʭ+ q DOO©5s8v AV3|#56TKW>K{j(D?&ԫc=ٟΑu45dP>Ϋ\KK;wŲBM"m/Y3^ʑ A~ QMkVV|w1闚]ٽjȬ3kyӚ$E}k`Qr,~JAkE>,̴qɫ@i(@v(TWw]j7e"1IQ䲜L1XNk4*cz)S”j,=V"#N2&ȥʗ0E,7iJm"y( [uBYE72C!񯼄%U'#CQ_dmgjQnfS4a]&`E/(JvmVxr ]֐u{e?-b=k9iEȤ) a"F_& t!\qj I.Sl%wNjKq̈%b=`^g&_}4\KUK5RHrY܉"_R߯} (z2~Du 3Vi?O,gP bIJo  ?+3+f_SfaEy""7%>Mf9gx鬉YH5=N.%*w 9Q֦KP7O'k՞>Q7s@Ž0T'r'",?SZʉqbITW2dmdKEAIhQIҹV~qS(o;3*CнJ:C1KUpUVK(ϵ1ݕkUVpC-.-sg^e0C&h?hߜWi5CSM{u5eG:)Џjl>Z$Ĺ`[YUN*f(aʙ?ջ}+˺tD^=g.k膵tRju_7T[MYSS}W.)Ҝ,i ƧPj$(;F%5fyj=kj\Dk<׆m&T)gSyj{V@I.-Է$%8o9#c#;Ndˤ$}yl3WߠE;]N5M<߇2$-l|mcbje'vr.Wʗ!$ R[fe5x' IzuC,@2~;*ɥ!X%B4njGsCwAeXKzT yn'V{K.n76i?hL(:PQb|,<Ϭ6>>yr!T* "Ůb{'F-U38QPaIaYXK1h_Dj[v OT\Ӝy׃͆ U&dAP|R0GDf KǶ&\7d}Y$ič6;zpI mRfEE2^'V2(JLZu0z4ėD"CX `Z~UcdBa&2r1X|pGJh4wHW/7:X9m!Ʈ5UGչCp7Z-VvE}t|Z(*S< \Z\p\U/\ORT<HdV>amW)KOhR Zk"r~MD.C:ؐ5>R@I<0= B!(Fzbє:/LQ=qSF2k#bdUHRɒ"J#TdOu^>_uA_:w$i 2/#"L2 ͑fnmʡ!:HHߗӒLYpV[2$b[b[M9X`]]Ϻtbb35Ve΄ZInI zQUb * E DB5t!^cP,*$RWT(QSYW<Ӌ$ܠu2YYnzŨr8?[l2Ҟ &r19ӑYD2ZdnuVVATOȵr̽dJfԱ>_AH(dMnSSW)3G$(C/tBjyLtUFi%TlM\2+D+(|x8ac&ȷ)2%>8cU/$$MJlؒJS/r</u|zW+?D 5}2M >>:^:yWj)N')cyեa@Pe!-h TJ2tq05Ҩ$H1HJsĠ@,\V"dCa'z4&6DMF.cğpLRe_YN%Gg#j]ٔI7O&V `Ol`̋ݣ̰am'4q ?jeI s}S|?H_}c͐tU X6 :|E@|1Oeɜ%6'nX+ R LwiUQäҢv䲸ݲ٬{f52:UVh^˜E"EEKf>R,h#Z~K\W VTR͊y*Lhro3צ}HmWf t Cxڹ6g vdg.8%&֨_]QVpxHX6$@\~z>7S>ri/d+9+Y LT 1a\ SSM!@(1Y} .ٴV/1Lzeѡ=GG6e{$5ӶɋQE\:jш#mRbDy#m1U(*cB'!YGtao Mfz`:z9ߏY֢EBKQ0+/48$AֹZփTHG wꪃ-k-2UP7ykt[ko"acF_(rm2uR "<Ŕ|.Iex,UvS^zJyg=X?mlاvʾI 2EKUDeŬg #t39O.՟17{#o_|2Oh1X}g@KA:&4vTO2_Nmlx^}4뷯 g]nl fD. c\|SN'N$}Ib}*$w%IW ?Om5ӨU/5,3[Kn/(2V zK6za}0ឋ5-B-N`R^dM,sMsE>}j}ueq)yФUr"{ֶ$5e&zeՠ!7)Cؐ?y-6uq&Et(# l<_N@$ \QyOJޞea_w#fMaJ= τZGWme>`&-$V]Jg.F&tW7k!!!6gUL]1Ũ#WR\6. W3?>\d~AU,y5z9alJzgL2en6F kk>37h0pܭ lZ&6bSIQ(k5_F-)N;TKe16G'(6D[D;Mx!Y"Ua܈1r2/eHa꽖9MNJ ],.ٽn6,̛reO,>fB3KU8'[ݫJMx]P^wq4H1 Ʉ8!9#(ڹ_-=+QVLJ|1r]b2%<$~.K6%. %q^\B8)IK#ܶ8CS!,AJ4d5ZQB)&>Ց Y;A'K2 H;giM8ie:@-8m~D"(B5\jMr^upeawF֭qG7o'Ni8ꨣo/iTWqEv2zNF~ aTLJW6#AHpS2@j'g90J㉸|G#CHxwN񝡿_kuĠo{O<{^y睇/w(N0՟VOQLj>g`N/(ΕgԒ%M qdϴ?=D+*R*v-r6`̇5n[_2'UvWؗ4E"\N|d6*gC}gELG)&yM ?=&C 19m^:$d6\ܴrJ~,פWsS\mիWO>.]D"vh׾}#0&~Frf}N@'`jmYMY->v1r1.oS(/a] DWüh 3rL5lnLA6#z]hGZBlEЙtET ̣)StQ}sbG*p `Z$,ay7&rO2SLMrYKﹼ?G~X39"eY'X*Gz٧BZ -J f(WH<101})u.ŔʸV# .'Te/L<:ڤIR=mjzر0ak˖-سǒŻv*NY&JwbŒ?"łE\4P6Q "O/Qb[^S.2iZ$1 %022˔_ -aWG9z V}ؾH,j@&غuk?O+dgL',)ۇ^I7Me)yk6UO9{]2ԟ$ykMw琢q0R~i1j\S)`/q:5$X#2$%ka*CdrIIsj-kD&Fºu'O0;3ݹ""f){EѠvUg6rrHsK_5Y#I"$NgʽJ&&ӴdRhS Y+L~2&PiDyLN7!iӖVznȒh\>CE]/{ĉ1uT< hȚXVM!cL1OumPt&OBBGpp|8H_xqbZ=2@EeS_,;[mE>#3Kt0z/ W]u֬Y&M©(:-# Jvɧ~MάI el^QeWdZD9%33joLcd{j6I{j@H\O8)U݃i_a,pFž44F"EO[K) !=M'3DIj*M:x_G n鹯Ȉ\mvn6sK Rl7'gY@C\|ͫz;vp<jic{p*  =45!-iAYR?uNƝ4m᪘`FUSܓY$>/Ni-\4dUDdfH'Ǵ'~>GB;7yc9& e`»=J)|,Hn{$F@N)%/1E4vG9A=ƹyF1ѱläȖ2`%qy` QFJ hYiݢAZtn:Z?jK[*@wx#Lz/E;4&(+DyoR)ȊXz#ScҤA@6%\_ B"hhBԄ:$ `,CSHT`DOt> SԿP:q(@#fmOb| Ozd+oŧkqA^Rn=2iEBߢm z\$7/z׶)@YG˦:ێTitIfwM G1mBJy=rϘƼFBڏ\ ^glwpե̯o&ۆS)#S|b387(eHW& 9SY<{!x>YD3N"FɒH4CUD+Ԙcg hZMDÄh F4j/U84JҮקC"kZw(\&[Zɾ}*iK H7诟XV#<範~'w3r%*,-#1K~1eh1,\7~ɔp&4')!Zِ$ ܖ~WF)mzGٵ?*5ߍICOUzumw KI&%y7O߻Rmls䒛@"2״#6ZK.,`3`gF1(9hV. H3YN: xԐ%!SoHdTD/RHrǻՄҌ =`]IZ2#'V^,B'N. f<%|g}ĩi)Vl>ngsogrv5m}EL4ͮDzE`5EUfBhTݢl,]!4ԁ#.>-Jgj K7^zƏL2HsʹD>mIؐӣ#K35E>w1zYƬaE*vOiK{LKeCG#d@-S֡u)6)6ӾGO|#HgZv>@.ȫiR'{.Kz 9Kc[ZJʗGDN@lUMBm)~5MI|u^7E2cj'fH)KXJXv%1aJB6%"|lBCR6#h\Qs˪KAI셳o(FE‡?ےZWQ p:+/N OJ 94oPIsOr~{oˊ/~k3iVP2>D"?L/z$R[eN^yYSw'm1Oz4djKY0?*WnN2@A""3<h>ť1ClJ0^'Ejeevd;hF*{If)DA@BE/HהzdnG ƪ3v{i) {PD>yZDI2 @4*|It)Bw?I`3|nX'0I|6JlZJ"B2Z)0nzr1Rm7VjL fo9:I/o.Ek38$C~Rg`Q?\!U"Ϥx,-#mưDdsybS%or,ԶxadRڱU=# P^ K&_>8 }Aijˬ8JtXF&є*]˓ P2(Dx+c`.S\&+qAEljUͫ|y)6]>E(WȎ X[M=>4&1Q0*ߊOYI\G> )Yz3a$L>6=6J4n}PD˔ĺЌHDi+b rfɩ-F[kwQ%V^v#5\*`ޜ%SrR_ᅪM<&STf?Js :]t֎ȝiP JJXj%xW\ _gyلDrC o/!P<蔈NEJeJ2ds9H kOP*r XUj=R_xcJ+%L6i1:D cIJߨIt2&;Бn0o6eIQPd-KE$SON2yb#D!~[lq Y^X `ZQˆ&^Rfll-+R~6[}p>}fkZ/(15U~k_᧸hT ԙb|OQ fʴ̴ב VQwQdΘ-bh٩\Υh.&uڄC. PMbiI҄bgTKɸ6Vڝ ?Z`֋} ڼh9Rf[(}fj?hsA43&^$D3YGR꟒Iw\`r!"PRHXNE44IIc~KL*AlJ̭+D7՞q"6 3JǕt`.x iI$,L'Ap顠*XY2je\.E=u8#Z豖!Keq5Ʒ]籛ܖ<)E'@Ḩ$ 4$SÌI#P* +DDFDU.%#:B򘷯]:r z/գ :_?hx;QN7[͚Vtvݞ7Am!AZ黯"Mh76x%Vo\Hbm~"1@ZR͉h-3̛]u #V ]\üy^_n L=LeN/I>SY1|H{hzf6Y "l4"\7&:?(؛ҤZ !]ju2,qj4j"E0UZ-#׋CR[08.Ȟ\H钨U+gOL- H14Kv9:Q3D(tH*UJ,dcQ0!HLJ(v1>XB3ig*+m$3IL)&KQ]MȘ5$"R?ٓ r0(3A'ʪP\%,TɊ٦Ǒ= .\k^U~k7DW{+igse4)si#,4)3btBȭ{mȜO]ZS%S\IgRqR諪ńPY,Z jaɫp|o3,_6]4JlxD2NJ˜GYHD[LSlں?L,GHheH4NJ'y!j]hBUv|T>{ɫd&LfaPF1۷ߍDJCA A\-LEN#0z\\2 Ol;9MhڤiKx3:(՘+n%PGy<"P, ҈^bIiM$RiM,ޖ eVM Rc*#Q@d >rA">B*,|ǣ5!Lt [27u/1,Tk4z VY>CҴ"h;⻭/66Z=[2ٕrdv~}Zͣ_.fhϏ\uWsHpHOۏ(l6k5PE8ю4eqz+%#sA8! 0('ʃBIQU?91$]jEpLOrYAJုmL2,OLi1Em[x)D)F2yBOG &\Lǭb(~.]ѐP `UDu$ cTL盚`6ҙ!U?tBm'NgųAEtiQ('$80H \Q' S ihVn(qscT$}C,V*z*)2 qCF„RQBf|c}hR}VID.OԶߣFh5?Zi(IFpjgmj'fwU&k?|&nBu#B?'mҲXZcWE$aFgI$Uv[{J[8le1ʒJj>_#&Y?mve&'K٨!t?d%7Cۉ<\G=Qidv*CqF2ڑ$JSo,VC_*M/8RǷ"8wH IDATD qqTFȿ6+-ESG~m b@̰LBT( .n } !,?.Z%f- Íc}-=#Y1E,ڴdU쉰c/x_x5d)5ێ|Y/)E'mp1(cHb;F0&c5&SH0gdZRb4_9Y' zVJulk9z}EAd3}Ā )¼Hfk3y&ke/PS Y1*W^T)S2:)FINNye\|&rd[5XHۢh\K WFp7Tmq`?{m؟#K/՗dkhG\ ]d]&gN{U"ZeiOʐb˳5YHkb%8 G+&P,ˠR)VMlɦ; Do:iPv7R-ؿ&~X2*&YrpG6e7iI '*(%`Cc@kvksz~/+mXih&i$9".s6y_J6v!H1 94f bZa8ӠQkJykH@Qȷ5qoLT9_(2LVnzS'˷tWcjD*=r\FҚǢad2z)=R6O6wQSЖ%+ N,qSWOv]fbj|U$1`4rL_fD[N 'Sx!ZdveJJ^r\RVuވJIlRDSBynNV)ga8PY`X¬F2&]ϕDࢀJ*v.3UbFW.8\2)eSjcL? L?} JXDB 6a!cS:_OEA4m"EđBi,ͬmqNe$Ku'yV3Y3'jE bƒ_ ݁Se"9ENxSDQM݉f4*BND\0q'!ڰR{t-%MJ^(lAJ"toq˭dX4F0}T6<3=4d1%@e1Kk:ۉ&9t*S8쨁AIl{IUdZ|JuӳUnTRVP u'?L--R84[jq|ʕmަ"J4,20f͊mY#1-6HZd.}wfmC:c |d ߘS>ii2 7(h"Q$%o|R"#ĸb4f5'ő},F9d~.]t~m~ Oaſ RTFBJ6uNS0>"(qvny\I8{fd,hRxsd'8(܀LJ⏍2$g|~g!+"otdOJPl7P?IxT@SxYH576hU 5lyuWFebC,?XY![Y'6 /,2%' I a?ɬ KYخ|H<V>ƉN,CM꒩A]#vwq<=[zMZrm|ue: 1 fXS|`4)zS=uh:l?: A mP5|9wrנȖtě.LY\" $G[SQj6:&HVg!O RJ2ժ<S." ]VN"] BEXTEI!Gn`/7De5az5J* p6L&C ZێHXiDBcґص7$Ȟ ۸?h2$òMNmu{ $b;HdR !s(HWyb$R:mHp%$uLAnfc6@r ZB$Ѥ@hoa~[\p|,9ވ@so̟X]7IIkja@˞3y5IvW0 ^Φ ןm_]d_LU2@3b劫F9'g${Qň϶xw P??%_O)j%z1!l ^lkd[.nx@YWI3LiuIEY5{ʫ;x 9=7~И8>R/Z[Uf>Zv,ՅۺTGAKSuhJP7&c6*Y:qEF0  slRW\lS`Sٖ6 9>#+<XNu޻^DiD'H@H0`n& N`0L"~6o'Agb(F\v]yZyZ?޲5=[]fbzԚ7%Tr.A+̬x`m!NI? %@K]vk:[ϽXNHf_ÕS⛤:g|6dx6!§ܧ~Bmگv0NΎvQk.?d;-QRUTZjx\myDq[ܤ n@)&& .X3eB@ 'J= >D-)zD,QR`)-6Ҡ3ꨘD u:!7o^|O%v:޸ !rE\z UZRd85gMF^oC^V k|@˙^& 8Py`#9{-KdO,qQDw8ߪoU ȜL>M+eod2IbxE94hMDʀR6d2H^ x%^tO|pUV}Q4xp.C~A @WnRdfR“2$E- #1s$maBի2xaw?Z{o>+:9&mzv["W\&{܅ Z@#Tb[kR tY>bHkKDiN^j+ s P.uSG~b'P4-jc9VCSy mZ{zdWX: !6>7>~j MTQ9 ܺEDbp1o%=&ǽ1DcŗBɮF ~&u,J|;Z⡒&`90wljYx?e΍Xf_Ti_uʪZN[xoȥTZn%?_+YD=3MizzͲn5uh ,+4 Y3 ,TSKjJpmɫA#sdf[@j}MEpHW;w`Q̣pnrthqwwcyb!T,R$ͱfVI_ʿE-G_3^+̠!>ğl .sӼ"?iNi<_,Um\,1Y89 ,)I>d)D9D^l^l0_zBtz)~dQa~kNύR1Os@tWjV,Ыc>AX]N1:Ah;QUm mC[@?b[hQxt4X:P_# p y-2ܺ#],jPX:gqJzc]Rdm:`i(aU]l:Z/6cc߷F,{2/oCAŷ!U&XrLZf `bX.0Va Y=?D4*<@iXf6ڼW8EJtUWUL'9N2#r!aJP)sQ;E m}fgEXoM)DP RX xҲXk?#'pv@p | &p$(R+(B%j|T/* z@˅&0qSYtpu+Y`&'<]Nh.PAIxyEPxA6#NUT9}]6S5yz-n G~8(D/+W- 1m-d#ӱ~y.88ȨE\ MVc2mT*+V{!|m>#d7Gs 7D.%=?@_to y.vCj@5D]w`w1@#h<$CrH5ңkp~ꏈi`Ӱgi1IUݻʍ':Z_[޶̳tY۔e#h'MkvW=~7 .܎qdJ=7|bc?k  ^jDD|&սqVo=ɔn3]M|ŷL3ԻJn :X.ZPo"ل]=@|p )gpB6dfߘҏzdVI ʗlq=Ԫ3pԧ`z¥8\O9jts+T% SH i}~$a^bգ^h|i^RҞfFR-Bgޑ)UP>rڄ\Q+Zm;PBj1}Zj W,eWhoSf8 DM>Wο<\Pkb z 5P2c!@<,S;f+Vɻ,2ꀞULFTB ="I \\fSA$ j4[F+-l6Y(t,FfyHL{}O=Zk,:2X Xu1 ,BtPEcC%W/4E C_. zDV:!"?X+7LK~4U^Na6y6%n[@0p~)J+t0Yv0S[.wSÛ{~楪^|v۹'Ez F񏚾ꎦ5%Gz.-e. Mh^lz-ӣ5B0)u2mrTcOq pD~7$NHUe d !Z9^WSyKr@\Jz|`8/uneɺLw^%$R ;vp"#Zs+E.,;~ϹSjwn!/dyq4=-p7bvNmqnZ9đlc?vYOBC`:@qO[Kqhp<6(WՆ|L '*,AB}α|1xėpc;AviPp*:4Wp Wo8vVI|;akWzw;UFf+A-ki>,Fblq !2SњaWGvfyoyTa|b>kxH.xJRK1y|3WSLFsIۼ j.Y7{Ya[*1zY4F.Y@SDlK]?2T,SUmO+n5cD@gCE<-<s%JE4"N{ٯ\{,Q5\@\wBi Ly`#2B $'mZ.>Ľ{~@z!@HoYp,kupp.}ﻒQ,@yM}oz|0xi`um\p>9سqbnxqKVhAx}Moj&i[9kmT:02qjE#t/,!HRLke3*aօ4aKxx sw03М~<'JsQE2R1PY3D|tˌG[ᆮp`s|2PiXLj7[:UjYe k9yc78鱙{DQ̇̐9%(0nwn.r8$;L'E4>[#|No.5@ Uy6#G7d} R8"@0ON?įz@Nr/Hk2} @xD+>҂iV-zMm`hםL$Ԫ>py S9x*b1R{#=Cv+QJn^_.'.h=ys g Z2Tn^9u?U?+׻$zYOcݽ٧/Z~CK՟1Aw(G'0/G&ўvs}Akۗ"t7X_Z& Ale%I ;y2@!]D]`K}>DZQߜogfcx]a)(e>V_ב[IU "=iw_yH+k% ddZ(5jhx޽Wqy}Mz-VǑPMj|Ck:)d%"ܬlli{J IDATR AFUSTsMMlblrHiY"l!ZN%C@_x4ҽ{{m7M~t܎YhZFA*X-9څDT#kص!_@LcH@qQ\  e1->֏!/)D낌D2\AIv j19 = e=KS]H*[3FZZ&=zq6Rpyk,/=ԉv'36XB4lI'{S +C[meh$#=#).C6,𶧾on6gp)&`Albr͋H֫<fMfutzv5s,p0$ Ai܌R9ra=vV t^u+fk2%ir<P*V{̐;hɁP,Z;5CK|`6quxE,Bxp[<@=LmTHj$C.^;pR6yxչsuٺX\Ɠx= Iqep`E5H^ͨ0P^fvݬw|Pg7Q*&`9Ik9V@=5Xj:J8۸'g)0yPIHA/,ahupBU+NY MZs2j鬚_c_T:$O#`_#1UT *DtOPH-i5a"b"}yM%PnO`8˧jY(Q1E|dS̲.CGBc>JR;0%l o" oF ,K¶eXҥ*co x@Z6 '[ME#lI!|tb*3زD["YѲYTqʐlVsCկzt%vpDS*48ִS1>Rv8v 4,zU&lV:~wۍȳ6}pAK1}8HwKV̋'$ Z&hIJ̼O0x!Xq۔NpTbR":D֐}Ps&KtGT o]5ՎBQTa4-G*gsO(wc͛E'"4ϧo>Zc.kz@ e ه"xu咡KwX-qqwoPaF+pfRH DFY)*t}Fp0LzAF2_Ƴ fu79UKc.뺆:`$ nc9v&g7P46hB.oeW,rP\t.3iE V4~)ps(˃Ku5Aeesu-#䡙rd^uEGʏ.'/VPcҏLKfP$сzDeoȌTC0:|@Sw |C?ɘyW=V<4}\G Fq]rMeM00D1om&~?$=,8Nh>ȥ8~D ?l~: BX. @l"N/4"-^&%10uY"ÕG[ 0X,^?H} %%M_4]MvL?Aj"`?YGj$Zc41Z:$pjo1SI@.g8YTsVa&%E/>C|BcHk/&ZB׌C+R~ L[esM+iWk|類QGq44gޥinXt!xi]4x51OPERgÖ=8#~l҈45@ḞNBG."y4ȋth$V;^UP<lZ3%v! B4 E!]C/BHWcc*OF㗘nQa:HHVj!MJDd;\L[dYpYK? \~U߽SM1;8 NQۦ*bҍQ3;6!NՕF͇'z0EWKiSKJ1xF!?FdJatpkWYT|wH?Q -U1m<6d'J9 ׭h Jy!9įSȐ`V>:U֘pEo٧;O~;NmY H*mvdu1lLA0hLF!s6þ5a`>I&QUƀ]u3y`E9Q{A ]& JOJ`Ef~]a_\~SSZ 2zto]AjӅIofYn#R6mbdiJ46xh஛6-qCQC*>Z==y+{mk3f00\Y9Fz+as3ϣkwJ>>,!{U/1?Xv٨<~Fа- .?(dd Lu(W֑Z9^1`L[6u/ `e\Kġ^Ga19&@(rz|xXr$E&gJ۔M=g.mspEʃ M/q[G * maF*ɩk9{n$cd#3Q}Ai={c:Һګ,_tτ<?}S^sS|jX.xXHl({huW8/[nX+Pxj5`h K!V"{ް뗭D*ネj{ksf^ bN@ 006JrFeF;Ap9>H­pS_n,B[|ֶQޭ?8Ӣl Q-4LaB൐!ѫI*b}#p׎AӠ1=ੵp_9$ pVFmxҭfKF~BM7ѩ|=qx7"J2C!I? LVU?u=󋥣dO%}f'K<<`&a0aA|wghB&ea#|u2y] xW7$$p92X2M[Kh\h`GܨERTrv݄ssxz,&A^Ȝ̴\Dd[ueyrb(ZlAK2*I= b)s4} я\+%fEs;c 2@98RGœ4xvwQC_~09O Ctc*{hwIvD"#U1wu&;iɠ np`чVGף:?K?xUWY$F E%D*?Ñ~죗#| _ z>oCDͧ$"2pTE}%)K~7mY)ŠjseijSؒk߻K3RB$xBh0%i,"O-X ]ɧdrFFY">CSoU379ϛGi),5Cg{lqk"+5C>e,RՕA?BU5`nܮ4rKg⭛/v2n;3mtdxPQo=`UzL_o/^>fr`t~w}.AWF6Dnp bM8tNkZ@w5"6[_ ⛦z_bU#/Yp.,:16؟M$/bwЧ]\W˹umܳTXG?ӡ% ^0"\P[iHhצs0wGK[>ƹyVz$mwK%Mt@oiRfu/4UG.o_k?ğ7J|!|otH5ѕuzœ3Ik/XBw̳CAQ@}da@kGYrʒ2-{G(sO%?O?mjvlC-E62q܈-SZj{R#$UoekBQK dC?ڽp*:z?*ŧ*3)ҿ(aU)ptԐV^@q0]ԝ׼>sy~J:/7i:߹uXLD>\?) ,K"Y" yS)fR%{19:ӧ7Z__\F2\1\3,V z)pW}K0d߷S:jhU"~% t+ d^htQT2v*̃Op/_ Wm62w#=N;N;6[&糫;AD~@r=^$4TmfxAyP3EC; 18xR Lo{?\7ߴm;%+Ĕ;) Mb'O\-xE;X^A4-m[Z7;N\~~0sw/٫|khjo[Ht|WhĵwA*̕[0wGj!s_Y+Z}DZpڍihYgGl+}o9e,;_wF‘\-;ƑVR4p )'/l#ۨ:5= .}8?G.9JET1I[fUjKOOv]~aRFk;xvO`<52IJwUdu h\@ٓgK1|)phpǬIҾ0>طR6ˠ$r(iI&8_#0 *("R?IB3w0p7O$)+PptFy$ 9q &03ɞ϶MqBĭ1~27C@)<8⡦ԕ ;[;u2Fqy0e)xZ+kj Znh49CoDe(}2!?jGظ\$]a"T]"2} oT>5!,dIVP(f/1)7s73-1/7pǀK7;گҔ8EYQZ9vE\#!*]1R:^;lm$~st±D:Eױ88 igF5H (ˬG~|Էa[nȱ eFepgl"-a- 7 :P9g~|Q1}f%w+T|mȿ6 F/#J}o<ʍ<HDO_0,k",o{ 3@8uza9}3Jo|v3MKɭЅH>3,eN85т ~0b-<|[M~(zT= F,Ei@9X 1,ydl(A?\dƷvf-u2!QqwE0c!QGr[l-4[cMlRȞsʥ,ge>h9$rwD:4]ycp߽hd.[_G% r0'>Do`!fw_n8#aǝ/TJa#u#qk`vsLed(ng]z G`-Jދ03cJ6A3 *RjWnㄴMp9-L?om&O52SMDPk9>v&Z" :_K+IW'2ܩ/ D3[ݲk+UI_}ݾRNncG6rg>3lTOZ|0um6D?\ZT "QW;VL(B Uf:@6];!>{hגێ Gn֩'G+s۞q$ԈMm/¢݊\Ky39@~ C5+P(YjMznyL_-1LT1)p4FhX#йԄsY#xNҎّ+FT#Nyݴ@x'TA֍K[+hhfA~~1p9 wwlVI;~WYDQk_WGHoQh,%|Z[&,d9-Z/DaWSB hˉ2Ҷq Ok ;sgxɶt7[W>@2"$|JwOjuy )6ҫf:e涑v%"[{G)K ONO|ӦG.}b 'KhvD4Y.cZV:v{ڄwO@n\,3ʲ2&^X/M :%-5Bc^s|־Oω ,Y);!9[Ȩ>Xʯ{#4U%{4j\G~b[^o \ڴsixw]c:҉O`xz.(;$EFh}Fbu"uU Bw<4|.q3O?`=zclAEg]CnQ#+(n <|pK{|rR9h?5Jt{U8Ayt"QBoA2%ץֆdÜ{MD.iGccHQBe|\̛ 8'=8wX2 +(rRߨN~ NwTkPZȠ tgO`Pӵ[}W4d."|@*8دHOtm&U7gx\-y{@_쇙Av4 o+-vΤ=IVG耿D{\5쬖[)wKAzۄ-{$m&X3"CĪr>ppi6o+Sv%R#-)kkH,/:1~0| r)RnW+qX9y:|^zG1oy|H$xixiy="y;vzj9cPt%rFB夕xG`Ѝs0.}+%ByY#KPBhNࠝ9W ?#R5QZO|`r&8@e@I 3y!B͛Sb%Ct5X8 ȘB 02aA}>DǠ_\jq[[b[;;M6w؛v_U`(򷹭nDv>QFқ`rzT̜ŵzYXe|G!5MiXAk X;ewad=E(hO2, ̿ @riLY2 |Y(0>]ȺU\M/W'^|$+m}k{ˡs/ht[:5NkܶhihHɹyѰKXhmzh@8rXcIė +*{fLhSƕZuLW^cGr{ѱmںd(8YiG.ͷQ6'7a\͵1Y+F) &2/Zgl`}FZw>tn\Dc2}[˛ur6wta13sT d6wYpuJy)7hYi2Q0˼i9raxaSW?qYcK*1\[6*ˁnzMsCuja(@ϒ lΖ}uY4'qi/uEgu;MM!}bs>~Y1?hRXbPJ99Te)[Ӫ=ET~i`[Pmǀ1mXk໇5ʳSHzVD^yS}̲cHgk0MոAew46)M[d#?S9Ղr&ƪ@plNj+0fྀDng |ZHs鶘Ql:o*m (\nf@6^hcJtϫ{W6s=A.H*!+DqG my":@lCn|7ug_rc2O?r,Q]ׯ M\lqL"ھ->w(UAa>.>dm^ۀ5jFŏo{Nk&#fi vR'\zr-(+y_EEJ¦pZ/] -5|؋rEŹ\5ux*sLaC.}yByg[ 1~x6QӞ$hree~.!u2i,_>GF˭֗%QٯiEk- yXz']LWk>EY.J'[ET~H7Q0ONk^o/;ں7"O %~4J r5azSfw/_Qj28" \'K#H~:χHF?.H^R#`8kh9+e#qsW aD~WPrbh(" `#ս֘6{lp'*#Nٍϐm{9\v:xկkX|wG\nByJlI:=tFĒ0jjN7y?Pe#07<3{"!ChiҘ("Ixj: TGK۪ӊ1[h:V9Ə "#7v/W-o<[N-D]l6{KЮ0`ubN5c8790`њhˏ"` Yrp@ٚ4RD;߼;gSSuȢ^mqζlhWxYKΰkWCV*XRYGUmT`o a~҇٥ظ,^L2z(U{Ij+1FAwY'7rl iȲJȅ XFA@Jlsi6m" ycmJ->ezIm~=WQ)ۼ#.0V߾o; 4߂?ɽ;K*cEްe-}%TF6wŘk>]C",3cp| ĊfZ&ye_u-iv׺O t.Շ5B"0̋wp53I `- *_TnMEHb':ZViۖ$\Pr%`y>TdUW_$rўw˖TɨhoT-dX}@%~6h\}8ӆLS|:p%,#{6K~ `.MӔEE) ,D,^,4#@n7 E#6=3򂇯 K 5\긾Eٞ2hʍ׸^7f_/5Pc8[E,bx [C.EfqIrLh-#0μaJB08=S(i<:G{ ÞdKL5M[Gڞq^ M ,:8CIpUD8} 3Qm^"}٤E: H{Ԥoaz,*霴-*'#9c{KK_4@a\>#/*M tD|"$ Tl[:i4qGʥ`(k*0yuΗ@D)ƍ3_[tu{jLV,9vmGd@T&|Zy>JsN{Fĥ,ciD#4%f*۪G^v1SοTt׻e/'v+hF|Hk'۵. H5 '6GGs緜u="%MOJEčxЌI|2hϺt-&Ӗ5yv@tv\O5?,:o㰐29MDA>?TFٞ (V~b,xQ˂g8#D,@7C:qKqpT 2_D崦 ov#RQh:LKu.4ءMmzT^Mx>y`)3?f,\ -~Nrn|$Y|iW >"+W\9ym |myڦQn]ǑU=ߎ+%kzV`0bGxbz5sit#y 2}8 :K"c\,aG@bq DF2 qQ̇~,*޾R%/vSu5t vR9[Pm_ɩC ԏeٱ7"ʞDty|8S q|GtV3_'}ok^;eJm9T~]!̓Y#3e>()=>#(Op=M̮1zf}m"j?O1l;X?l鯘H6F`)ʐ2`M?bCK++S5QZdFDŚD#et?33)\NH/ׁFV"^%~av]D=.cm`\ ^͜|}6N%9AE ͹C*p`E5b)m`eϏ:p$E;1t[}töۯg8Jq⪗<%l6.30Ss-/ڜOfŮEF嶷m7 l}^*n1;1mr}{Dy -F@-k4 Uʶ@%H4{o8ʡ hmԘQM_-~5('id'ȁ>SL'>f{ֺOj2lYtFt0?^L}h~ǀ%K^"һa܍.(jy|l)F@v8gw|ĸz׉iJ~噾޸Ąqh-::" }u+=(:sv8J Xn5>S5{[^JҴ"-ڦ]N'K̤lwb@O&>V]{rq x݆< xiŘ#ŀNp "mhM᷽BKק[hT+6Yv1`  )6,u `X"nӖjQ{' j9;c&H<.wn'!Yׇ)_~O* 2>skNfXk} S!b9Y[ڵ_G,'dp(8[ͤHz J fFǗ #ࡀe%1sKo7{GJiB7xKREl{v8KbVXɞW>*p}F/Rk} Eymh[fҞ٨{ρ-pC'vI/: F Ȗ;Jڡ88$oY ;qMUtk|l|mMiyKqiًn:T7\5B篢~TFq*o߆n}w|g\wNЅ Fkzy9jg=̴1 1p)|@@! <_ @7ad0k9 4 dA`z'v$O ZvK$jywٿd{C~9%itpR鸅%JOevfu9+sVM9U׈~#KlyOnu\4]#Y,edxLʌ+*ԆsCŋI !W]78XzTH fqe`g"~Q1yb*,FO#}G,eQGeV$uϙZ6ty˶Ϲ,q)=Ckb'v5QZeǟKv{~)>̌Q.W0=Iη~L}|P| ccZE}w Y;҃K260!)`yH%!!`4M&B w- 뫤3>VieRP/NGDa#n?"S0:=j| VkRh}?"}OUh՘I2b}J/NVKR6?, %^([>_yCV r*7qԤbDgӱɊm^#2r#F'8#c=c~t?ߗ'QB6X _̺{εܷoz>IIXU`*|@| go!gf5 aFM=CWUJY[NQ Sr6+Fe5sp::}e Q|/r@dz=EHΕSpzX>`{Fs;~e@ '0M# %Yz+A<(e[O" J<~)q(ǵ"{M` hEp6_9tgDc ש,\`y@c]7lK0lK"|)o(7 ;w4 bb<[_Tт/C\I|ų덝E~P=a2.4bAVw׏ :A@Ѷm|nP[UC]p!"ߩ!j@Dب`r`̈I26XJv9%%FQ_QX!iόG!lWh: F2_-ٌ›Sq#r#E;f.yΣ5q{8ׅt?ͶeFf7[8m}t#l1ms2N !U~Av< !j ˥;F^5q^@'$gIl{ee~ ^qP ]j̡2â~{ *T·G||:B~=EK(V[`l1V+f-!pYA"\#a5NFÃ7i>.sv)ҕEPzxIB5;6D{m Inp7K릒gf_!uULNJ C*Pkk 6FjXYnϕHP! 9t m#G* (#ZO=4KOhEǷ^F#j7GTI哜iD :0LJsvM2A|QJEH5a y|Wv}uôIm9ѧ^LlT^/Ehb8t`&~Dr# z) ]Ng)NtZKނʫOb*?1A]LD缒ZZ9\~}Mn(9cbi{vze)>k_y[Bq^'Kumk*[<6 ^ܨ>E**c'}JPD V`>PXW`(?]Krt .| 2˽ ms.}:k ?̮o3l=] N}skhuv1.En,cmO,c;& RYΙ+bWQI<뼼Mi`wӖnlI>f!ҿoo{v? vdjdҷWֈGe]#m /-7% ~:G<Ͽ=^9G!]EeRZpaau4gyѥʁSqs'3݂JڳNE$-S.h1#y؝V8=ʵSW~-~0M at#[Y!T}k1fzW M/#GId({*ԏ]s9% ՂO%Ti6B@} bMnl7̤<~I~X+jFnGb:Erc JUפ(_ T]s\==|g:[ VZoU?O{Gb{*oPR`5.EU{wۑ9&Vs->"}d2%y,V f*ULmDDOfrr-)Kok[yv`аl:I"C1Kcrut$Nz`L%v!] R_yYwG .. ǖ (>BɜΊZ|ϟ+u#\x6ĸ~ՙT>VbXRtKMxe|<4sqHi"wyY;됐vE;n%Z]A9ߥvۘhUR]yW}t.?Vв'8hiBqZ"4{uD P1GjR*iFd@ ◳5i"$0$"Vì!ݔj^QWUO>+IZ.b^ -FֻtanP>?AЍN?_(S?0ۃʔkï9a-Psg.2!gKlAW>R`;MH|W-uq~pC*\Lq}k c{U/\}V!7-;UO^z߼Y?xS>< e6 ]95t\OiXXuer'ϱE'h畒Mϑ Ni4_"1x%""*O[ p{veЪ+ Vۣ7PvZ:~0K%Px_ ]XnO6j7H9G{hmqOj`rHPAP54V=PؚMȐ( bg'ұ>] n@?Kh|ؔlV? YUˆ̏"ͨ9 H:cgCjr`?DkʶOkyɓ⬣OK>5$2}WgoQ;?ŧUJthz7.sQ~ܗf&"Xͫ:e޼Cuk楅V|Ok+㉏,1]5ntKI#a؋L~׌oOXn"t8fgW .;2 /O)61;N+2ak 2@cc HKAt;,]QUXȞGs,u XF$:Gjn U~g 7ѯ.ߏH%bp'9m<䰩w¡К?0r^o'1jt]]W J{ ( IdBr*2|Gtcdxcuo68Qo3vPL}0s?_mum8]_l^%gqT;f"6)@PұW֫qPycxipokyCe D!7'YӯhLL;ߵcwoֵ;ObD:c 2)Lj-&o:KfΗZuFVCİl{(GI6>zsƍZ,A=J`?:w݈$.4 u5 ;m8c [:?mKܖ ̼2<A?NFN-S䐯hm\vޝ2=_v/_Z̛ ؾ=cp=-xYSڛhi9{9{?)? #gZ Dcdn{&@䡷FEѓ!ሧF}w=E"?sat.[ LߛEO HjUv6v5_xOم,i})8DzM\V ;+\?0+IPy<'8C IDAT$@c Fx Dypgf >z}׶9nOB)'Rr7w0)7SMFr~E13$ԷDs[sz}wuO85.?KMat5?$"::'(m ?r9rH]tc{ײa7GZ9OAcƫ ?1 vJ7}Lߖz7cK'6 ٖ<ܶ6B! +';b\|'!JQ Y8IFD𐊴f)9s|9b#!@zl^lky`m&=.Z;f=_r=_K >3 + &G0bPAh}tAeN˳1鯨q+LW:?M IXM\"XF}ө/9t (XbpR&U o9lz@R1eUVts"^1VaZe>Ǣ~k("/6.Wi/#l6ט07=RfBɶ^)I[ @&QD:?r53 +/HrKg1p6Q1&Ѐ@9 0|U&|B ImoSK=ыWE P1;f[j!A8TdI4{s=#Ie+KxZ93l¶ɛ&?O$rwKk<334}՘1~j8]B;'/G={CR{Z\[qՏqyt3vXV l~pD~ d}^Fm+xoEg{EѾ7hn>T0>0'exvE %7z5U7DP{b Fm:m \ PaP\0Y)8+U*:}Bgˏ_9NFГ1f#V#@+Hos[ x}>fL>X*,5 XhleWG7ݿ}C\2ElNUz7T\?]Yn.$~.ߧՆ+Hht\ϯkez[2j##q1\r^tUoֲl,ae# py eD *,D!t)mփ:Ftѱ?GT38˶ 5v!!0ؒ-oUM DmUa5gA1^v;bǃ/iT2&EG-V_hLO"0Hپ%M%(|KAekf!zXX"|6<ҴCar*9z/.-'߽Pɶ!8!| va-nF";[ֈ$sW|щpI2T0 udďH2p3GNqQ@=m#89@/zz'q\oIڌhMxVCVͨ#8([̲6r)P'ϟL˛hm<mwc`nտIp[t_`p$V(9b% 5+5S -}j]n㆒rBPza7DVx8j0݇Ϣ 耢F`2UxQ_VDI|Oz|--z$o4XH'aMusN\S P.C8jT)GUjc}ϔ=+ 馻ť؁VҙR ud<#I3^;"\a 컿wos&]X^>,ֵu*/ 3!]~ҋa`s7۞s) Sj󜂣7לFޒsA/>?5d/}|Mb羈սEx>ګ7U,YW`*X] PYj Cjwxt̬W|>f( I zoA +S:p y:x>,MoϕRi}v_W*S.m"sn: WPBkRR<@ 9~w 'lN3}Ds (He?˧W 1>os,^'byMve>; (?e-\T]Klߊ%quqY;n9;١}U÷, ?0}*2d{ NΗsXrp2F÷x _S=[%:zAbCG r(E"[ *Q`CN! jv4z E7ͯ?g_YkLgfm͵k5^֟=]# zT\٪zN^QRC }r̿eģzr|^(B=>^")`ɐMmñ5wnl6GIx:gF^P)h+=]觺%G SN2^=Z_\<Ҫ絧Q$q4ȝܼs.؊O+YPi4h7<F9;F sif&#/ \<Ϋ6JAx^8Ty1FSrW:@@e HXá%>L9Q9%mJE{lz G[Uw1y =õ؆.;l KnAA\6dx//=pn\_GsEzY`s:"rx[C|/&Ek;L_z 4 >fq3Vk5gXL`eX@jE'$KR(i/l[T{ƌJҁ&A%|~M-huT_XH?J//ΛǏ˲&80c+nR^LXey@3);xA·d>'^,7߸R ̻Wȩ6goR<SÚ͉w8G&5"xroVܥ|BIQk5':Mve2) (U˝tnosw}Y䲂,KM(#6®!G6Q~]^u`E>kyǓ{b[T8@eL$u 8])`]/Jm,_gJFloXKK֦x7eL`SlXP4YrJ;0EuAd3nr9gkŚb+/,s*۲ǜ=j`*VdUNOŸM~#l7\i~HT8{;GF EZCH5$uq/7*S&s{?kT?>!πacgk#I[N蹛ϡꊔܗk7!C=~ 4hq*',g3:k ٰߎh[׉wu@Y^`UDٞ81Ԟ~-"PvF\}pCtG0vMmSF[|IVDalt ,J=RwL$8v|F5mQ_@?|h\Ed25xP D](& .?'{?G_+vHi| r"HA؜j0_sό;R6Fq EtNkqKOXN#P-6/Dy!sD>[9 b+N1:Km>O*6/&J]07 ?gp~__ܹz*l J.ⲷm ]-M-6oS֬OQ^Nہ,y4vƶ~}/k)#-5MW=8>ӬCGҶ4_ u7=1`jZ{n-~ؠ"8r9ZoJ+қi^묞ȠV[u?/N~`N~jxOFlWm6k5VIReݞȣW ,Q|Exa􍺣B{UGG/ C4|>g=≮142r3ݓ8cʇ_O1RvSCiOеc<[kهq 8JCey[}kիc/ IhCcڦAHFĐ/"t7m"˼1sεȦ{͹[c5W)֌J 0 E2z٘(ŽlׇSxmwb;H`ֹ#IX1Si=P(VX?i6bQS^bedOk0*TNXg~L hlr=<ðgܝAfMAc$Ca: ]*ͱ=vKx}s>~i7@sDuرp$3;"!!2dD0jD{&uHz{F.[@]#RuX[[5WQ *J0S;]eIԾQNϹDGq%l8:q~Lbk)Kn;s1!R񄲩{[<5pwqENp@gLK2QT&`|4DӉVV 'JcS'\T4|衇¡C駟}o>RЭk5 = -|^HG!{.βuw5=<{Q.q 2^p].|h;&]bZf9%= Iăkb$,t]M8fvj|X(Ib:O%!XNdT%Qz!DtJ&$rIb? >.pb$q[_(X>^zR4B P4eW#.Em4,`;8$ &lH&HzCR|q6eS_>쵡JKN%ls@"[ huˑJc͇{ ZbV q ηTT"ZX MZV_BodΰDܾ)X%f@O &L*iKjsisQu4QT SI=-lzmF?SF2e'-ZNcf0j}Sr>͝ $ÅVe.)\^<4:mq2~j8e eoak}7@]*^}QAg{CbmɃJޜ2yFv#h4R/}o04R fL.}O?X$YOoStD-Sf<)p_+ S}j=㨱_7}BAp9Y72 T(U2Q\";0fz.$g|+M+ڋ9eq O.&|\ v{;F;ך[{ZNxQ{ݥRQ")@Ω3bSj09ִ_ ۜ\v~d 9 ~StK{pu: Kѣ/IDAT!pY 7x1MxqGA^1oq[z$f!lmbOx y;G)Ih--? dDXvS\Nm_A⭠mK5LB^:q=Ǚur4oⶤF :;Aȍk=Ag4qKK *{XQ xPF8[BΒ T\\"l.sLpד!qyjyHӤ;SDE^DbeK߮,cB^o`.lqhRqO_txyRF`*KsuR`rQm4?fzV/zntQO)Ov*F_iJ}Z?/)~2z_rz{zvvA=Oj|B6X#dTb)/*{g |%|r=%!s9_fCeq3L|;@=? J{ Fk~%B>O\%!֯ IHٖjנJNגn#%ENL,kB;:dDZ!H\ g:J4\JU! Mqo:Call%VmCwy \Rl[΂=fYk>[JNL?ɔ T4cCSZ%FR^wxV5%F(eB<Oasr[]"s$)YKeNժO4uTšJ>FH4'8D&mieZ~MC^5f:HTK*wS%E'<ݶGó#Fpu.Rɓ; e=հ,??r9V3Kھشx:0#=z0@j{AN\b=¥6ΰPK DJQB%0z zID,E&AK%)TشGN{:L7%0(FFhN~#)7S9n_y"Jx{@syx6B<2Ea\V Dɹ{ϱc+Sti (zD2G>ůq<Ԭ>e (T龲Vإ0rҘO%xK82^/cpϭ+9qH\u>{+ƨ2ykSoXm[og!iH"ߒq;ֳ2yKR/$jv$eH`puRRs6mO$fɍmbXqlE ]$5Fe/yLiE:y@޻>~5$IzQN( _̌X*HŔ$ ]ߩ-hAav+Seֻ۰~.3'@ϰR\io襣p9!ZHk[{|ݜ(*dIǾ͟M"jNJ3"HDqNROQ'I|S QR LO'3c:e[.<3%iE9toDs`  ƧC.+<TbX{e( l *Cϖ~?(gJᮬ! =+H(J%.UELF 46`xi`38$r2j!=SL }.Ы(VM^V׬_{ɵD9~Rпdig ;DBa DsCF $D 3Q_`&- ?6BjVrmr`:8Cp F;D`xhuM^he3zq9OY>pGA.g e!*[ իjԀӗEtUj"qy CIuZ7r䏅QjMEƦꑼIM\|HV 2$&>)aŦ,uPÄwgRK"!» ,E631A,ˡXzhsņ8LuOT\`SR h7>7Dl$ z-)UYAd?h3,we$!y%cZYKzkAGjhݨˀA+]+e %W+ʯ@zO1۔+Ѥk.Gc 𺲖I$C)RI,ٗ}͠Y~;%l(-5I/yEK0mYA7'F"-?}pnY8crɅ/}4:y_o'PPˋ[Oܥsrf-g$+ђBL0?4^.uU̙L!Cҙw oaJf)Tq6;7ؕ2ԈHa\à rمw%һSYsPF nV'sf!ʅ 0rL5lv@ -4Ќ3,#k%3Z`@~nf4w4c\vѤe.`zޟ8>$[Dɰ5j4n7nҨ & OuMևDnǤ@,frxN#:l/,hG7BQ6%- D_ "/5`aGQfi'msSa)f.sg,?8gغe^ !G.kTmkd<ɓr"_V y +{74Bq"[af 4\,D~msܛ[DDg@e\vᇕw#"-WX9G\&GD0 S'F!&'LY ṜOfg'v oaz0E^,o(#@> PtJsXNXl$"CD]``ϴ^r9ًbTQjo'un{h"g3@|!jAkPS!pںRY[M/͓ޡe_gSƄڸKCOCHiy'GzѨu@yȋRҥ _x -~^<0~BD_\|]x?/8colzu ~L 815AûTFe\v⑯7܀{),`ldqPۯH^pҥl*-?~h6 `0~3Q#ϟ'xnرc `0 C\|Ξ= =AY5ri0 `~=`0 a`0  #`0 14 `0eE؀;Zرcٳ~0clllw ]vW\2k_|C g>xgJf)?Ç;w'?I8~xf #᳟,(p կ~;V:YŽ"'OOp +W\a=kk.np 3Źs}oﳋ/M77|3<䓅"3l7|W_}^~ҡV*kks\ꫯŸB >ӐCb pUWݻk ;wwC-F.+s=we'??_",`Po< |.ahz-?'oۥÚ%W^{ n~ qwKѣC1GpW}8rH #`(5x={0c=zn68wo}[pe{J6;;wtf'_0'ñcot8뮃뮻<777`׮]%Cle%G? /"}7\",`P{-ab޽[oٳgK2;z+lll/<\{Pd xamm Jcئxꩧ+ot(-W-G7|nF8q9s?n[p)x"\p6O&X>|vQ28<nv;D"\x= ?8{nwKf1>.nfye4pYKg>OG繪Mo] *Ü#OSx;\}} o—F. `0 b=`0 14 `0ȥ`0 A F. `0 b0ri0 `K`0 \ `0``0  #`0 1?ިxIENDB`docs/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png0100644 0000000 0000000 00000030763 13077405420 026571 0ustar000000000 0000000 PNG  IHDRRM7_sBIT|d pHYsaa?i IDATx{Xu ` \L4lxHM3fAkӶ"(Z7ӲnkPn.b( (ܿ?D~~|\WWq=3OO{fleY {T%!.` q cKC\01%&M$ݮoH9Rv]vdըQ#5nmnWHHg%Pv<==UV-+fs>β:(fĉ%I.\b _^[nջ Y*}c$("##յkW͝;W_ԨQ# 2iӦkqܹ7o.˲m۶zUNUZU 4ГO>Gz{۶mP5=zhӦMFg.Lsv.^_]zU _ \gݺuݻׯUvں;U.\N:)00PުWzO>Ϟ=^xA 4Pjt뭷jh" 8PM4?Q{ys)g_^}NVZ2d~Bok˖-ٳ}o޼ZÇl6yB?00:|uhl6kEz,_eeYҤI!CΝ}{=h̙馛n{U>}_*33Sҥg~guU}q駟VPPu@3o5kaÆ)77W۷o~:oo_9vT"j*fwuz+00P}կi޺J*;vrrr7owgUV=ZuVNHHPHHz?MhMDFFnݺ_o߾رcլY˼4x`?^s¾6Mƍ$Yglz7e۵pb?_eؕ v}G2dknզM@֭[}vt预뚽3j۶mvͦؿ~'Oo>|VX;jȐ!֭t钿oQ 6LZjk׮뮻W5k,4t.o瓤ÇkZvtyrrrR;$I oԩS\ڵ+rl^#G8mOKKӛoJٳg.9}/7nСC_u 7((l6.^(Iw}QFiȑS}$Io5oTԩsu3g^F<=/qu{"IWLLf̘ ߗt)MVI&5uTM:U o] $wy:uꔺv*!???yxx(11Quܹ]s)lfk]v…mNRtAuQ#G<==uI͚5Xԩ$edda%Px{{{Qv_ r~~~lP.SRR رc=sqg*_yfShhvء͛_v]>}Y8qB7nԲe˴|rڳgJ4ot-ZHaaaN-]j.jKuAM4smڴIfͺuSRRt뭷~{y,(9ιʑo]GVRRoԩ,*\uu \vEmܸg-L[!!!1c׿ܹsZjUn#00P'|߿_{-Le4p_\S6lP\}.W}¾PRR5jij @93aUZUoN:%ҋ=4~x߿uΟ? ;wVfjʕNΞ=[,L%:jJB+g lpeTZ׸qcYIZzϟ_`\M.]x9]6o<߿m1yԄ+;vԩSyYf9}}nn^xYGy8P|z'5k,zլY3-\PFRVp8t뭷… :|6lؠnI?c,X@=zpΝop8 Fqd&x#?Yҥ6l*Uh۶mWÆ JgϞw߭`mV 6Tvv֬Y}O>kk3f>C ֭={hHÆ >.o[F>+(N{rꈤKuP$>|pגɔCeqyS-K㼗b,o%tS%\+7eɋ5w]ZBygQSx+"C\e΍oRwzeUQYs(eެ9W#.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\Ⲍ뫑Ӧո8}/rr4$2H}ի()I=G5kp(}}i4;.N_hKNFq;`-[ ژ xxjg> 6MK;%EGrr\\z<>^?HNxbw_],nPѣM+V\hYEn ڽ[+gOyI\Șu:ԅSGKy* {yUVMѓ'iCs#"ԬM-ٶM[p(4,oͭ*kC\v뺨8@:kՒti1|"_wڸ|Ӷ-11zltVTGRH޺XwթTm[F_&&jظqz'ΊȡCjnbM:u$Im~%3bzxɿn] |jݭ2Oԯ0a¼y3r|nAgN-[j箇r9sT7Aꞷ6icyn;ݽ{˲,5JFrկ??I:gf4H}\&M$[ޚ} ?,K#ǎȼ-^^8P~p|_,KW B1oM6Upp+GUz4uTK۷o߮vnI~$JK;uڹ{T mۦm^s"sYVBLOOϿ[oO?TUw$nd(wWff>3-Rz7'r* zz衧zJtRԒ%KN@TO?+22RjѢ-[j>#ŊK___͜9S3gt<(NJ|%{KC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%ttwQwJuwHv4c_1%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` qYFyӦiv\NIі,u0@Ӗ-ʄmʄM^X\<5;__Oqqڝ#99znzzm}u$'G\<1;___M6Mt<%EsrY5'IpBOIQnFpbw_],jR$˲tݰWj=yv847"BڴђmԸE Wr? @ݪbF?tegkmll+ @GVsUREkZ!!!Ϫo~JIIQܪU]961P)V-Ix"_w\߾:m7D 7N=YQq9tH-ݍZuiz^$鶶mdFT,ޚcXs>ZjN;_$iݺuΝzctu%3|zWZbeff^|ES튊rl0f)b|sgE r+.SSS .80o4l&=6ĸ{0&--M_ޖV#zuzxFtII?K3r^}Q-]qݻwo/n$ٳGB%J|%_WM7O}FԔ'P[yСC6 6L7oVJJCE}.H"DoϯWgC޾QCԲ8P16V粳а0 Rʑ#fRQ…JسG;v̿ ?;wApW]Ӗ-*;;[3`X:)9oI߯a&;ڷWٳ?/͇r$IDATrpW5\-50o-歹 S [s .1cO+ĉS[սG=}_-ݲtmq}U§ SSSUvmM4Џھ}ڵk|Y JL[-R&Mt,)I,PhXXחWABχM>xPKAQwPmNHPM(9)Io/XAaa__v$''-^^(J$$U\&M (,,,ݻ|||cEDF*>>-u;kY'i۶mj+DA;(-ʼnK01~Ut>}Zw^}gPy{{Fr̘1:t萤Kγ|r-_\6MjР!P>;.]1*ι1%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\x%N{TJ7{Tq_1%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.˨j9m^G))"'GC"#t?w^]ZٳZ|^[FOW6MuJhtݽhڲeZZɋ~PFyƚCizeuC@z-//mZF*uk݊?^={jΓO*EĨС.]̀=Z^^[wV]ϫJj~\DEi~]̀JMuPLLTz'\5**\9EaY i۶mj۶5@^10*[1ݕyIJ=vLE75*0JW .+0&ЉusӦbLwJ^ƪӠQPIP8^LU=%IΞՌõ%6SP:{.Jk9.׮]ŋkӦM_t7}߽=>xɿn] |ɜ b͡4q|"|'NhjժN83f讻իROb-&$H$mĘ=;,~܄ya4qmq8Xs(M_q9{lծ]iPpp^uؿe: TƉTDtW}TqK{T9WgE~Aϕa)IjѢ9bt(Fnݔy~- S#5'xA%CYu'##C۷oWM̓hpkԐ$5hR$ml={4:(HybwT]:&o}#FU׮zo"A1*}}哷Z}yncleg+":Zaau¬Y7jXP {uǎy9g0(Xs(m_]rرRxxU+o͒9sTaCI>ˠA2h,cM(5)Iv]6齺~;u8PO?-nЙSڻŹ᠜xyͺ>h筻MX޺NKxw޲,KFRQn3A .ǁ5~Hr/'DDDhʔ)={ƌSr>kDT|BJ?'**JSL믿^hXr*v\FEE/b&SŊɓ'+**JpL(3fhĉr8yf.|)r\f)..NqW"fŋƇ@R丌wJjq0%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\01%!.` q cKC\0,~,wJ&5Rƚ;p|u=ⲌJvtN{T:9W#.` q cKΖ$eJ'I|J䬻(.J:˚C)b] wPq|-̼gee.DIWA%P߿ZrT.]Ͳ\響Zz5j$oooWJAvvիW/\s_%*^cKC\eHffƍz[mڴ'|Peff_TϞ=(ݮ(w lڵ1b6m*___կ__kժU5k?KPFF4hSjժUZx5jє)S=^[_}zKꡇޫW/ݻW:iii ԤIqPA?~\kvvuZf&CeөS'%''СC¡Vʈ+VF4hGyD4* peXJZh#Ga"TVjՒ>R#.ˈ={E$I{uXrھ}ZjQPY8qBsիϻ{ d/#\`P;VYYY w(z)͛7OᡷzKO=KDDD?ٳզMw ,<<\??+WSvv^z%wVeDZ }v2===rH4e3fAw-[n$9Ir3j(s s.ˈo]?rss޽[Ժukw./qP uA999JLLt(qYF_Ϝ/ZHSǎ45ydEEE)""BT||<<<Q*~-^F8CO=~Wiҥ?%KpUV̙3:}KLp/9vx`f̘'p͛.뮻4*\~~~Сn&jO/rڙ &eș3gO?TjѢ^y <ݣkܸqllJLLT 9*}fŋ0*E?O?SNz;ciСB".` \01%!.` q cKC\>@iIENDB`docs/images/camera2/metadata/android.tonemap.curveRed/0040755 0000000 0000000 00000000000 13077405420 021741 5ustar000000000 0000000 docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png0100644 0000000 0000000 00000075406 13077405420 025265 0ustar000000000 0000000 PNG  IHDR7?{sBIT|d pHYsaa?i IDATxyxT>{dF E$ Z(bQ[]Pq_[tSi-uAQ*P7?&$jbXž}IyČ $sΜ?u%gsɝC=N!@DDDz """HlnHS!"""MasCDDD憈4 i """67DDD)lnHS!R?P|")**¿/p/B24[o^ݻ.H3 7O;~쫯µ^. w?~~)~a߾}}:ΝKbȐ!JBF Ң{/ _WϿ[V^ 466.\ Æ v{]ԩSBkꪫpUW)]ph+_W}믿رcZ3`ʕ _Dee%|;!""hPr-Bzŋg},88X;V-111=n?wÇ !(//wqHHHfY 6L\{GHzpx`Pk_|!-Z䱼c6رcBӉٳgk N'򗿸uo}Ns- 33S;BӉoٵ{:N\m}ts[ޱ,Z>eDZZí*t:OB\r%l6"~BӉ xWjjv-_~tn3$}{3gnze]&t:LSkk6mtb̙'7xt_v[~wN'֯_/h.gnΝZֱ<.p-eY$$$4ײDcsCtC{W,\Pĸ}7ֹ͛EfffmݺvmbǎO$^g67B׋Z![nckkk]fpp7n\uL2EFZֱ_nc}Q /otW^BqF{WuuG^3g N'?ǎMOUTT^/O>;vUscEPP8s<^;txꩧW_}%8fΝ}gN|k͛NO?Cccc_/"ٲe PTT@@UUM'|QQQزe MrڊoYYY=-))+tR\x}~k.i<^tg1FrkK.ضn,سg&Oڈ#>8yzn-{v9y$vڅ۷;vȲQ̙3=G?͛k.jݻz,??Bdffz;q^^RRL4aÆ7MN퇝,Y5k'? CRv?4(77UGXd ֭[T\r% VO?uNkk+n#455tf|W>|Ç]w݅W^yfB455\u]ŋcB@c׽?pʷ~wʕ+__OMwɜ;wnc^uƺ5&yfϋazt<ꫯ]|9ۇ+χ9pף_^۲e |A_db:umyMM }QXoɒ%nMúuUW]{61{l|O][[[jþ}j*מyp5hs?kn>K/}>#\tEn׼?pرc1rHn6s+66mڄz 3gte$ɭqںu+f̘9s>]:t(bʕ:u*.]cƌA~~>lقÇ㥗^q/=>CG?ѣGfo5 'N֭[1}tL<UUUX~=9-۷oƏ/G둘?{^|Edff";;sEBB6n܈jpݟ;˗/qw7ƌ\l߾sŵ^ ۰b ,^ fNw7zs R(//aaab˖-=}7Ř1cjW_BVeee\r8sNz^Ĉ3g~mSzT7""Bz׶N׿kŐ!Cڗh"&BBBĦMov DZZx\w[^3Bt:q->HKKbСkwK ^?K_]ze'O .IIIbs=W,[LvqUW ^/JKK?\矋y`'nv%2۷O\uU"<<\lgDvv6:sIqwDa2DjjXd?'OVUʼn{GՉpKg̘e㧳",,LvyIw_Tss!}4zjn֬Y#t:x.<~x?Opy饗7ˠ^hX:{|Bn7PZZ("!ka„ Cz)̟?0{ld/TLjWUXvm\;`:?f׮]{pB=?t=.7oJJJ~mNGzzҥhGyB$5NǸqCGEVV^y\z饘7oe)'N(6lJJJЫ+<;w츓@zz뮫;q[on3N5o<]V2WWXmR+uhvx>?Ccc# z=j*;N8t(,,Ĉ#\O "** W^y%֯_k֬v[s&L f+++ 5-UhnkD$B:sI|P_W<,0yd|'er ^yܹsm6曮礐4++=!ZP^[#uehn9?d]~w/𹙛3f@eeNc]w݅[ p^Z[^7*-W^| w|!"""NZڪ ;^hXV$H*/ۿ>5!ո+.1e1e1IjkmA0K"a2^6 #Fcʋ+V<熴飏>R&T1@W^g@d` G#6$l!Xt%5,,hAmKzQoBD`4,딛?asC0@n^ɌR1q m DF#$ k"""?y& `ڬ)q~'k@S*lnHq`0bf)OmӗFRrb6"20SWj+PLj*Kk_Y_Yn^p{n3ƹ^+*^ǕO)#`sC*t ~++_hɚ hDL c'zh !!0)xXTcŊJטCvVz[ vjq56F#V+!9C%zA"""rmiD`2v$58$nko~-' """"ҘVɎ GQVsZWcqYsk$ $aSSҼ_ F6ԴTv{c"OSPqL̘4ܐjdgg+]_cbm?(i>eMnͼk12mԠ;8sCh"Kk_Y_Y6G3[*as4z0\u<\0G*/J\w(NMIČI>lnHE̙t ~++˗B5-K^j@5u)wS B5-hZ{^2 uiCn::HDF7 rI5֭[t ~++K;ujcjl:="c9 1q~lnHEV^t ~++KM;-U(91 ޿WO{)]_cbR"A١R9`2Ñ04W0ꍈ y훰v+*PPPi`|]oқPK8tlj222 &(] 7a|}ڬ)q~~X` n`CM_":&IɉnĦF_f5=FlMo ŤEEEJטB^et46%ť0Ț Wc'h T$!lnH5qKk_Y!ڀõqh4jmIȂMa)R_~YWmMj>VZf2v$h4׿%@$mv@9Ӏ /UWX6G ԕX!?{Hx97,RSҼ^7 fJvT5Bs[ccFMw{q*ۍ=WKČI^/ k[q춱D̸ǮeYFsS[c3/Z>ۇ!x.1e1#jbd^Xbcyab̘: `a)RKk_Y̿od'u |}΀Y#׵]?2mkvFj^_:% )dԶIzhDXP!@DD~)ՠ{(DFà:8V]PR:aHDh0 ruVX^UU 1m8uVD A):n@ yUq`0x<`ۦ/6c6 *h!Ԑ6!""f5=FʂHJNQoBtP,BPbRUV)]_cp Jhhlh4"kz&_M'DLpt(\c챹!Xz%5,5/@sk#ĩ㐝R:b9!a>pK5OR%5,%/.9ܼ*E f0TD'D:[masCD6o߄>X^QUoƴYS0>. Ct {Qo!"3%mDtL4ֵ՚ q}<>cgh4\YPTܘ  sOSC'j,\PW7/9T}Ʀш58v 1mlk gnH5xPe1ey#Ivljq56F#V+!K2GO TcJט3pVJdmvHHYQ_46a)""BkOOȲ[s I8Fe@jJ2gn4MjEE 8<^=6-ƞB`b$K48sC}vKk_YQtj;ml )9fMaYFsS[c3/ZL5 5TcٲeJטsjqjm=6y:s2/Blt, cYp"xw.1e'M'*z` 68VS C#ǜj masCt ~+l︴DZACjja> ^x!N˖-èQ .k֬RDD)iDYmqpkR"G!ƆO47;v@vv6Ǝ?7t~_᷿m7/KtMX~=pcڵ^htuiwWM1>ng o`Μ9o~{ ?EDT**{nL53tpkcy-?0-|ϻk߿0eӧO۷ː/++ ֭s#;;cVr[lTUU-_d ^xeFQQ^zldgg{<eXpGm]wo]_~?qM|ulٶ o յ/ƞo;6}`k79nvyo_V1c&?V\5==FDO}Tࢋ.fÎ;\˞x 8~8ƿqF̞=۵;|W GFF0a„SbAA{Z/~1Y3Qqq1ع5y;dLz3bd!A_9W੧_c…رc/_e˖! (,,Ĉ#s .7ވgys=lƆԁ?XCeWy dMτhDBR< kz&vSvıpkd'̜9k׮1w\^˗/w]ɓ'O>Flٲr ?+[o~|AwoED4hJ`omj7hjYn37pWꫯ3ft ypp0-[dSDd26;$Irkp$I<7FD=gG8T[jl >1@m+vń$IX*H[s 2 5%MmҾKk`mh:6G&_R{ <8$3&y^_[|j)oRD4pV t ome_Sg FDWKfT4G8thl?"C%hsl2#5% 3&adڨnAD]csCDOSBeI4zh BlH̆DEhbR3INz{-tFą$!1,fUP_Y_[ܐjvmJטߴI8Z_S ۱aHDD%; 3e1ma)RK*]_cNԴT a0X)2e1masCԔ{ֈp8ۺQAFYP_Y_[@r:Pt= 2 68& QguT5S8kԛP/UGD] ŤVR%ԕDM5 )#0e1masCt ~s M'P^[dvhŰ4C3} OqP)m0AQHJNr=N8Y"z}0u_ " o x,¾aڬ)q!a QoFDtxXNq`0 (8z?mGˏ>7H СllT37Dwrr\0$ ; o7p?u{*Fvv%5_egl:0Ț9yR"F :hȠ76Z1masCh"KkdǑR[jl:FXVS0=r9!5cRsQU&S93v$58$nko~޻˰_[8sCD*Q^WS?2>1 2vń$I:F۟򝚒LD/!"M:stǦ㻽ESP݈'fLjD408sCn:KkZʿٚ%%'bڬ)eYFsS[c3/ZLzm!Xz%5-/@usזG'̜: zf!6:aልEYx1c,/UN 2-|"*q(Z%{L3B`5z2"@Dt!jZ*QR trthDf|D憈|]Tgk̆ Il `sCD>G'[*QRXo'Xp%5_lTDc+kܐjR{}F#fkԞ1masC`KkjdQɭݎ3_[j95 Ad`O`sCD5D48'ە.%p$Jzll"c0,"MZW_[8sCl2L:U2@n^Ʉ!15f$\/`DM45+k Rw}W߼}ncyUU% ôYS0>|ףc έ,-@>-0wU7/.9 AoGҶM_h1F E!*(Vs _i_[8sCD^x|8dMτh$Iع5yE﯄tJLD>D{*>chDL NacCDTS[t0ZOvJFWRe1ma)RdKkSȨh:{&nC$G$mO0&5,-!ո. fv kK`'dYέ9$ \Ȳ HMIԆp憈*T5r[>zl:[(ۍ=X-lpN׸Z/ignhP8dhl )9fMq}.2ybd(JD™R"=Z2@ڀrc&\xF ;{ Qzm6Mfab$kl+k R6lP 5;M'PovhE|P΄~VpW67/%ol8S#c֜!क़:UDzC`5m_Y_[Yl8GSB1$8K?csCDgBa Gh@8CRpR^xAZow '*xn"f`c 37---Jzdlj#=4aFtP,t:[E' @? a^Jt:!5l:I!I4{:"e37D-)T145v;.DBDO!"Rs[N6씺10ZQqW"Xt%A١R$E~hN1茈 MD9je1masCԼkMXTUW -´YS0>|u#OpPq`0 (8z?mGˏallHS>1Y3a4!IvnAAn@Q~OE|P[CD>37VRQv@MGchDL ΩHHcc F~~%6-X-0'p0Z섞P bR+VPklmƣnC$F,y)$IɬXO2"? @UIh(S8e;@oq΍,?;5%Mgn4NvJ8p-fײc"@An)(jfSvM̘z37DfwpĭDL5,hnjvkle_iV+@asCt RoőRHNG87t&]Xl cY^ؿqW"Xh%h^kClp)dlɛO(&Xp%RGjKmlB14<_ WWܐjp(D,,-lnH5,Xt !o8ވNp!Rfh<)u9j 1 &/VFD)rrPvmm0 HJNtpkb". ş}.B!%%?||ǘ8q"1tP,^--]O󓲶o߮t ^y&?#TTUno>|o= vA$o Whnv؁l;~!n&Wo. w>7  mcތ4Z&_agy&LovÁ?0,x!/^kV̘1,_DKK $L8%xMn^5=F$aGtą cΖ?F_Y_[T?sڊ-[kq[>o<455a۶m xdcR});T }Ʀш陮H6 _W77hkkèQܖ1P\\NAAb+@`` "##u&V;bFV K2O&"#77uuuP!!ihhXsy睇O?/ꫯ[n䊉&@e 6;$oI`7?f@DWonݾ{~ mmmk=,Y5kR+c=t )8P:{ ,cWq΍,Ԕ4էՎ+kO( 466-u\qn/]<s򒓓.aHN .Ǧ㻽ESPt71cjr+kgn`0pA3c#G5G;ge]lYYYXn۸?w}+:#;;UUUn˗,Y^xmYyy9QTT^ˢgXzuTu\p:~ֿp׹HJND^n>J475ߟe_iutW__ߏ:Xrt̛7c=Q.6 ;vp-{'ꫯp܌8dggv-駱l2?~QQQn###yyy0a~A7l? Yȝ~8#hsl2#5% 3&""-߿?,O=.b̟? .Ď;|r,[ hllDaa!Fhg#<̝;;vez46D'@:2M ^JD4TX fΜkb;w.V^˗GaO\qXxXJyذaeU'QkrhEB08B++oKx嗕._‰GyAć^IS_1e1masC˗bN a~|%rО=|9-`b憨rCnrLtP"Qml IDAT Q?6?:&hp?3oHvM 8RWec35_Y_[8sC*jSgAE._7MH ŋU/E_Y_[x)x)8FާPkrLтa0L^7Rp"91A/6x2"":^27hrL% "HadԛHxB1ƪU~o‹3rAEUPSS֣ oЀp$hv+k R|Wqs ?ضK-o?&20CB}x3H5VXq}<>cgh4B$ܚ#Y#VR?ybb™KeJt46`45=5Sy/""-asC~|t0Z!y6""67wrsg6;$ɽ$ v`6^RAD!.! 2vnq58Ȳ HMISטbRE ;no o7bf)𸅉&5{_Y_[|;ğgM͙3gжp1m,٭}-Ff01e1m𙛲2,Yv}7MtVG}ca|Fwqx%6Mfab$jld3g"))i7KtVGpuzZj~|Ś0?Rg^yB[֭Iyc` IÏS諁Ο+kˀ770{lwCnn.N믿@%iիl[CGcs; dw_Y_['~3;6m?>}:f͚Yfa޽ހlGrvؘ $9@Og+kˀ܌1<>cTWW>CVV>cL<ӟ-\$~pM!"Ҵ 6n4"++ YYY/Vr-D:2ɭn6 )|8""b띞Xc[1!"ҼonV^ɓ'^niߒ4b…gq`b2͟g5 wyg [FBϱ龱Iac C O_4iM~ Ҩ iMw6H KQo4bb2}݇_K/͆\#?%;%?naa4!"7<3J ; z@%Wc#u7cƆ_ 97 s9}7ޒ|{#;}{ccbcgɟWזon/_kSLA^^@%iIJe˺}Ƅ66gip1e1mf-I#}._uz{c3&yӼecǎoFxx8.R,_p:Fii@%iD```ec46F66; xsȑ#{tT>gL.r"&XP$@cOQZ^ b唈K ,+ЊGZAZ  r{ -iFC̼3{?y\׽v; %%%ͅjM7݄Yf-IZUkwn~pǜ9szQUUݻ`0-I^| KDzՊlѣs_OnP|,/Ewcr1u {s/c޽_&Lŋ1f\x1oG*ү_?Wxu#vNMXOr0"/8|,]ot?8&*//Gvv6v;dY^חOѥF\: փH "37 3x'OSߒT9yƦ""O(njRޝ<~KcGn{8FC3o>#""Ç֭[ߒ?J{opi\x _~q[6 Dei_..aonx<8~o&oIq&w_⢝<}};y.AӘ\_]}YɓXn0j(u]~{EaԨQOӧcذax7qĉpNql7e߈1#{lѳ;v(C}ԑa\EVzj%hK/r .]x瑛/HLL=[oEQQ~_aѾnT:ų'0 3F}_ +Kw?~"Rq8w$Z`454HLLD}]=. XiWs/ܼxڽދgy6 eee9rds aÆZR7kpn7͏ą}uO>ƦEZZ֯_7x#:yͫӳwvvvc׎2x< jJAA4ե]gn,剝FCkD-8Ss .C3/o?+c.;\n9#oUa\_]6d2H՟Eз_:1ǃ756mwaPשUO?4ե]gnۇ-[[oEZZZj"xݔ=uOÑ/BU98]NMf HQHܜ9s'O 4Fs˖-4iR+7ugO173DD,5`b֬YHLLī|??~pgNf9פcr1Ms`HJJBzz:.]n1P‹˧H99"Bbr1EsSZZ ͆LlٲӦMSO=ŋK.޽{9?BTUnP<ENצ1\_] h~YYYxW4w. K.c=%ӟ9,Y={Fܸra춗cp497ѫOO hJB^+%""j?sԄ۷;];"$A1\_]bt 55o<%%PSܞ={sa0gOm/M7= ̘y?|藸)F߱O#_8-[,*Cʘ\_..1ܴvE?}Q >c3f$33F9cF>u:j5mذ!jE\_..1t P[[7{Z`X`n7n7zx7 $Z|M шDE7)t_./Won222`0W_>lذl޼Brr2f3f3cL&A?1l6ONNn>6-fºuaP]]7pB:u 6 _jΝ7pPqA)S>|ЁxY~s;/}"<99999^z%!C`Q:3mo64667O_Fee%_> t:֮]tt9ΆnGVVVd?P *><ҔƮe&T""RH|:7 , p= //Xb-[b8p p 7Frr2t:&ָ<.\7?+ÒhAcc##oZ]sˣ~b 77wiҤI(,,Ċ+v;FA_Cq;Ww}[xHM茞}%UFDD>qqYB}nzi{ԁ͍F4Xx{50Fa{\y"EՅ͍!.GHtrE͛'Mcr1рKht5(&wEzj%hՅ͍ynTםU<%1-jboŔbFO˨7[Rw EktգqQX^ Q(ܨ*O"N2 9!5M(\_..lnTby8=M:#ZР<院bMM/Z64H4JJJ0zhehՅgn$GI^XchDΘ38NV#Q""bsaAcs`֭K4/ SSʠ37K&.AӘ\_..ln"+p(.g} 6n(Mcr1Ms`HJJBzz:zIDAT.]z;N,YCErr2gy.WHq").Rl6dffb˖-6mz),^8sy<쳘1c{=DAAfΜ憈(r h~YYYxW4GrtRU|xh;?Gx%%%@|y=Z#<^z%!C`a"?^͛7OtU8̟?_t:㏷=v v{u\s|_[%h oF`L0sPZZ+V`ٲeHHH@mm-ߏ"-- (((~}(++{L߄Hfٰa4bMnn.6oތ bҤI۷/VXG}`1~x_ӧOo ػw/rrr^Ka۶m3fLUZXlH{A[.R0\_]tBr;F#;;vYYY!_UVS2vN`DDD n hl^"""67a|]9b&̂L2[ӯ_?%hՅM !Ш0yL˜9sdi_./W67a$EDD-lnˆe&x_\d8EՅM)-gaGgx7o<%hՅMx4:NBEgղK4/ 0it7*s2qVL\_..ln„67a4X\(܄Bq2Ŕ6PPP Mcr1  ^ O4%I&~54(_ڣ`r1[XkPG\xUuS#9!%\%NGᙛ0ht+'rL""csJwJ 0!""667ƹTUWW.AӘ\_..ln:Iό3di_./W67t>LnK4/ R:s`2%T5KBbr1uas^CaDnIDD$ hr7\&mas&[8&$֭]1\_]trs\v br1uas"!Rzc Ś5kdi_./W~ q#<\H.67!jts>""X&D\(6 db$ulK4/ x8=Mo1gϖ]1\_]܄eFĉei_./W67!pp21Qbs20,!""bsNKfuV%hՅM;5 er2q.AӘ\_..ln)d(W>7n]1\_]ܴS#7$""lnکU0`7H\'^w867"+//Ov br1uas\/B\_./W67tƠ7¨f0uT%hՅMyMnGxb6ryI(i`yT.AӘ\_..lnڨQa2:X,3\-[&Mcr1ie1pٰa4bo6pzހqje21\_]ܴ#""ln@憈(i&QB55w\%hՅM+^7\g8ڄ_~di_./W67zInΜ9K4/ Vp>""J͍^gِ """j /܁{J%Yf$ηj%hՅ͍;t#hPv̘1Cv br1uass6Lf/Mcr1o8D^fSh\_..lnt;yQ|`ssG憋67WhRhn̆ h˺udi_./W67Ww/IEGyy4b Dǚ5kdi_./W67m;VtfeQiE)67%lK4/ Vp2q̞=[v br1uass:YfM8Qv br1uass Du(7|Ç#)) Xtiyא ՊC{J^"""?qܔf!33[liSOaA[oaO;?~<xm~_67ѵuV%hE'h͏~#\|eee`΋2dcÆ {vG x|yy9y0nCa#HINNv% br1<-߿vYYYay͘?sԄ۷;jkkVfCQ|ss%@jjxJJ &,iw7ŞonZf#i1ޟ}jJDDDKb~RIN4_.[w9-N?yx^,3Cf~)eY_./e*IX(FXb~*t:رcGs9"t:شio)t:8uTs*++E?ş޽{ʰqq+m݆Fƞx ˨DBBBs222V)S`߾}A3g̙3DDDT^ЫW^_ `„ {RX˖-CBBjkk~ 8iiiwCnpww[o7|3;\"""8s4pB:t}ŬY裏`X~=O{K/+VO>OG ""(憈-bVp"""Ls#cWqV{w:Xd d :< \.W*VPp1brss#Xᅬ#Fjk#<(T>bٲeΝ;cǎ>߿a*ܹSL&1}t ^/}٠im}9st_bJ3gIII@˗$_"C(3<#t:͍pJ0 bƌb۶mb"55UL:5C( -Z$>\^ĉbȐ!B׋۷_Ds3qDq7="%%E466*>gbʔ)~cSLXj^XhBӉ֫6oQQQ!Vի7+ ߟ"##CG^ ߾}FBzş'ѵkWѭ[7ZmnRUmm-fΜ 7>h ͛Rۄ ӉӧƐ!C"]*EE?9s?Cꫯ`Z#Zַanݺ… U>s׿F^^LJWMw'䟞իWo6fskQpbѢEx̝;~).\*UB|r=z~oU^]tA.]p}gi8ý8 G6m}݇qƵ. -Á>(4!N';Ē%KcǎœO>Eew܁}aڵ:t(")) ?|%WUu4˕+W{رc{d2EP % @ vvC U$['?~#smBw7x<nV /`/\&##!`RÆ xNf"Q*[UX,37oߴit#FFjo}tbĈLڵ罹Flj;رcŸqUʕ+NfXh0bܹ>Fjo.Kdee=z?񏢨H,YD$''2?J۶m[:7Ds#[l7xHHHbʕc-+~Yv4hX,"33Sk.[5ړN'zt~?mYݒƍ: ?nA$$$KFlhobܹbРAjLQPP \.Uc۶m /w'"""UQ"""67DDD*lnHU!"""UasCDDD憈T  """R67DDD*F)q:~ÇرcիnF_}{XhzQ,RD6n܈Sb͘4iot?9g$XRDJJJz߸lF^^.]u(b"i4h]067D._5j۷@DMln(fBؼTWWcÆ ]w%:"Uln(f<3sal6L8_dFD1Q*..dªU. V+Wȑ#%WHDQLjjjBN0j(./KQLڳgN'ƌc= @#//Jl6c71cŋG3ǏojjlC=^x7&憈bɓ'Łpma˖-W}Ν;._nfiPUU>^7 &ѿoʠ1|o`Z=vLDgn(aرfٳgׯ5=D>ln(r5<}ŤIpqLhHDQRDuVڵ ömېO?VBii)wGy%%%&H:7DDD*,EDDD憈T  """R67DDD*lnHU!"""UasCDDD憈T  """Rr‘FIENDB`docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png0100644 0000000 0000000 00000054242 13077405420 025651 0ustar000000000 0000000 PNG  IHDR7< msBIT|d pHYsaa?i IDATxwxTu{B 4)" %@$ ` +E(ફ*"J] ۊ(jE" *$ <"(XQ7* 59YIHsޯ̙{)˲,8DrrrrrrrrrGڱcԣGӣT؞={4k,eݻwWTTch*iz׍p ƍM8xLPazg*--MFfڸq:uիWy}7۷tI'ppO?͛->|i_uA38UW]@.HBk3yd:sN:I7|~IҡCԤIlٲ_([η,//OW_}7n8u%`IRjj&O aÆzu+**JSL|( zԹsgծ][ZҸqo߾ל5k:w:u}z衇/***J~aygϞ}>wݻSNю;Էo__W~~vڥoYM4QƍuUWz/wﮆ *66V-ZА!C}v .?YuQVM[lZ_/\Sf4|p}~=vG{t9nݺjٲnu<#<38CuQ֭5l0رw4EEEiѢEWÆ }?ϙ3GQQQzWճgOժUKꪫ˗<ǚ5kQFٳG'NTUV-lRvr@_}x=z,KNNښ8qեKX_|ᄋvxUV=C&MXeK,bcc X#F&L`y晖nf{<뤓N4h`qր5kXiii㱚5kfMn<bM<-˲3fXjܸj9jӦx[n%=wي."k„ օ^hy<-˲rss Xjղ d}֟'X^zU\\oݭMZ-ZRRR &X)))=99ܹu]wY}}G;-cuź;cZɖZli۷wx]vVFdq[{QFV۶mDkW\{wÇ[ڰaeY[O-˲{1X-Zn6/UN]v^x2?c˲"w޾; dըQ:}N4x<֢EM6VÆ }??u$뮻-cxq[裏,˲]vY~x޽{['N:+::ڊvywWn<k:t-˲XG{ޥKZǚ2eeY['xռysoݯ߿xK{<+**Zxq%dVV֬YݻMZqqqVaaeYyqrs3Ʒl֭Vttծ];_)γ<o/c͘1/X+Ve֩S'N:_%.XO?_6ׯoÇ}%Ou!m=z<gYeY}muݯ4Ye]y啖~m߲?fXiii{}qX7poYY"7|cժUj߾O?ǪYfٳ-c 4:|oK/Wܴnگ Ze%&&Z7l-ZX۷-+Ƴ>ŋ[߿q܍:۷W~|?רQCzt+IJIIQvko2ol=Oȩgo XJ[ڶm-Zȷ +t%–-[|;|-SNg Ȳ,͛7O5jP}[$iŊ*..STTdȎ{^z,K?Cm%7n\-+3ˢ2Le]V]w<_~Y_}vڥ{O]tQ)h4HQx<~x&MT-*g\n]zP2[!Ch׮]zb d]6lXBpWu8 Y|M]|~:,I;,ݻ5vR]On[vmϺt"~Uaa:uTiÇ5a=䓕~޲deeɲ,=8pڴimӦMo޼9`??to"tx_oUE׮]%9X8 }駟nܹ%I5k֔k׮}ӿhѢEzWn?SXO>_=(7q 0@5j]wݥݷO@}~JOO8/]wݥG}Էlyɴ2RSS%IwV_ .~?%kРAִi|;JGw!ȿ+ .Pv4{l}~롇*UUW&?{WH<߯{eY{TPP#FƄ k۶m>|xP. 2x`լYSSN;ͧ~ZyJ3dY &ط|޼yڱc.bIi&Iz7s7jH}ŋxb﫵X 0@6m?ؕ+Wos=FUslj'/XK.UݺuuW^~}͞=[ ҙg}yZr>%''뮻kjJ7o֨QԧO]q~v;O_3謳R>}O?_WÆ wtLY3IG~iر2224vXuEW]uj׮ŋo-R JN8קOOW_mjݺuziӦ=HG#g֭}G<䓾ƌ7|Sgq^{5Kjٲ駟>c]wuS~i͚5~;MEyZdYfɲ,-_wK=G視X<~gM EĖ˲+))I}}?/XO=zM4) V&M|'+}v-\P:u ;0gŊj޼y3g5j3跼_~?mp/iSo[ov믿Çk̙Gt#.RiFSL'|O?].\_U/bbbB>`7Qnڴi۷Eʽ͛%᳤|8'O>DӦMӊ+oaÆӧnߡרThN:裏ŋSzԵkW7RZQn6l V%g< ՓT}={1᫯}NYfzG#5}n*8CDlC=x%kΝڹsgh~7ok9ܔ.|۶m~G cǎٹsN=-Q{v~-ZкuVpYnԶm[ׯokDYWsN]ml~zi-֯_?-XEfYo͛5dܹrsmڴI v<JMMUƍuW.6>W|6ڽkx꾧~NlwZV15C^ܬf͚JJJ2=kYo;KDY{!֭,Y[6|p=3zwԷo_ZJu܍O픨CŇݮt`p|3,7%t]EEEˎmoY7|s繠jdI`oWnB tzN:cؔ`c<yn(p;'t #EfD>7UC-OWltRogXx\"Y(7e_ZZ\"Y(7A /4"Y(7Y(7@ rPn*zGp57"gT'LjoE,2=)99YXVT|HRLT *rSl(7UD(7@~(7D kzW#,wMPpcԨQGp57"g zmzW#,wMQp0rd̢܄jMjoEB  Neee,7rBʙ7o\"Y(7!F (7a@ |(7aB <(7aD9T#EfPnŒS6jEfPn nGp57"gB 4(7Qp>ʍaYz\"Y(76@9"##FfY,Hs5=Yo; F^pLjoEBrcCrcSn,8ƍ3=Yo; VpZnmzW#,weY! //OURRqwv@RoQ*&f'zB-7m[pMP1e#EfPn" MjoEB@N-83g4=Yo; &B9p(YoEB`N,8T&QpGqt#EfPn FfY,\~vBep@$ (P܌rPXpMjoEBqH+8#F0=Yo; "थ,7rRp"(5' ,wʍKDJ(7.Be\p2337"gܸ] N^^^X_,7/)_ .0/ ܸ4PpB${F,7rgԨQ!y^T EfPndݻwПGfY,0ܠT@ܠL.8AyT EfPnp\,8YYY~TEfPnPpyU7"gܠB)(70  PnP)QnPi*8UDfY,TI( g5"Y(7`s3U\522hѦGp57ʳk.IRlٳgO{衇}v]z饾e7xƎIQݮ:Pub'ULtM[n,:QQoHW^yrss5k,\R+;ըv2M $هh%?~7xC^ytM t=衇?Omڴ)Le[D1e˖-Gp57}ֶmܱcǀ|璤?ogIg}V]vez~RRRw˗<~ȑ['׫|&MRzz߲) IDAToF^7'x"`oByހkdee)555`}]p_ֽc&w|BonqH<$ix%"}?Cϣ{xv<}Y߯ׯ_sT*{ի߲ۧ &hwW_}Uo/ط|֬Y[k׮~Srrrss7þ}p~nZlw{LT 7|#YoN(~~bItEWjjrrr4c edd(66VڴiԤIW]tѐ!C4yd%&&jڵ?!Pl`;[l$v2'b7"gRԣG-X@,͘1wSnnu%KHjԨ+WjzGtW襗^߯^{[A)LT8yGEU ߈rwl1؝^o; QXXWT,w_K _Q;\-8(86=D GY,ƈ#J]N GxY,FZZZQpBx#,w l)8QfY,D <D x(7 ߗ|GfPn`yyy?'*?"g  K5@ @)؂8@1(8rz~ N#TEBm5*(C`只!Y(7޽{(8Qyo; Ew(8>FvvvHS1CfPn`YYY!{n NB?GfPn` Sp/,w \GPp(7p% 8ף wGfPn`&JjEBm 8Rp0? Y(7(8$p lcզGpuCnFfPn`Gނc݊"g6Νkz7;Fo; gz?n+8vm,w pn+8,ƸqLP&7;o; Ѻuk# w:7cYez;SrrrssdzXQa}k/l͝;׷jƍ{L^^о!0sAwv@RoQЁoYoN(~~́rJ]s5~맽{jժUY~+=o7m۶ئ\B[pbbky2,wۗ/RT'$$HnKjժ+BqqqjԨv2&/7v$կ_oyz$I{ x_IR߾}չsg-]Tw}fϞÇxb(8妼]Grk4m4]x7n&M/ɬqƙWpo;M $I~K~.h%[u \r$iÆ A׺uk#BYEf؂c Y,/7۷Wttm淼;9_iKe$i_>8Z5cQ"?I=z#އ;ag~]tE땚͘1CUAA6mڤ5iDuє)S4vX5lP}UNN222tJUpJ$ZJz ?W߾}3fhر\uMK,=f̘1zrJ]~3gLY(mMK}pƒ,wZ*Z<׫7xuWj !f9|8O 6=+ NX"g z6m.bM6Mk׮Uqqs K!Lj̟,wAO>Zzz +ԣ> 6O? K!͛gzW wf$$$hرz뭷/hٲeJII[onݺG KPrm6רQC))){_u](8-f֭3gN;ƪSN~I ^nԭ[7=>t`$"55f:;Kc=:覛n*`$3e\p쐿Ι3G 6Թ瞫 .@~ 8Mjvɿ|kg}F{ yO$Qra}駪Y_ Ѓ>(׫5k xLǎձcL @ܩRQN>d_)ѤI͙3GJP՜d#;KMZСCe YN? ,A&&&&XOѪUj*䨠 xLjnNqcvBY&:N:*vd*))8¨pGbb8"k!ĨM6| 6}EzB~ٳg%(8sܰizW#"gݰ<#aY,!ݡ8C11C1D*"@"D lȿl(8o; 1j(#_ EBmF e!Y(7P *mzW# v!Y(7,#W^0 EBm̛7FUCfPn    l#55FQՂCfDLYlv:u(>>^ӧOc>s9G=zᄨ.jOU E&''G^W:u… 5tP{z:uj?}t[N'ē:hzW#l!Yj"&O$ 4Ci;UVyH҆ 4m45k,\vЁ'ULtMd-7ʕ+u5-ׯݫUV؃jذaەQ ;gr_СI֭[|)STTT4Y9Q}W6=T,\ g}ٵk$~~ի'IڳgOOkΜ9Yͽ ##FU^y g})oKTT[ؿ1cƨk׮ A6w\# Σ2 g}iР$oy%eYta>|XeXEEEUgzW#(Ԏ-}pLawۗ+::Z۶m[^sǎ`}[j֬5kjժU_|׻z(;;~˗/ xȑ#,//O^W~'Mte|^l'иq|WU }>l>>Fnog ߇S>Gdz>511Q xXm^o>M0Ag?X:x,Kr<f͚x5j1yyyJNNVnnB@RQ2HGfZvz-]Tf̘{G*((К5k|OWRROrr֭u*)))‹诨‡Y"US߾}3fhر\uMK,)9<g(֭[ߌӺURo뿳DRRL+*kL@Pn&(8@pPn`"J,MjoSpY(73g߬c뿳Pn`iUZaw <  l؋!߬뿳Pn`Gp57"SpBYH$\~@lF~~\ͪJaw lcĈGp57SpY(74#U)8,GEfU7 N; AHff\ fcw l#//Ff; N; __D\v Pp&؆5=YȟS6g6FezW#•?tBmFf3 N g Qpdp) r6=Y,FVV\2?i(7y,EH9(7 rCA6RSSMjow[[ l3Ef17;揪6hzW#욿[ ]GPn喂EA$6V^mzW#"!'HGmddd߬Hߩ'RGPn`s5=Y N$Qn`qqqGp57+wZq|@89(7*(7qƙ߬H 'G lu֦Gp57+ßDz,vd*))8];thDŨ m]3̓B-7-8p (80rزe\rZVpQn`Ǐ7=YN? w3 lc̙Gp57˩GJqjnEmp(Yo󏄂݈rH(8p ,(8 l#==Ff%Faa\rSv,8n jb-8p  Br7=Yn;1b#M4FZZ\"r(5,?T!glWT|PpPFff\"@,8,F^^\"҅p?p/.\\~J샃ʠ"ED *rzGp57+.r5j\" v!g6zmzW#ȿYpY(7>8( (88mzW#ȿz[pY(7,#EWCBm̛7"K,IDATFfpTDLYlv:u(>>^ӧO?;?1Bo(==]zk'@qɓ'+))I/##8t萦O;Sjf͚ ;VԣGI㕞ƍMªu5ĝ[n8+Wk[ޯ_?ݻWV xLAAnրir)/2tRSSMjoFE ax'C(پ|:x:t8>7[p"RPp"q)^oUVDm?FfY˟y(73g,7)8rPX,7"Sp" D @? l#==FfY͟coFaa\"?Ǿ*TCpl-8C(8Bm,7+Spr1b\"?(74#Ef3 yGEfYΟcC D(8fPn`Gp57 e6Ljo)8ƥq"[pƒr@QpBr@QpBrzGp572?'t(7QF,7TР6zmzW#,Spra`6Mjoe)8Amdee,7NSprۘ7o\"?z(7(7j(7(7T#Ef= NPn`,7͊)8Gm 8FfY?b(7D N(7D Qn`W6=YoV$O)azW#߬H͟S: lcܹGp57͊)8(78#EfEz?s1n8#Ef9) 6Һuk#Ef9-eY! //OURRqn(_1Q1jyB[D d߿lܺrPn`1=Yow[6ƏozW#,7廬Cm̜9FfYn-rpڡ"ܔ qzBN.8Fzz\"ܚS QXXhzW#,7ĂnfR \~Pn$ l#??FfY?N(8ƈ#LjoE"Pn`iiiGp57"@\p(7 R3"ȿtZp(7LXp(7"Pn`Gp57"ER6LjoE)//P1T_} T T] zMjoEUgǂCm5FfY_=v+8F޽MjoEgCAa1fٲeڵԩxM>ǼKԩtꩧrJB'"MNN^:u꤅ jС{5u2ꫯjذaӧ-Z={ꦛn+Q٦Gp57"2]p" ŗ\rvޭ5kM8QO=~gժ^bbt颹s 0@ںuk9Cy)))裏LZoEQ3]:uhʕkO{ժUcmݺl߾]۶m ̨O<FfYۂ7k[o_/ ھ|:x:tmo~UtT@;:arӾ}{EGG\sǎϙgY4o\-ZА!C6;*/99FfY~YsK6;Q͛7FġzҾ}[6a͞=[?bccӾ}{}~_7n,sΝ;sP͛~ˍ$w}袋t+55U9991c222mڴI jҤ$Pjj7n+R-ҫ:_Dl=rҤIղeK9Rcƌ$}ٳ̙aÆjƌoվ}{}>ϻ HHH@zz:֬Yj1rFVV fGVVl6ƌ"\p!i3~?~Ǐ͟?_RSSM˩ֿC,_>h\4MS߫Ul65͍Aqƅ|lذARRR䯿25jGSo/$%%ȑ#EӴ>p̿_e;wnxZZKR/׋<<쳁ckk+Μ9+V~f35J'a#G7-[,_>\ W.#;y@3O>!H{9NԿ9sf!)) 2?Byyyرcjkkى]v-2=jֆspͿ!~ׂGWjYUU;wkQ0onnƛo ] 0#?w 77 .Dqq1=իW=tuFraفK7)5g('W7W8jYYY "''g@!cx"/^{'O6+ڐ`^c `/te?OO~a8q[lAzz:n7֮]x[f%oU~ZkYQQ'xvj5'Կ"tww"ߏC+H{C3gNC== ?F_SS`XlfΜUV7no~!,\͵*}ԽX/͛FJԿ NBBBt]p8tV+v*0R{{M3s]bN{A'O'\M\\QUU4^YYDdee쓚cb޽!L0cƌ15JVZ~+WĞ={x #߷oZZZ?ĤIrFHv;{XVL6*1Ry\CC`ر&% o>x\.X,2o<q}Jgg455ɹsl۶M4M˗_|!O=h&{ZǏi%GhA_v]rrr"Y)F_QQ!O?-)KqqqƠ5|>̔[oUyq\RVV& #D z!Ϲ1k͍HuuL8Q.)))RQQx۷og˖-&qqq!;wtle h&E4M -)rrrk`[nK.ƍ_=ұ1{<)..4l!֭ʨ 7kDDD!"" ) ) ) ) ) ) ) ) )h "׋G}OƏ?QFaĉ/_~w Ӊ;3i(pm)"i},X*ƽ^/|I\.?~QLID(>|0s̠q]ב?^4QbsCD1v#-- 7|skF:067DΟ?ӧO+NDC"Y6/p8G!*67Dn733Oܹs1k,|gшFD1_'vaZi&h|lԩSb ND1 7x#O8D4Ťfx^dggm[[JJJ`X={~WBuK7,YxL{D~SWW/d 7n _p߿67D3~g<Ȁɓ'q|>444\E_~%~"R(f$''믿~GbɓCƧLlXl6l؀$L4),(  z. vKGڱcǂgy. ۶m 4=D67D4]U>/=z4rssqXHF$e)"n7>S455oG}}==M6r /^اbj"2sCDDDJe)"""R """R """R """R """R """R """R """R """R """R """R """R?cݑӝ IENDB`docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png0100644 0000000 0000000 00000052476 13077405420 025457 0ustar000000000 0000000 PNG  IHDR7< msBIT|d pHYsaa?i IDATxytT$H !!,QI7+ ,ZF   lи&*h` 63;>2/ܹg1p8        8⋕k"kÆ ?1\kիmxN-N*OffԮ](L9WVΝu-w޶q^ze˖:lx;Ow1jl֭*))=]q+lxKuscn-ZX,[nJNNVÆ կ_?}w!ϱ~z]:TNo^'N޽{Cb [԰aCCK, _nt'_Wf͔}rw.Iz'> poݻ+99YIIIܹ^xᅐzwM[ƍիW/5h@GuBm۶MuGQF+}_|QݺuQG5iD_6lts9Zr=\%%%Yf?֬Y3}w˔ƍkРA{177nT\\Ə^{M;wVbb;8O?:wziӦ;v{J#w^=c:S͛kڸqc>mfsQG~>}4w\u]uQJJ w y>Hqqq6lX`5fjJuQӦMu-_Ti222L]we.bLFFFy;;ӌ1dddg6mjvoJJiٲiذZO>ر#h O<Ѵm֌5\~A3V2f7W^y3fر| / Z|>ӤIs-?&))ɴlٲR}L=o\{VZNZ6]E樣 /g;@VW_}O37pCs >|>cٶm9䓍3=z0cƌ1W_}7)))f˖-]/2(7pg&Otߋ.|>dc1&--$%%u]em۶5G}[V@ƎXVf|]wUj.]j|>;֭[gM˖-ec~sgg^wٺ'l޽ug={n4>|c~ouT1gϞ~;yʠq8 k׮'x|>3xCg^}x߰a1ƘM6:uVZ4k׮:uT̵^kX>cƌ}uM̓ 1Fmg4ibZjXv-g{/^|>ӷoîP|,Abb/$[N/ 7ܠSN9%٪]yI8q^~es1A̔$ѧOj+R7N͛7,_}QIҴiӂ>ЁO?]t뭷V߿ ѹsgIҦM$IuՌ3O|[nBף>t &~9sfl'NTBBB[oU-[ԼygϞUVAZjϗ;I3gvޭ{G{lྦྷv|/8=裊,tw묳ΪK.Q:u]wuںu}˗k˖-k%쥗^Rt7=.S׮]5o<رڳߖ¢EAoԠAIݻ%Igggf߾}A|:e}9vg(>>>-^$I!X&[ze?ח_~ 6hժUcήiӦjٲe\m۶g}]v^VZ:ssjÆ =U@6mBg}&I:3C۵kW!իլY35n8_?믿^ƍӜ9st%Hf͚M+ڳgO®]o>^Z]vь6 W|o$m۶M[o魷:W%%%_n6-[LTvm3_]7֭[uؾ}|>ׯr[||=X-z-++56|3&'~Pǎ;dw '<71FK{챊 ]V"~V =GN&Me~goUxҥ-Z8H|޼ymaڵ0aBB(W$WiiiϾ}o>%%%H^x>_n-"%''͛7VߨQ*?oU;>c]}*))̙3j۶mzu;w_~ ZW>2fCn+oYyիro_bulEzm۶Mo,YB]wuA3Iʶ.J rDi&w^=Z_$I~G 6Lwu{ >sI5;GMygcرI,??_JKKkUe!77WUբEmk֬ݗ_~rǮ]S;v :P^^9昐SN`qSNw}!uAm۶߶m[uN߾}uGhѢE;wԿڵSBBBʃ/у>[VuQnԤ,T9眣-[jԩOn4iy}駒~'~6m PсSf}s\{?88WڿGo*|pvv=[EEE2dHk=:.zWg]֯_?=c[l25nXWֻᆱ=zo[HvkԩSg3?Pݻw7K,QFFw/RN>d՞@͛7ׄ 4fviٳ5o<խ[WEEEA߀* 7ܠy饗^իխ[7ּyԲe@yԤI͙3G۷oW5k֨CAE2@Q:#2<;Ђ t~Uvo寞ئML ̲e*/lڷoo֭kڶmkN k3qqq!?e˟x}Bsӱcǐ>}zc|k5wSiݺ>|xL1fO>3u5:u2=)--5zIJJ21f/R~1cΙxIׯovjf̘He&...\9M{=sYg #<\|fɒ%Ǜs=7p-Zc93<ԭ[פ &:L\\Oͅ^hM͝wYeիWHf孃1+sꩧ:u꘦M<hڵkg̱kru֙޽{ 뛞={/\yA9@v2 40lݺu]UV&!!4k\uUfʕP>cb2}."[NK. :Ν};_ gь3\ݺuUTTĈʹuVٳoK7N<>917 JOOWaaavY{コk裏 /O?kFƍP}K,uBM>] 6ԩji:bܬZJr/Wx7jݺuݻw>}hÆ ~*#;/hB&LPϞ=5vXORZZ6oެ'|RGqDbULPܢE mذAM4 _J =hO됳|PIJJ҇~-^XթS'92p 勉rsQG騣΂yV%U$Xo}.]I5nX={챨&1TUU۸Sw=7UUvO=^{۲el@?>Bse);냾QPv qCeo>cVp\YnRSSu'jܹAg}WնmYem۶M3fէO͛7Ev]yf~,ڢ.8w6~FNoESVlv-$K=5°f֭ޖ? b#IMsK!IWwM\W^)sZƩ:aއam /=]oኍ$R[=sa}<xb#xEvT4kpjJ 8Fvv<"?nz饗ok9s~m 0 3znV#xEv}oNMlPm۶Iׯl}#< 6K. ,4bĈM %c^/7Ƙi߾}ٳV^g}Vڵ*))I?x94h@chT{z{S%Is!QS>S>pkΝ ,=zN͛7+!!]ϝ;W}o /0g7߬O>D:u zLAA222Ȯʵi&1bEw6E͚7cxuRt .5\,iQBBf裏V^ԱcG]?~ڶm?X>~H3]oGVEPlKIRff͛JzRnn&OS~~v7|STV--[L c=/\3f}ݧW_}'&>>8_$cb ]o_U Q\\?@ë{l]X7|,GQ8 $ %(6(Cc|NDE5SbCBc 2Fvc m{O#ȿzQ "ȿy s8xC *BcL6FvDؐPnG4+=6.\~7\~܋/w1za{O#j?Ŧf݅r1b@ (7p ߮O w1rssmioWU؄ۿPng϶=]Uɟb~lBB*FA*r1bTe{O#?&݅r v]ʟblBcFv?&z݅rDrCj&f[oN:)))I)))8qby7Թsg%&&YfU\\?oŊG4,l&//O~_iiiZ` {G=!+Poj̘1z?!*rrrlioWNN"wc!*rE_~G}X6f=UNcO?]f ,'OjJLL zLAA222ȮU\\wA];~-%XoO$fZlzO>ڱc/_+Woխnـ]oOG]_nM6ASSS%I֭ yʕ+%Iu_D5lPvv( ?Ǘm۶Iׯ<99Y}$K:t7;VSNՠA"<1T Ǘ ]IR޽ȑ#5n8͙3G_uDfE͌9FuphbwǗ H^v\~A/"IҪU>'jyG44i8)6./7ZR||֯_ۇhjԨQc*8H T$kY"{\kFYYYɓi͚5JMMG$M0A#FQG^z)//O999>|xHH$)33SW_}^z)77W'Oֈ#$Iڵ|c=Zl.2M>]&L,vTDGNeͯ[J(6KL|, |,ekf{ "Ȩz_M3;Lb{O#GQo W1"16o Œ(7F> R!ȿjRl.w 7DLMؐ].|7|@uQP}|b8b8qUo]_5.6o 1d#xW^$ؐ].8Fvv<+'RE].8R+cl.w Trrǘ6m<bCvPnG4=6o _ _p >/@PlFPlGPlw1~<.6^6w cذaG4/oH ]j oFSOUfff.֣G#xWwBS}ͷ~J͚5 S@X9TӦMV¾f޽~Jx… mi^߉K;K? /P?>c>}p$\"77Xl$T.aXkUZZ,Y'J=\u]ݻwK̞=Zl$od.as#F7O?zK]to]s_*b ¾f?yZҥt颻[w֠ApX[¾fݺu>}z'$$(---/ D'&77W]v /P K%lin?%.a/7?ڴioSRRp jb#/XCcnO:Jgq9%$88_min?֊cKСC5vX}zꩧsN%''_~jܸq_b^a/7Ǐ$H4xp$H/ܔ'99Y7tZnŋG%VXa{Ocz%fɇR~~~_.c{OcH,ZHK.UIII|p$\b֬YGX F݂%#\ueiŊTbbN;4 :4/ TlWؿ-5|pII'N:IzJKK?cQ|||_PlND-3(%%E3}c-_-))5|pm6ң1bM_nM6ASSS%I֭;c'L});;[ƘΉ[b<,?D`f۶m-ONN$m߾}zG5}tծ];C",rrrl9BnDۿ]./7q ]]viРA;ԩSH05khy۷y̼yW_^z]j׮˗>G^z鐯w饗tE . ;#CjڴiA UXX|ܸq4iRвM6kڵA˟z)92hYqq~gŹ垐o߾Tl^:S oɮ=>.}ѧ^߃`==\k۶mէO)#m?|ܹSyyyeGԩSyf%$tM|zg =@WzzzdWoEpH:~ύc?X\sɓuw+!!AEEE裏OVzzz'##CSzRl «b?Sl,b%&Mfffࣦ^z)77W'Oֈ#$Iڵ|C> ׼ys#VeشO=bcۿ].1T4܊8g?P=^D\b(7pN!.w cԨQGp!.w cʔ)Gy5("](7p Y35=Ɔ"](7 p0r8 1*bCv].8Fqqo(_ؐ]o _ _@,(nPl Plb8Faa-ņ"](7p!Cdž"](7pl#8R>".w o16oEBz(7Ql(7piӦl"w1 l`=6oE~`E".‡rXFQl (7p o{rZZNCvPnÆ =B8H߉.w GG ';;EBȩ܄rD rXp"&o k{b#7XAvPng϶=BJܙ,!](7@R7@{(7@Ql. #++5 2݅rLj3rb?XGvPn=Bzb;7 ](7@ PnPn+V=BZnCvPn999G4)w#݅rǘ5k*ōF݊"w1mP!)6w3݅rT   cȑG(WS ݅rh޼BxHK.w1 |bD=7@9(6(7A(6(7pk {EBc5{H:݅rǘ2ez݅rǰUL~|.݅rOPnYp' cҤIQ{-MhPo Q\\~7M?Gvppop(6 xr(,,Rl*'Rr.w cȐ!aNME"TEBcdgg(6UQ5o oQlo EvPn:6 \b1MVSljf.w ڏ\MG͑].\~7\~!vQl vq (7Y@y(7IPn~RDFeGd].8ưa*&r*?""w1zq)6UQ,݅r@TGTpe)/DEBcNGt].8ٳb}#]bܼ[ԩ'%%%zծ];իWOڵ<={DibTP1Qn h{C1~|A 2D?hҤI曣89bZ+==]/#سg&N;Su O?g}V9991b$)33S4j(M4I5JB@88~ݻl2;hy>}c-_<1EEECNݺukI7|Q-f]חbcQVV<"wq|oTRR6m-OMM$[.1)))2eJ̔?j׮\l͙u.vMtpV.wǗm۶Iׯ<99Y}J=ϼy4c :T 4?!SlG4s*^W_}U^{uVᷬ=cǗ,EEEA~h/c=~믿#8"2J(6Hq|iժ~eo߾ct뭷ꮻW_7xCޥ^*ӥKSs;!,KСC5mڴe*,, Z>n8M4)h٦MvڠO=FX~_+VZ[q}uzu׈bx4V|~ߋͼn{Gܱebm=VXbqgb=x_۶m>}ό1Ro$ϋCWlں|B~2/f~iv)oٳ<"{"繹{ukQVV4ydIDAT(!!AEEEZfRSSuGkʕ4iN?t]}裏/---p@2(ʢYf.w(77oƍ^ziӦS.]iҥ:s^VclߚbcQe>E䐿].>c*:G(##CJOO=p0P"(6h bZl>Ev].DDu4o1c駟֏?:uD,"{% +p;w4j2'OZ'g>Ǭ[|>ꫯ-3g|fӦM!ټy91F??ş&M͛7;W?|ܹSyyyeGԩSyf%$~lԪU+~A_۷V^}Ȗemٲ%+sRt .5\,iQBBf裏$RFԳgO-ZHs՜9s:D_L칑=rܸqꫯԴiS :Twq$wӧk [߰}#8 8м{5qqqIݩ:k&>> 2,]L2ԯ_?Cu6f„ EPy7n4m۶5qqqfٲeo8=Qnza8㌠eG6fΝ>M6o߾AkRSS#6[U5BrnGy|>SXXyݦ:+WDsSn-[OVZ_5MuM-;3@54l4j| M8]T*`ɿH7|~֭[K1UTNu/SRRjj۶mGurJ}[vmZ~#:Tw/** \LFuֈVV-ܢ,?\○/7Ѿ8U'M2%Pf̟?_ky.Zu/3a۷O^ N+W$թSG_~հaCvmڽ{wvnK/~[۷o̙3okmZh 6hɪ[noLį&}Uq Wӌ3ۻӐ6 LQF!JL0P4V6# !ڰE(3 ,(?DmqHP(H3~;t`>y>7皳`HipUȲ I\[)OO .. HMMEcc#222pu=ltuua˖-ccĩS\TvgO6CO8'h2zYRRL*R$&&ĉ sUi%l]v!++ `6122g"33{/IIm6!//˖-,˸x"p5WKSTqro{iXgfTTT`0PRt!! A h Qo[nu߼y30(yy9*++QXXdDGG#-- 7o\__l71cIH?XiɓC?~1>}x1OT@IKKKoooHI 2^| wNIZ{<AI;::k׮u7LvWJ5Y_͇OOOL&:Nsb9K.ŢE\Z(?ƍ8y$F!%@ssث !!! Ess5%7Baaxyy9 """\Z(鿿?8hj VV">>^4E߅ᆈ4ᆈ4ᆈ4ᆈ4ᆈ4ᆈ4ᆈ4ᆈ4ᆈ4e "͆;wo߾ł  Ǐj*dffbnԄϖ""U{݋Rōl6۷VucD&<,EDVSSv$ III+n߾҈HnHdYF`` ̙^?۷oS] Voo/^~ȟ Dwb!"ժ˗/>bcc{n7TGDjpCD%2=3ؾ};6mڄG4"R1^ ND%2 rssvFk֬qsDFTippfBdd$V!iH``2lWWӡ둔"OpH3gΌ-g8ptց܃{nHp9TUU!66˷d23g{ss3p-|Fֆnlذe@D=7DJ,C$DDDkyՊ(`^BFFϟZDEEMjD 7D:vuuu TUUaݺuNッ$ ǏGNNhza!"x=6n܈ ׯGYYov:$IϞ=Ȉ"uj^0իWF#qu̞=R3ѴgZa6;Kkiiq1GjE~~X!"a!iWWTvpBݻw0 SY"M!"iKe<|Xx1F梮sEbb؜Ըj"r5熈4HSnHSnHSnHSnHSnHSnHSnHSnHSnHSnHSnHSYIB; IENDB`docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png0100644 0000000 0000000 00000077200 13077405420 025206 0ustar000000000 0000000 PNG  IHDR7< msBIT|d pHYsaa?i IDATxy|T?ϽdNBaQ@B,jզE,j( XQ*Z[ԥb."*?Po@!@d_g&31΅a;w9s'7s=c1B!/wB!}B! 7BQ*n!*TB!DU!BPqC!UB!B !BT:6l3LHNNƍ7ވ|Ck׮.>߹V+|Idffl6cĈ_CRRf3FW^y.W\.꫰Z^ <ٳg !O+wiӦaڴi^mMMM֭[;wɓ 8-Y뵟yq[n]q\y啌yB]"AVE~~>vt롇ɓ'/#..Nj_nz={1Mⷿ-cx뭷 `˖-+W">>/ba.!Dᨸ!AI!<<Ν;1k,#$$'NĖ-[:}ݻwGtt4"##1ydl۶4cڵHOObW\>97wy'xGSS/^xL&;{8s $%%b`ԩطofΜt9x nf 0aaa;v,6lՇy\q>zr/Kmiiiꪫ׿ … 0qNckpB~/ RDuzsYoaDZT8 q{gیyϟϖ/_Βq쭷r3ڏ98czkeeec^;v,8}]Ʊzj&]{c9sFɓ?nƎˌF#KJJb]|=Kf4hdr [b:t(8=SR?W\s'7/Ԗbcclf{/[p!裏u]xg^Q[[˴Z-k $1ƨ!{c\.m7ߔ?q3 .cRngSLa>|1.XBB+--ֲDQQ\\8cSNyn߾}8xN7ny^aРAh42~eeeL3ۻ97gyƫ| }{xA:rܼy38qrI,&&0;[@t:VXX(}7q>m׮]86w\{a<ϳ;vxO}#""XBBka}geUUU /nxg^}V+ eƍj6mX,1vaxЭDν 6m‰'0o<0 ^ _~%<\[[HL0?].}$%%nyd2Gwtt8f}݇cǎ_|ܹ9s&?J}{]J?i$ر¨Q!C r k׮[\\ (**u]'gffzX,33ܹV&M¤IЀ";v G{{;DQyG?яϏ_ۓsv|R477ꫯ?%%)))=~3gb̙=FW L&fϞwyǏQ]]ݻwo~~<!T՚6mz)իquwAdd$?yojjkqhhhD ?C^^lٲN477w|ss3BBB^z%}رc\.&Ocbӓ] 11|;ܹe܅Q3tI?χ:~kllă> 8ddd`ڴi8tPw%%%yrxB=pkuuutz|bb"yN?o;#͛7cŊؼy3c^k)s*nH0ؼy3Fk.w-=)ʐky|87`0|sVWwYy>p/uw~QQQq^o9-Z;FFNl>mB%&&^ OA)8U;A^:+.t3f !!~!VXM6!&&^{O\$ăn'A%..N]y+++#<";rHt 0LسgEǙ^%QXXu98͆nCrr啒>|3f̀Vu<YYY0  s+#}Ό='N@MMsSOrNo455?Ǐ~#k0aT?~V~?^Cb>555ȑ#=Fw{$Z|;8v6իW3[sO5kyٳǘfΜ8cR۝w8cOM8wBl{{;h4l^jJ'%%I+::H%%%,66 ۷o,++JZw<{`}q^DQd/{}Tjj* &3枀=zhf0ةSc5@j8c111쮻b˗/gÆ !Aun]wŖ.]l֭R?lժUl׮]ɧ(lҤI86k,裏QF1#<շ1N͛~a6dq[reZ`8J뾜ɓ˥unbcc;]7 c͞=qdžʖ.]/^,%s&Z0ܹsrVX/^̒Yff&bfY%s~EDDvw pf4ٿ/"""hd~;[x1KHH`_x/n؃>ƎBBBlf>q;v0f37o{Yff&yޫ`yWq,..=lѢE,22M:>|L@g.d쫯;ÆL&Zӄ׆ 7uٌ3Xxx8 aFb/sر͘11&OQ(--eDZ_=mmm4L/g_ֆ8u;Xrr2 c999lͽ1'L :t^__|Az=KMMe{/;qWfg^~BQŋ _~9,YG}f¯k5 K.;DB& FnR$&&b׮]=Yǣ }K+ߏD͛ֆbʕXr5]@7ҊY6=fA+B1^6m\.W?Gtٳ1{l}?B* .K]䜿 !B# Fn.g2ˈ{;\=B!>{=U7YYYKg"{f%-B!G\|, Y&336裏cԄw}Æ gs-[#hQE0`sބg uE4Ff (Haa!5ʿ( ;EjN]h4L}G"gwiP]u8#102Ii0C|v P",Ecݺur(Kh֡ t:FQ*lwKsr(+Pb.4QPӭ!95 )=Em^͜ܛ08cH4rCcɒ%r(+/4d^ÁC) h y_((V(q! rWBPˋ/@ɿStVf[#\=4ќ3Aس+QqC!(\`G-?Z^HS M9emߨ!B洢Z]O]k 4 L#|Dn*wA//ʿ;Zq 'z]&$b`d&=B7n~3ZyQ%G e҄dd^Y(S,L:s@lc";;3fBQ]{wz})'atn_#(s ZS_WK#7B--*l4"z{v~$&y2F׸ 7B}_ztHignEŇH 0E#=S6"BHt k?##6pȝ3ux441x Be6D Q BPˋ/̿Pve%ht&׎܀1sh\ QCe:5J@BZQEW_hաt:f ^ >o5z!5ʿ(;EδByC l^ $$poXwAi΍(g1!BCtZf{WY:" W (*8o-wȪE#7B%p8r %h7S0c (hok*lޤM-Fnbݻ'O;E_^k-Z;{}L> QX uF  QVQ*P<(-Sas!f.#ʿ(w6Էעw& ( BEL?(| wA//ʿzӆzkj@9zR#fY_^yuӊzk ^g9PqC!thGVg{ӾOA !NwQcsZ{u (Db9Bt+8Q+VBPˋGKK7kV#g GuzgHS44"O(ҥK!QE%^FĩV޳k 95Iw6T4*n! >Gz<:{$rNVv**8(>|ɩI9 "Mш0ESQ h !`uds9J+JGl< hZL^h<]u1x h' IDATK6r(ӊM8\ 0RaSz 1LDcsT*nb<#r(=ӆ h*ZFsd!gv`Z5!5ʿ(}CTs%*Jɪ IܻqߝAWJsnDQ JkܤЄbt+(_:ЁzkMts_,*8oh2z-k !8rG{,l u`*Z(hok*lD;v0! Z4{՟xDbaFa2p(䣬z20.{<6Fnb #3rɅ |W;!zjCjyS`˶g=;FLl SCmQgӘ)t( '}=:{$rNVv**8(>|D*n: -`ҙ%`0RB洢VkMUaҙ~+l !~:P~m8d V ^O 8NIׯ;FZ/i=ƣhst:zv xmvQo[a+*nbBPKmwDԵAy} ^%$pƽwTx܈{mAi~WmvtY(ƺu!Q奖3lo@}{ .:" W (*8o-%f@='n4rC!1joFEQԴUwY@rjN"=E96g 97 !Kbu :[/zs0Eb?8PRiAi= rI!rQ:;jOhUPC8-qk+ BE tY(Fnn!5ʿ)Nс-'qX ΂Ԉ V K*?RIh(ƒ%K!Q]h5ߠ1"&d̺ůU'G QZ_^JοdG.걿!2p5J?pTBc -Mo?%؟46"YD>TBCug;zρC)QXhx"${Tغu+~FТK--A~A+ʤ[SSS9lbczaHD9E翺и!Q7BPߵw'־'457~یoчb`d&CW!i&Cjy3GKKeGcF_#&6ɩI^&Xa[?.TBH/ȓ=9S'@JW>"7:1xC(!Jˏpx jș:P]u^DEF! hBD`GM[5l=&TxhZL&CDG ۺI3(Ƃ !Q՟\δVx1؜6;{A`&)h :%8ZhPyQg̅k*Jlo(b<̹E0(-cR*:Յ.KŸ[!Q՗,W~NYb@Q!|[tn)=bR::ՅFn!DE:;+pS0e$(hok*lބC=^BB .u5h7ؗSfbTf6)/*Je`\x*lH@(޽{1ydZy]lch5Z{bC%޽nMdepUuRD1֬Y#wA/Ơ5"9<aij.4rC>;Fׅ!t펶j8 b,fA翺PqCl6BP˫7]"5hؗS4̱QW, cǎbAZZ{n\.YC Ahh( l޼OBHqϫGyCI >2O JQ۷1b>̛7?8}.o~+Wb޼yO[n[lcri6o<5$!)| "$Dyy1f۸+Vs=1o&n6<䓘>}:`Xn'b Cjy؁8\ND ̄Yҟa⦣_}nF9s栭 {VzEGG5 W5bbc #]~"'/nМmۆ;v`ǎ>}:`ʔ)%K_#FɅ*..С\(Mș:+10=w硨$&!hs4d,:E322hp1vÇsIڧN 됛/''[n_ 77ׯj+,,Dnn.WZޫ(..j3j"77{j߸q#,X7߬q]w}GQP9??ގLV#6n؄wqi>s b b<ו}yxǴiT>x7>_0g׸T麏̘16 }Q8u  u~!nflc8pƎuLaa!QPP1c";dD_]Ϡވ^}mXp|HLN"}o@q>9s&Ν `߾}xf DLL fϞ+~;~idee!??Se?,Z:Pvt:f jRa#6]=mp/t/KUW]-[ȑ#={66n܈_|Q󩠠'NZ_}ϟ^z 7p}]<#߻!?tvl*Ǚ*x΃ ܅yEwAiR@!}DԷעV'+ɦOǝ-g %Q ΟGchhAEñ. HNM铥Ǣ(bUɽ ?_]b VU8Ejڪ{eEͺ Ł|UB .&20.{<6~F翺ee)B`̅k`ϩ!.$!nLn)BQ" 5m= D[s4F !\ %=5̈ IAkCd&9N_1dGECI >4 *l( 7D1.\(wA=ӆʦ2ԴU\ 7F"-j0Œ//ʿe)W;F6Ǿq!0}( 7D1.5yQ׬iFmiL/6@)#5ˋ.TByBδcPC8b-jt~TB䡼 zɉHJCrjb4zą$¢Sޢ D1֯_/wA-kN}O&5u5hjnBM] ɦ(*8q8D002O `˿PՅrԂ)GKKeGcFK=;*̺ )JDW,EcݺurԂ)yףG"ghZPTpP|Sma=a'% BNYE)Vӈ0E#=r0B VB7CV{h(6Z&_d Ik+!e)BHPp] }۶f ^  KKC#7D1rss!514ZplNMBR<@EߝAp/s#"`PZTk_]h(ƒ%K!1gZ`l^CGdEmaMFl6ijFX՘@BW!qWBPSSch֢ԧ$L>Iz,"ڽ 97ap +.4rCQӭU褨9Űp!UJ+J~-l!}B*xFkꭵX}ÍQ >ZˇORD1n*wA-owPXzk +ltS݁5 7D16n(wA-b.ԵAeS):D{}#L .L _M(BblڴIZtkbG&3)hWʿPqC (.B}{ mu=4&e0lN+NSttO1 >4 FB7̭i7(s,跟(Ƃ !)5VG;7뱰1hH@e@@6J ŠB奴ڶ3h7ГC5%ʿPqC[o;;p m?ք$F?E`DW*n!9ZZ }F0jMM^kGxjݻW?īh4XkIڳkskGJ U6tˋ.TXf!5? OztH,Zv.{ݍ#tf DY_]!BPg+GlrNVBj3u4S]uq! HO^њs//ʿPqCld;X;(6Z& DSjGkE翼(B !~C 5mRAc!W#6Gk!Fn!Ntn=3mU`p!!).ؿ; p6wAE b&.*nbXBZhchhچȒ.*87֮[׾CsKLJD翼(B QTCj}dsJɩI2}XE%97apƐ>I_]8;%(,,Dvv6 0f!$9n9 `_B^Ǡ T !?>iB1!0ф3m`e? >4 Cb0~ ! %Z;gY F!(..;v)9ݓ/l8X )< N//ʿPqCG;v1L>;i\:e . ]"+BP;E[N.XfD\Hx/:EW*nbЭW>W&" 7^sOFkGSL: C!E !WlN+N5cHS ͭ!Ȇ.x!ukpFB/ ŰZJWgwn= IÆa^_ m~ofia0!I5ҤaBš!ܓ[=L֚L !C !Ahi +u:b1d`$&uy\9Buuu;kNlfd6L٣:ć3;\գ_^ub,\PF{kIسk‘IM?_^uW;_'}=:{$rN3 kߝCG:0q!3FnP_^utWpLV#C"gi3H̤_]!$ȸ\"l6dV=ja2}= E 0TDB*ʠѺ۳  BH(A:ZPT ؁x(ؿ; > ؿ;(erP_^u(Faa!c ugpRZmx,CxczlyMi21x 7D1֭['w#DTG֫=95 SO:O1iZ\٭ބCk_^u[ QSǻ{t($'qT^Ǡ O !$`QqC ؛p ]f@2p !B !*Cmi4pc EQ%/Q\ChKn  EJD:"L> _^yQՅFnb,YDiEuK%e֌İh5Nˋ//ʿPqCꫯ;dk@m[uk"Q u=XK_^u←b.ԴUeBncd"/*n @Nс .hyRaԙ!ȏ&غu! 6f#3.ˋ//ʿPqCcƍrh14Zp"iARx4 RE_]QM6b gZePCE}ʿ( 7(CJ8Ď.4z$ 512BQ&*nQVn=!>?FF!E ! C֚nEem!4(Ƃ ADS-6;:aG&TxhZL&,W*ʿ(|W̙6ٳ瘢"cҥ^˖-ñcǨQ`ڛQ\=c!WA`z]ݝ`ȿQEW7eeep82dW{ff&ѣ>F#n% GJ IDATfDEEaٲezBSխ'EwI ؿ;{PZlBHRe&@XXW{hh(ZٳqmaŊ8pVZ~$~C]i4ꥶ#wC0&#l6\}e{?ry} {7ވ+b Z 7oFIIIJ.͊+Ϲ [Oz6)'IEQD{[Wa3'& Oj ˋ. z{{?gTnjkc>RSSOy9;}~t('‘EyEN:=e`\x6h(Gn222hp1vÇ3x`_t:&wu!77_NNn/@nntGaa!rssQWWվj*<^mEqqWgYXVϰqN7> U{):q 6g;v< ]soGOĦw?)l><v^Xt*?/RC?7x5++ syKű(3`ٰo>GśoSN`0xoooG||$֬YSN!::Bdggcƌ7DTCKyCju$`,O<fΜsbطo^|EY8|0233łgy="##1{l۷k֬ MbL> G5l!$g!hiWah` לسk"%b6 !~z}<#h]Xx>Yv7Fg+1Dd|?E_]!QXXU^Q=b3uZZVڠYϟ'( 7D1֭[ewFQ*lg삄 %@ oMR x Q[HE_% ЪPH $E " AC3erg~?9sg~%2?}}0r̵M=.\il&݌~VS g2/W PԘ5kVX^UBWK.8NNV}30${ |S0Z4onML\uUIaƍ5:8ދFe"7k k‘?ERG7ߌ^ziDmpDQx'$[ .IƆH1Ejj/K&N''HchMFT66DD !j 6h:N'w1ll.U/W͢E-Ž;uXroI(,,lkcڴik!+<8y+8u[LVv &#Wi-ޡU./W\;vСC1rHl6߂5iҤV=+8yݵ[V\36im_.9s&~aر˖-C]]pm{ZWxqWs]l C:,&K+#"hysc@URP]]UVfWoI:!6hccFj`1Y#\E#)) ӧOG~{E-)&d4#52X؄)\_-77K. kEYYoIXdIq!>gU& )鰚9=ObjѼyyf8o )իW !MIT;h0!C:lf{S^)r\_-77'OĔ)SСC?ҥKk.x^;w-I>? !po49.))\_-77s?27JJJx\}՘9soI Bli.v)[/ͯ{_~9.r̞=^gΜA׮]a2n}PXX3g"..*O/1c`ؼy3S# &\_AbjiSsӿL8˖-î]bƍx衇0db…ѡC >eee᪝Wxqp{^|:uj$J \_.毖6ڰa)))p 7hXO?Eqq1QZZj 7'p%$X,Xʨ9_./WKqs1͆#F`Ĉxrٮ)T}j%ඬpE-`r1Z4_, zη(S뼀Nf5=(K/(0XmF&h0E*""қ77bjasCͪwH}֬YPh\_.67 i0*#"" 08^W$] %.U TqԺ.!3#\Q밹!?]]EmqxtMR0\_-1ܼ(|Vxbܹ3l_ʪx=8u~ 0Gra@aԠ8NSL=܃Ԙϒ"gcv8T~W/5ocWg{'q1ņon> Ӊp.\ ,jѳ`;k~6LHHLDq8s#sԫ$"C1\_-QTVV}ƓUUUOOcʕZ-2(Wg_.Lq'k\}eӶ#_%KD}(0/%ꛛwy'> <8\Ŵ#Gh8b3jWf959Ցմzꈽcr1ZIIiXmg?4o<!0olذy~!9s&VX3V^^e˖aΜ9>c;W\XXT'NlVKé;f/ѩS'}ˑ2deeE^Į]4̹i<5vmv* 68w:YfDDp|}n͛c[oE~~>JKKtR,Y6 ػw/.]+{D ]4.-q{\30U޵8;|!C#Vל9sSOE 77TQXXKa5 PA^bk<.\il&݌~DXE"A/\8^yNb8}kjC ƆIHB93i=dKA^*#""NL"mT9*p`DEDDj`s59+&K+wY_./W ,<7n1Z!͝;Wv br1ہ*nՒ˗.Aט\_.毖V:stxK"I&8^)Fq5j:kn؝!""尹QWxq6Qqa3#\QQXe9j$""E\ðcgä]e]{a^yC*1ۇ.C\_._F䎽gǃ 5| y7_F 1w\%#7xW\3:`8}k\.ج63Cꪱ˗.Aט\_.67Իi=ֳikBwt",x)\_./W OKIR 8np}""`s#Iߘq!""R s-0 *K5/͍w=TmmSu_./WA!d ˑ2dee;5{F5)MDDM#7oviM !^)e3a2$TDDD67y 8PQQ!]cr1ZDX}21L:Uv br1067-X@v br1@F ,&jKR1\_-ln"q vDOIr67 VX!]cr1ZDPȍ`dPM)//]1\_-ln"+wX,Ӭ2瞓]1\_-ln"ᮇ2^<%EDD-67DDD&B.憈HSln"@Gn8 #h']cr1Z.Q_f͒]1\_-ln" ))η5n8%&, H}ln" ЕRfYB5DDDjcsfn.oc>tbѢE8p 1p@t{O<Nw}QPP3fDnXfeKL\c!++ \.,^?vϝ;^xK,<̝;ܹs 86DDDGnlقng|„ Aqq>՘1c8|p 7|@ek_./WK77D} 8x>X|yS3護ނj{p 4lf{g*Mee% 99g<)) PUUժYn^{5̜9)))L24itbjoY!DۍƖ?ڵkqk*+8=xoeW77GY}n(3QPPcǐ}/[ sE^^JJJ| N8qb?#//>Z}?J|Xh;?GX%%%J| 6cs:uy衇`<@ޣLeeeW!UqM^[U7xtbh+1qyaر[R,]K,fCuu5݋}K.صk r ozMq2OI5oղK5/%&\[㑚Ka̘1Xr%Lz sN`͛1jԨ2CӚӆ>_./WA.G҉rdgg YYYz3էPYxzrM)""&Z~6 ű.mLF3,\EDDgln4zps̖]<"bjas@w%83$--Mv br1X\,%gϖ]1\_-ln4xL#$""67B>@sg|""as!WsֹY_./W  _,mZcܹK5/͍N&6Eش|r%F#B7ﳙ0M*=S./͍F\^'<^8ד""",67 tę9߆(h$|^)zK5/͍F57fl "EbBߘEڳơsHHGr/J$""RN{ p=)""Fη!""467 FXM6 Į %榝 o<2hԩK5/M;9u4T[-X@v br1i'N&֎V)4_./W v `pL"""ܴ"`sc7a40Z""" N^)ЬXBv br1iF[K5/M;[ e瞓]1\_-ln!Б ,"""܄qu\lnBTmL;,//Ov br1 Qd0bJF f͒]1\_-lnBlL;lq.Aט\_.67!v 8&yQbs@͍v ըcÆ K5/M !P2p%..K5/m+~o~k֬]1\_-lnڈ!""nlnڈeE767m @߸dhP]M.nqηF~~tbjasMxr1\_-lnڀMxM4Iv br1i@mF3Fj(67z8, \,(i%^~%%%K5/M+Xrd%榕ͷ1qLͬ^Zv br1i!woxbjas zq^NDD}ܴoCDD;ܴ9s.Aט\_.67-Xi)--Mv br1۹.))͞=[v br1iA۰!""JlnZE+67-th2o>%n.o<Β ͝;Wv br1i/˗.Aט\_.67"bbr1iF2Ml!""`sWxQpL""h&UXf$.Aט\_.67A}W[8s / ?>K/NҬwKzաiK/SNf퓑G>O8w%>}OQP=z@=4{?-رcq뭷"??Xt),Y͆jݻ}E.]Ν;oo7|oF:\"""8r4=rؿ?RSS1sLw}3f V\)S4/bҥ8~8222;(b!"""j-tXUN'-Z"11?#ۍ!C 777-7n܈!C >>z½ދTzdIIIkIsqt[nm캫( "L">1o}?Qddd .^Մ*L36l0?+׿N:Ν; bs"8 %j̘1yyy>а*N(7r:2e  0 ܥ*)wڅ#G`>w}7KLJf_]]ݴaΝ;o [MW'_䟞˗753z-XVעBɿ… x`kB׮]ݎ爏GNpwph?ePUU_|&OUӻwo:tK.E\\\7&n^U|iuk{mvm0j~)~ijHٳgǏw܁9sO>qSBꩧp!p Mcwux0U;cǎ~V77-SUɗY]wq6]C___;wt!N'ছn¢EG? e+7ވݻw^Q\\'x xgU.A_忥#8jo< n6=.,Kx UT(ϛ7B̛7nnBx^x<Pos'0P넒;#M6aժU6mFGyO=?a޽/\ǴUȀdAi<ٖ}(Pٳgwnlܸ)CJ֭ ՊblݺjDjWA(75x~M=Z3o^{Qy8JWncԨQXnڵkѱcG 2o}.ÛoπЫW֬PGy=~MBwΝ;~);wQBHHHU|yX,䄵fFFh?\vea [z***FQr-o[MRUU%m&Ξ=۴ʕ+`owF o1_A 2Dl߾]l۶QUU%ĜP~/6zhquEd3<# 9sشiXpZbΜ9>Fjk.Kdeenݺ/H,ZH$&&_2?Jۼy}nF!֯_/JaDFFxg5+ /~ .233k鲕іW a4`y/xv%_~Y\qf>}ŋGle5j1gѯ_?/233EAAp\2W͛/W'"""(?熈 ) ) ) ) ) ) ) ) ),"@N'~_8|0z+P__'O⪫… qK ז"fL4 ֭ƝN'nv_z-J"&<-EDQ0rHqՊ|TVVbŊ2J#(憈Zqq1.]mD,"bln(j?1|۷lA>!UZZ !D楢WFnn.nf QbsCDQ //ƍ{'4"bVqq1, -[p\3>-> Fa6}ΝX~=y?~ݻw̙3;vl>#7DaZӪaĈ> رG+41b5Qt`sCDQrYYY磏>˜1cV+nOjmkQlasCDQ㫯cdff9z_\.>cWnV0yd9s>^"R&ѻwoh~۷ohƇ Ǵi?:uBvv&5Q"yEEE=z4F߿|Yf+WljzH=ln(r4<?~<9(xZbVqq16l؀m۶!-- 7oFnn.>,[ ڵ+Φ}^H!""") ) ) ) ) ) ) ) ) ) ) )ȝp8IENDB`docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png0100644 0000000 0000000 00000077073 13077405420 025142 0ustar000000000 0000000 PNG  IHDR7< msBIT|d pHYsaa?i IDATxyxSe?ɞtIWhiiK[(@iy,":LeyQauP~:̸Έ(n ¸,BTtPZoYGL$$纸9ɝrgc B!>B&vB!݉B!*n!S!BOB!>B!*n!S!BOB!>B–-[ jYf!;;`/~; CFF^x477nݺ6S#-- /2xž})s'NL&CSSءb@78q"&NrYYYصk ߿7tKz}/iӦ!>>իoowƌHMMF:tVѣG`xW0ykOi… 1i$jC!/QqC58q"֬Ys֭ó>+Wȑ#1q8|0x+t.Xx1̙'OBp+:c {n9c ڵ ~-ncthK`C įm)BիP( <[oØ>}:6nV?_|9TB|7ZXn @[oq)JzC`[ PPP۶mL&Æ *++?h4HLL?N?!]!`DZo=졇b!!!L.;۽83ϴZǏgDZ8籒qKHH֮]8cs6qLTӧOw:vb3f`DZn=31ؒ%Kq,66=Cg8 /}t&ٌ3?F8cSLqyϽ{2Zz=[h[j>|88-^إmBBKJJbAAAlڴilʕn`DZ9sx6frJ6vXq9sk̚5qƏV\ɖ-[RRR1_86tPV7VXq[na6%D٪U؄ qn`---ζ&L`25662oqlȑLRZ%''3<ף>8cGew}7S*,))q8﹥ř㌌ c;kss3c 0؏?DZ#F8;޽{;s?qǞ{9׸;\.g1Ν;bcc\.g3gdO<q,-- ?!]E { L&'w)ͺu\l6VWWvd2۴i}1ӯ)Fˌ3ڵkڵkٚ5kو#Jb7nk9>k<VWW<^^^Β\.w~:ا~lkZHQQc1"##Ytt4;KΝ8cqlc , qΝ<c .ҥKqw8zgPZZd2K/T||?㏐;vs7x#0`[+~[έL&C^^1R} qׯqF~111?>xGnn.Μ9gĉoا_nĈv9DcHIIa61+9;~88CFF[۱coiXbL0J-_|;s㏱vZ6s`wm^ * .\ŋѧO늑*nhHOO;#Xz5FwyÇwiTuo|P._n rL&9 wD"-- ;wDbb"lق/ю455AѸM=1.숙2-ǹ|m"=qF<쳨`/,Gѣnbbb|(Ae+9A@@Z[ۮ|;ye]ڊkĉu7طof̘q-dee!++v\TܐEP(|rO8w6mڄSĉ>}zt:|ݻ7^ulڴd 48uTǯT*.?UȎ/KG ߿6 m'|~عs'.^jٳeښr[)GW lvaХ9ow 󕅕Õlg8üypi:u ;v ZfMׂz2dU7!mZ {-—_~o(--uzӬ/b =Xse/NW6G{1bc8tsiXMn566G}tկkmݺwq9+ۊeee=zӧOMY68qFf9r$x?\Gz8z"//V-HL6 Vt٫{|gO7;3^~e TP(/駟bqX,FqȌ30k, g1?&M_;Y\Ӹ[oMuUvv6;aܸqu|_Yx|I.^իWC./fΜ`K(**ryO^y6o]+-J>8ܾ<ϟ?V˗/@fWv>f'Dss[kpBSO=SbΝ]]9|444z`61eAe-#͆/WСC1tPlݺ9s\c„ ػw/vrG}5k`Ϟ=n4Dشin~d/k:Ի_Ǿ}w^l߾su>k.,^۶m_|iӦhmm?l00ansN; SN/c ZRu<&Le˖_ǰaÜ>3ǰaú`lڴ wu3g"::?tOk]Җc9s&͛ ;v Gɓo>EUVoA~O{qUTشi?ѣG#;;GŤI_umC=z [q%Fhh(jjj ;|'|{?`ԨQ8}4`xGwu~i(..FBBk466"..?=܃UV@on gm݆̙3سgޏv2G:1^THVe))).r9^}Uz= dcǎe~K-[0L"~nGtts&\2o߾@fϞN8N88c{cm? 6iZ6d-xɎ9222Vegur}egmذ0Z͒kVZ8cns&rJ֯_?RXll,{Gr~q6e]w.\RSS]܅ \.wYJϟg/fLV~ M'zpy3ΝôiPXXoǏo'|sb[sN[q]wy0jBTd29ǎmBBFҥKP* s{nPUU6ؙ+sûヒ4twމ2e ;t@!R """ܹC †NxEq?.\>(,,ĬY\Ϟ=EEE4B\3.O@\h5-l*n_/.ȿU" E\.ǘP(7q ƌπLn/ *+C&Ɉ'@ t%@7|S_\qr[y35hnmXVFq6 Z^@(dW*x_ĄBj@KqR 0yޥyf}'oZ땅 @!CKkqĭ( 8z0 <6Gf9oLLH\;K2B!81ڀ:c# ?S)R0*}tܓHFff!5ʿ(ۘ Zk#`ǂ bp)lfgA='P %K_/.o˿``CtzmB0 wdȹBqbBFHԩSQE*XPoE O _6@ر+/BVތzc ~ 赡qQqC!HjDYOQE X#4Dv%v~/.ʿ 8P ].l4 -!>4zoӨH֭[1c [qQ%F bؾHޱ]~*aHh:8;)Ezz:rrr&v8B|w}qnDj_#HG.jB!ă \ \ޡ#"2q1.:6 E@)Wy4noB !AYǏ:NMܙ۱A^I@3F G6k{$mD!x`Qc3=6=f|drWsEy%2"Tt7D2.\(v~/.ʿz2GuK%k Pgjh{ @.2Ss$-+*ʿ(u4R 0yޥyfQi ׃F$c޼yb(;o,|%uh0պ6aуYycnWTbBRoBzc5 _ee9s?r-Gt>zn!`[Qtuh4ףbbp˔[ARΜ㳛Zz8|0n&[qQu-oͨ3VĀ)7`HPFqisĄ$JMuHwQE俕7PKS_߾p$ XT*ndl۶M_\qu%f ƪڡ;Hp]$T G7D2t:!5ʿ((&*--]~= *95bBib@ FKi'Bc F1Y]:6 (tM'b CkqQ=~>[cn3/?}ߥ†Pm@h*l$zndʼn_Yޏ?u>VjAMm ~M<ױCw6rRB$cҥb({NaQKa#1v| 8ZD@NYJ7Bc ;|> cg@P8v9 ?uq1qrj KИB!~h1Bc J{l ( XY^($@x@/*l7D2QE9&Jp&VjMQa1{j6E@QQm!rJW IDATCkqQjByc)7UTg5Mf<xWn+=""#rn*^(?PqC$f/.,ϩ0f| soSgōN*u=?m)B!cQPrQB_M*uClH+lB!=·p -&X,Fq6 Zbq!/F=7D26o,v~/._?oq"J bi(&3xwm0JWﯨ!+v~/._˿&p %h4׹<уY1Fk$&$y,^_˿RD2|MCkqJch4סPIy9'S)R0*}Gb|'Ďzn!\7͍(/DUKE `qǂ 2fvڝ\3!r]T.7u5m(fNRXN6K+'&$aTh*luB5iͨ6ThiR W4#LCkqySMpl 2q!I׿UBOQ %K_/x`봽ZAD`o蔁_O"SN;Foc64jQg:m)Aj)\=*n!1.񝶗qr"׆AѨ"*n!``iF,Bk9pц#L L 7D2vڅ3fߢK ;' %ΩqqqH>]z`M(u+{8ڞE׿o~C"[n;Fx}>*446 scG#/P!>4QA1^_t!}vCkqy2EرSc\#"2q1.jZDDA X@׿oBLvNa3> ¹qe^I@3F)W!" Eݖ"?CQYGa cg@&5TWB.SW`$G: BD+oFUKL=4ZqP(j0  iK$c…b(6q,LVJ` w]yMfV†W- B(3fCuh4;GDAуY1F@bBR$Ut-E$c޼yb(;6T*Xܞ8$OyfK[B|H+oFyc).6Y@l\ MXZ .94%'P !ƣPFs]m9p4n2'x(.-rPQ飩!^"M7$v~/k?c :`cB [)%\C׿oRD2֯_/v~/kɿҌsgQm贰Q+4C8(k g[HƶmQu56T`i鴭#"75_-Ttb(JZcL!D0]$2yw-^s[/ȑ#lX~=  1%cWS.6 ć%#20 ◼9r2331dܹիs{9<䓘?>>33;vx0rB>FK ՟EUKjTr5b C%W{(BB+gyiiix0uTBYΟSӇa +)C|8=Sgmu IlE׿o⤤$r={9s ot9>~xvoGff˟1c`׮].kdff?7ov9LԸ_v-^z%ceeeD~~nF#233qa[n… b;w?{XrO|~ՈNދƆ&B}[lLnKTw=G\^W9&NC꿏~5%%gv{űH-Ʉ#G8Z 6mŋVO0w\|W.7n܈~ǎȑ#]Ezz:rrrֳf,߳v_B=Z  .^@hp>j=/}OO|zESO=ɓ';… qlذׯZFss3N:dDDD`̙1b<3HIIAvv6ydff6DqQ{c M i"|J`6< yf}.6}oK7ߌ;v̙39s&n݊ 68g>`رػw/@PX`aOOg'BHOh͸PKc'?=   IIz B|FO|zE W#E~146l `A;RΜC[b FQX Z*eB*3Aj8"(rĄ$JM[/!Z0fCuj0tϩBDh;lG?R"EFK Z*:ݵBGiTBUm<[*i[R^}Vh<!DB\xs14jQZWia# A_ ʿ("-;FjBYC1Z*`c5H`Mh7[u։_M lPi[B^}U}(*nd,5qQ]׬iDuK%wVmX{jD߷PqC!Wr&ӶAj="+=!+!¢dd* }b_JbtxRB>Pz(ZBHWрb"7o;o~UdBUMPUS<ܾ y9?y^M/5B \Ck¢\.G@`d_I<{\(+w9O D|Xr,O"ʿoRD2|MCk,ϩ0f| xуY9 ?uq1mT<`3)!"Ga cg8{p*+ GR{!t/*n!~1zS-fY8( hZ{{W`4d2c%\;-E 0YP*Ӷ&3xw)pxdUjQb%\!)v~WCdDDAуYy"}17 <[P} Xd!5_+oƥryCRp|@^Iw & 6}FXoB-sC$cԩb|)1QV_V@l\ MXZ .94#oD-sC)hmA 7ɓ(.-rPQ=ZB7譩5V`kp9 !CdڵK7l5*tT(e*wP8iMʿoH֭[ycm̆%5U0w6DdTxc} ߷m)"۷o;m7[l.EhJFh:Evm-[!xPzSMmC=%!Dڨ!x Ո ۩jD@#BHϠ"y5 Nۆ"B'pBCkRͿb6jqI핅T/(znd ZmL@u%4:i!<[OZ ߷PqC$c޼ybפ۬S+ ZPd=GJGB !D4EBIi1,V Jc4bb=^Fxuo !gPqCwcOݎWT'1nҍHMwA"*(*aB#>b<¢F.# 02$=.;s!>Y/.ʿoHy29YΟSӇac >\3Rd|6]*ndl۶M'_RZ c3f| rB13=8X}?[s9E-Th5Y1y*V#@8 BV `C6g{k.G׿(B<1&sZ*d.0;|U[CsCqM@Ey\j) 1Qむ<{as`A$&$3!{QqC$cŊbz*FϢyly9'?7!/Q{$&)_\B 8Ckݝj pmظt 0`lc3ҀnI߷p1&vRt --MpjM`MlBUJ0*}_6ńnCsk.T1[dQA1Cz0BB?-hnm찝NX(JEF74HF~~!ɿj4qa!"7b TشqQ} 7D2V\)v~Z4|}rB]-E$7;v T4]7v.X^ѐq/.ʿoHM߾E:4;/.ʿoeAhnm谝V(*EF!%&Ma`l DF6BDC7dKb?c *o(QTK]!a4v<0o,lAayt[h_ j67RKy'e &\~l>hɠaQ4h"9T ܸRTWt$ ظv 5ɢHFMM """o|wx?vd4AӢ~/M]Qʔ Rp}]-E$cѢEb7 \ \A&CDžr qTE-sC$cݺub7s?Ø0yRуY9 ?uq}+5!b߷P 9%=6cg@P`ȰP(3>كSyBE-Tgl6V@@pU(j7bvwNM>(=sJaZRQ飩!x-*nAM\j.CC<|0ƥR.!ķPqCaPSmzFC !>F$#33SoqF.SoH?h ʿ(!dCZ&Mem|m4 Blyʿ(*ndL:UR- ф!20 ~g-_\qQ} 7x)Mvp+PFF!/d,h:3ojBD8hZFF!D2v%v^hiAY}QNФ*l([!uVC45X F F:f)[۷d٘ n!*(Aj5_\qQ} 7HEh2Xv(* Z`d"MT"a-ͨl>ͻ- DB.{02B.*n ը5Vu.\ aHFB.Cd,\P$A Taa##y<20!0_C!17 L_CDžr9b †Bk/#GD@@/vzΞ={0j(t:>(F%b19YΟSӇac >\鳈 MN1S/.ʿoȑ#Đ!CsN̟?W_vqw`Сػw/q=9ׯ;).-`3> BPʕɟ/EqQ}Wyg{}Tjŋ/4UYcxG1gl޼0qD_F:㟃tl۶mbF&Q8 BV Ck_(ܴ5kٳgr;'//%%%Xte˖ٳTH?^͍(o,Bi1yޥ 0{{w/eqQ}䋛bX, 0xrr2휼<Fӡe˖yIT4CtL@=,pxуY߉ IK!J'5 IDAT.ǃMMMnTWWfΜ+VcǰvZTUUQ#(j 7: ?rN⧼Sh50L #5*}%o'XdbS5k^xL0+VڵkGb%gŊbl̆ . `ܤARΜI==M(z@ssqcsL>iOtE'vʱGjh3-DIi1,V TJ0*}G m($%%A.ٳ.vNm|jhvoGff˟1c`׮].kdff?9C!77q9vZK.ʐ|ga4>֭[nܹ#FqaX+7d5˞rmO%sxz:ҥK}so|sHo|`nq8} [`2pUVaӦMx"jK{(dff⣏>r駱~z\x."==999HKKD|Z+oFyc)x8D"HH!'%[ z)L<wy'.\#G`Æ X~=j5q)$''#""xgc!443gđ#G~z<#n !h1b9ؘe }Sz82B-7|3v؁3g`̙غu+6l؀{ cb޽s/_wyo~lٲ>,B)aWvz66 }C%[x{_\yc} _\B oic6\j.Gskcm `o˿[!t j<!*nJVRX) B.ƒQBq~_9W.H%E-l8p땅7ߗQE-sC$h4B|} QE-44t܈ `hB@>jÑBwְ!B !5l!ğЀb"Wz+&BM:1)lD߷PqC$cѢEbMy Ն#:W,URɿ[u։_a#3ʿ("bR+,*@vNJJjiL!OIAl\K[b{Tb 1QAp`yGfA@bBhB64 ŀs``8$Oyj`2`lsF+\B!;} B$l_A־uZDE R[B-تG**V-Bb%)RPYdUe#Mt,;<9g1ϝ;/qs"p8ڵlhl 5'Fi >?l5EpO-cr1 EYfu\8y(_}tɯt9aX'=Cꪱ—?EfڴiUW]\_6n8_]{QchPLf`cM8cr1h~Zȑ#ѫW/_Mu8Qq^ =ɖKz!"RGnrss]I&{R*""i~{ֆ 4ylj `MBd66* EfѢEEaǎz}:\R$E5\'NT;HcoID^0xŴȟBbjߎLbQFa̘13f ٣["֬YӮ]NT =ΒKS`dcP{ar1h|߾}`ƍ8w}`ƍ>|8?hDp{8q\kAƆH4?r_~f3rrrGy;~K9׍Gkl37S+#""4grʀm6233~K1׃fgJ:LF66DDzysSPPÇ_}Z%)"//Mollu[M6iObr1h<߿?Mp{zzoIhBƒB6vɊd #;bjo+Wcǎ:t(F ͦ[&MԪy'C&vъԔ`fc&͟ƒբ3g?;v`ٲeERRn6t]# /N vHdpeDD-4on{1hJ j*l6W-I'tqmlHp,&k+#"h~$%%aׯ{H%Šۄ8]yUf\+5?EfҥA]{(---IK, 8.U'P d0!5%V3wG)2\_-77o66o 3 ոX!zj1!:1LH(/Wɓ'1et?OtRڵ ^ΝÇ~KRD||B>7HMIwqY_.͛{ǏGii)E||$F |p|[s63 49 Ĉ֥iiiK5/WA!|z/s:x駱i&lڴ)**++Cvv6JKK%8xvnǑQW_و=c`yiH%K!߿Ϲӧߘj? ]wݥR gq!ֽo |gFWg_܋ 槥n[_k:ؘL&$$&hWc8vݓRdKQ& ͛J8p Ν;kvno﫳}FwWg_ٴǑl Dٷotբys3m4L>G o-)9p3GɄQ`6?l6#g԰#8'Y̝;Wv bji󜛯 +V@uu5og{nݰpB >/0e 4Fo=U<=fB8] -_\v bjiSs_kEEE}YC\w9r$ #Fh+C)V !`27lƥ=nuu|G /ҦR1fXjO2W{_-[`Ϟ=x7i&ڵ \rVS,.`pm[gHbS|gسgֆMvmxp8}v 6oAaРATK1B}՜bO]]{a^C*bTٳiԥK\VҴ0RSUi=1r̵M<~TLp܌~#^^.Aט\_-m:rc555Dj N?y:*tٯa6ЭK7Ill"bjE"!uI8=7xLMk.F.?wc=&]cr1ݻ~zRw娮 -ɖq#iMGnN> &Ç7=~z?RLF7n$gT.JDDMGn郂̜9qqqxW1}t^~e3 ,͛QWpI\'NWh0Ҕ4 \_./WKcĉXlvڅo7nC=!C ._:`(-- Wż‹S{${ԩS#Qbr1Ԇ |~NII 7܀n@Ê~)PTTTUUiW-!:zw]].A5o|abr17l1bF~. *bOE?p[5ܖβ_./W櫂bA޽ejp۬&'s1WXx饗%& h04 WEDDzGnaqxL VXbE8JVbr1Zܐ8S} ڀ;wC-)++Ӻ4j/ }OgʐRN,koqTm $\y6DDP8yڥU3Ձ'[LVtOJecCDDBpL 69" D4N n ᪈PT:wMm"ɖt8-ځbjasCmv;6xk":w ug͚՞\_.67&uWFYVHqƵ4j'/ Ʃc&ÀKS8csC"cps1E967*g/|ZW  ɞذaC_Bbr1UU\mtID)((u(4_./W jVT lGr/fM^Bbr1<-M NNhPQpln( n$R-qeln( ߠu!qlኈZ ;jnģkBo^^^X^Zbjt,^n 2aP :|t=4@|1!T./%&8dffb˖-Ü9s|jjjp8!ĉ>pn0>s_4=/Z?GXx}_  &F{D ̴Q[[|/N:={ӧO` /ttg2dggYYY@Q`Ūk. snOMnlۺJw NY*),߿1qyaر[,]K,fCUU݋}K.+^#11AKK Lojnvƿw=ΎZx=oHЈ5g|8} ;Goгץ9ڦ1ǃ | /cr1ZbT$T+7|IۻO~ Ym蓞!C#>iC3է}Rz"5'l)KReDDDډR Իk 0k"""5 ׃onf%E,/͍N|[sYBEΝ+]cr1Z]jnՒ˗.Aט\_.毖V:stxK"I&8^)FqUqV5;CDDas0l6:fG"""csspyW6LMBEͻx8,/͍՜ K%0Me555K5//j/|]y~6i28׆B8yFA tK )͍b(ɖ8K|+""",67h"bjasXX?9SN]1\_-ln|(KԬ՜ .Aט\_.67hX?\m]{DQQ*Xbr1D7JQWGQDDDF\?{lnbJGXBv br1q~Tsdk_./W G5瞓]1\_-lnbXo of#QBEDDD򱹉Q\?(0671G&5~T(_?9Cv br11-e3k,%&Q7ntbjasCTX?(mCr(""UQ6l]1\_-lnbPh.Aט\_.671;֏jΚ5kdk_./W (QDDD&q(""asŚ_?&J !p"\Q.Aט\_.67Qu !T./MjnN]bzL4Iv br1Bͭ1b(ڇߔQ&Q ʯU\\,]cr1ZD׏R%K.Aט\_.67QB/G5gղK5/,;xvnǗG=zvHMQ͉]1\_-ln$gq!ֽo |gF?}׏"""j>dBBbH ?7'/IDDDdG:Jwa;1_+}Z3gtbjas#ɑ45 fsBٌQÚ>zHZ&]cr1ZHt98{Scl6#..yz0{l%F ԂF]m󈈈uHrYzۛۍm[gH(RpIfÎ wƿw=ΎZx=ަ *Ĉ۷o( br1X\IDATZxF~;=.T_il&8nFcܹK5/Gn$ f:tNqp\YmgdUc˗/]1\_-ln$sRz"5gxׄEVYRRL\_.Upn&DDDFZ1 $TCDD67!P0$Tek_./W  u7SR55OQd0\_-!]D4(++Cvv6JKKV ֤7Q4 /Hh >rCDD67&xdhPZD%@yytbjasao0uT%&`%&M&6-.Jbr1 oGm&xJ(DP]۰ib %&jGn#&jOYYtbjas!^E+bf}/C=tbjas!:/SRDDDbs!LLDDln"$bln4& pn?FCv br15\'<7Σ6f͚%]cr1ZD@SRokܸqK5/M Y"\ D@+,&+Fj&^7\x.a%&x+((]1\_-ln,bos5k.Aט\_.毖in} < HOOŋ}ĢE0p@$&&bxr"Tq@Gn,&kD ""ҋhnJJJp8cxGO{O:wp Q8Ezlٲ7t P]]"}0c ipo6.Aט\_.毖on> ӉpA}ӱ|f[oZh&!T./%ꛛ @rrxRRUn:k9s&RRR-2!ܙe7i$%߲Bf-kou]UVZqz^q.IDD^Q4eo0< n6=.,Kx $""#ꛛ L&|>?4(~B̞=p-`ƍo~5~7afΜ+V̷ٻsfl|{;fرcp8طoe0g87q6*++@yyϸV#V<(>Gqq?#F(9_~0`&L&b1cDNNܹsEND]]]}z!a0<Ъ(--DiiiBC3y9w@VՍ7(]cr1e0yf5*lrд!bˑt (--EVVV^L)T}7ީ?\S߿~Bq, p 12WjyԻƹXf.Obr1X@s[&]cr1Zh,db.ْٳg.Aט\_.67 XeE !Pq QPWsֹY_./W  _,mZcܹK5/͍N&6Eش|r%F#B7ﳙ0M*=S./͍F\^'<^8ד""",67 tę9߆(h$|^)zK5/͍F57fl "EbBߘEڳơsHHGr/J$""RN{ p=)""Fη!""467 FXM6 Įr%榝‹zwx%eԩSek_./W vw^,SRm`%榝8X;Z͒0\_-ln)psc2d`sB͍lhd7p;8= 8OIfŊK5/M;6*++]1\_-ln!J\,34=tbjasXLVf &dn .obsZ7oCDD܄(dbޙ8dCv br1 Qd0bJF f͒]1\_-lnBlL;lq.Aט\_.67!v 8&yQbs@͍v ըcÆ K5/M !P2p%..K5/mT暑Wx9ߦ֬Y#]cr1ZܴoCDDܴ$""nln@Zq$""""6p{]p{~o<% xBbr1Zܴ4itbjasۘf Q lnZ$pL""(榕x x.Aט\_.67T`7Ғ%Kdk_./W V 4h025zj%U7n7syL&/M+Թ y 8Qas Q`s R*2̙#]cr1Zܴ b6sƧ4%om۶.C\_./Ooii)4yͨ?rS__-[ছn0aQTTѣGq:t_~e۸}l{!NMuUv br1D}ssa8Ngo߾(_|A9p@{am:]QE}sSQQHNNOJJTVVjO#Hֽo(D}sҔ6#٧ф~l-THDDD,h8]C?7no> Fsz( P}'(++]n1\_Ʃ$QVftRO>D uV}<( Xvo! 8v>Nݺw>>.Rq)zGmm-JJJ|AK8ul6>я~s)ĉ{]ӧqi?գGC׋R0o<;z+PRRKbɒ%l޽{ѷo_tyyyܹ3nFx7o}%""ȋ#7@#ϟ#553g}?1c`ʕ2eJ>/".]Ǐ###?0Y" f"""ֈKB7͍U{mtbѢE8p 1p@FQ<Ail~1c0 _`j%3f/ SO=%]wJ? rss\Bw&IL:Ul޼Y,_\$''I&Er5 d .}Q^Zѣbh4-[4\-u܌7N :gIII6>'N8q۷oTU[///FFO=0 <&FvGlnB^ӧ?EFFpBXUM(bʔ)>cÆ !zԩܹ0 -67Z|*Z*ҫP򯪪Œ3p8|a1UjPot:1es=0`@KUR(ڵ Gٳ}n|嗈k* i-F;wƷ~ZUg᷿-->__四H*NB?==˗/ojf[Z~E `-F]v?N:F}}}VHSL>x`aY5{ơCtRŵ|c&~UɗVY[f#_駟駟FQQVkxTX(={0~xq3g>̟?gΜ:5/z  74v]wSر#:vk|sҿ8^U|iڵkqwkU>Zuuu;q}a*MBtn&,Z0zhx^ce]j WǮBa4-"5ĩ>*b۶mٳM\R Vo`oښ/a0Đ!CŶm|2?N bG]w]JVJ(?3`03gM6  *̙#cĬrDVV֭_" ŢEDbb/~!ļ͛7&\߿hnb+6Mdddgyi[c௼>/ׯ"33Sk.[m`FQ GknIB뮻70kPW\!l6ӧXxqVF[󯪪s"33S %|el޼p}rUp"""RsnH_RRRRRRRRR̲ " t◿%8ÇG+uuu8y$*,\_~j(pm)"jk֬In:?itoGaa!w$hRDՊ#GZCEEVX!4"Rln(_~ҥ߶*@uuu"(憈Ç}˖-t;"Z%%%Bl^˱zjoPE+67D9pƍ{OFiDx)8E"X,,[ rgyÆ \!E#^ NDQ)))>|8 eCD1(*}p:5jT=t͛ш<N: j⡇jz7|So߾x'H!h"<裏KKK1j(?fgw܉ؽ{7Μ9cdž3#3oVw}7?5Դ(!W_?1233QUU?_=֯_~. + M̬YPXX+W65=D67D]Qr|T?GbdDA<-ED16lmې͛7#77| -[twyg>{/%VMDRxZ憈憈憈憈憈憈憈憈憈憈憈sIENDB`include/0040755 0000000 0000000 00000000000 13077405420 011235 5ustar000000000 0000000 include/android/0040755 0000000 0000000 00000000000 13077405420 012655 5ustar000000000 0000000 include/android/asset_manager.h0100644 0000000 0000000 00000014246 13077405420 015643 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Asset * @{ */ /** * @file asset_manager.h */ #ifndef ANDROID_ASSET_MANAGER_H #define ANDROID_ASSET_MANAGER_H #ifdef __cplusplus extern "C" { #endif struct AAssetManager; /** * {@link AAssetManager} provides access to an application's raw assets by * creating {@link AAsset} objects. * * AAssetManager is a wrapper to the low-level native implementation * of the java {@link AAssetManager}, a pointer can be obtained using * AAssetManager_fromJava(). * * The asset hierarchy may be examined like a filesystem, using * {@link AAssetDir} objects to peruse a single directory. * * A native {@link AAssetManager} pointer may be shared across multiple threads. */ typedef struct AAssetManager AAssetManager; struct AAssetDir; /** * {@link AAssetDir} provides access to a chunk of the asset hierarchy as if * it were a single directory. The contents are populated by the * {@link AAssetManager}. * * The list of files will be sorted in ascending order by ASCII value. */ typedef struct AAssetDir AAssetDir; struct AAsset; /** * {@link AAsset} provides access to a read-only asset. * * {@link AAsset} objects are NOT thread-safe, and should not be shared across * threads. */ typedef struct AAsset AAsset; /** Available access modes for opening assets with {@link AAssetManager_open} */ enum { /** No specific information about how data will be accessed. **/ AASSET_MODE_UNKNOWN = 0, /** Read chunks, and seek forward and backward. */ AASSET_MODE_RANDOM = 1, /** Read sequentially, with an occasional forward seek. */ AASSET_MODE_STREAMING = 2, /** Caller plans to ask for a read-only buffer with all data. */ AASSET_MODE_BUFFER = 3 }; /** * Open the named directory within the asset hierarchy. The directory can then * be inspected with the AAssetDir functions. To open the top-level directory, * pass in "" as the dirName. * * The object returned here should be freed by calling AAssetDir_close(). */ AAssetDir* AAssetManager_openDir(AAssetManager* mgr, const char* dirName); /** * Open an asset. * * The object returned here should be freed by calling AAsset_close(). */ AAsset* AAssetManager_open(AAssetManager* mgr, const char* filename, int mode); /** * Iterate over the files in an asset directory. A NULL string is returned * when all the file names have been returned. * * The returned file name is suitable for passing to AAssetManager_open(). * * The string returned here is owned by the AssetDir implementation and is not * guaranteed to remain valid if any other calls are made on this AAssetDir * instance. */ const char* AAssetDir_getNextFileName(AAssetDir* assetDir); /** * Reset the iteration state of AAssetDir_getNextFileName() to the beginning. */ void AAssetDir_rewind(AAssetDir* assetDir); /** * Close an opened AAssetDir, freeing any related resources. */ void AAssetDir_close(AAssetDir* assetDir); /** * Attempt to read 'count' bytes of data from the current offset. * * Returns the number of bytes read, zero on EOF, or < 0 on error. */ int AAsset_read(AAsset* asset, void* buf, size_t count); /** * Seek to the specified offset within the asset data. 'whence' uses the * same constants as lseek()/fseek(). * * Returns the new position on success, or (off_t) -1 on error. */ off_t AAsset_seek(AAsset* asset, off_t offset, int whence); /** * Seek to the specified offset within the asset data. 'whence' uses the * same constants as lseek()/fseek(). * * Uses 64-bit data type for large files as opposed to the 32-bit type used * by AAsset_seek. * * Returns the new position on success, or (off64_t) -1 on error. */ off64_t AAsset_seek64(AAsset* asset, off64_t offset, int whence); /** * Close the asset, freeing all associated resources. */ void AAsset_close(AAsset* asset); /** * Get a pointer to a buffer holding the entire contents of the assset. * * Returns NULL on failure. */ const void* AAsset_getBuffer(AAsset* asset); /** * Report the total size of the asset data. */ off_t AAsset_getLength(AAsset* asset); /** * Report the total size of the asset data. Reports the size using a 64-bit * number insted of 32-bit as AAsset_getLength. */ off64_t AAsset_getLength64(AAsset* asset); /** * Report the total amount of asset data that can be read from the current position. */ off_t AAsset_getRemainingLength(AAsset* asset); /** * Report the total amount of asset data that can be read from the current position. * * Uses a 64-bit number instead of a 32-bit number as AAsset_getRemainingLength does. */ off64_t AAsset_getRemainingLength64(AAsset* asset); /** * Open a new file descriptor that can be used to read the asset data. If the * start or length cannot be represented by a 32-bit number, it will be * truncated. If the file is large, use AAsset_openFileDescriptor64 instead. * * Returns < 0 if direct fd access is not possible (for example, if the asset is * compressed). */ int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength); /** * Open a new file descriptor that can be used to read the asset data. * * Uses a 64-bit number for the offset and length instead of 32-bit instead of * as AAsset_openFileDescriptor does. * * Returns < 0 if direct fd access is not possible (for example, if the asset is * compressed). */ int AAsset_openFileDescriptor64(AAsset* asset, off64_t* outStart, off64_t* outLength); /** * Returns whether this asset's internal buffer is allocated in ordinary RAM (i.e. not * mmapped). */ int AAsset_isAllocated(AAsset* asset); #ifdef __cplusplus }; #endif #endif // ANDROID_ASSET_MANAGER_H /** @} */ include/android/asset_manager_jni.h0100644 0000000 0000000 00000002421 13077405420 016473 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Asset * @{ */ /** * @file asset_manager_jni.h */ #ifndef ANDROID_ASSET_MANAGER_JNI_H #define ANDROID_ASSET_MANAGER_JNI_H #include #include #ifdef __cplusplus extern "C" { #endif /** * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager * object. Note that the caller is responsible for obtaining and holding a VM reference * to the jobject to prevent its being garbage collected while the native object is * in use. */ AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager); #ifdef __cplusplus }; #endif #endif // ANDROID_ASSET_MANAGER_JNI_H /** @} */ include/android/bitmap.h0100644 0000000 0000000 00000006371 13077405420 014306 0ustar000000000 0000000 /* * Copyright (C) 2009 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. */ /** * @addtogroup Bitmap * @{ */ /** * @file bitmap.h */ #ifndef ANDROID_BITMAP_H #define ANDROID_BITMAP_H #include #include #ifdef __cplusplus extern "C" { #endif /** AndroidBitmap functions result code. */ enum { /** Operation was successful. */ ANDROID_BITMAP_RESULT_SUCCESS = 0, /** Bad parameter. */ ANDROID_BITMAP_RESULT_BAD_PARAMETER = -1, /** JNI exception occured. */ ANDROID_BITMAP_RESULT_JNI_EXCEPTION = -2, /** Allocation failed. */ ANDROID_BITMAP_RESULT_ALLOCATION_FAILED = -3, }; /** Backward compatibility: this macro used to be misspelled. */ #define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS /** Bitmap pixel format. */ enum AndroidBitmapFormat { /** No format. */ ANDROID_BITMAP_FORMAT_NONE = 0, /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/ ANDROID_BITMAP_FORMAT_RGBA_8888 = 1, /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/ ANDROID_BITMAP_FORMAT_RGB_565 = 4, /** Red: 4 bits, Green: 4 bits, Blue: 4 bits, Alpha: 4 bits. **/ ANDROID_BITMAP_FORMAT_RGBA_4444 = 7, /** Deprecated. */ ANDROID_BITMAP_FORMAT_A_8 = 8, }; /** Bitmap info, see AndroidBitmap_getInfo(). */ typedef struct { /** The bitmap width in pixels. */ uint32_t width; /** The bitmap height in pixels. */ uint32_t height; /** The number of byte per row. */ uint32_t stride; /** The bitmap pixel format. See {@link AndroidBitmapFormat} */ int32_t format; /** Unused. */ uint32_t flags; // 0 for now } AndroidBitmapInfo; /** * Given a java bitmap object, fill out the AndroidBitmapInfo struct for it. * If the call fails, the info parameter will be ignored. */ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info); /** * Given a java bitmap object, attempt to lock the pixel address. * Locking will ensure that the memory for the pixels will not move * until the unlockPixels call, and ensure that, if the pixels had been * previously purged, they will have been restored. * * If this call succeeds, it must be balanced by a call to * AndroidBitmap_unlockPixels, after which time the address of the pixels should * no longer be used. * * If this succeeds, *addrPtr will be set to the pixel address. If the call * fails, addrPtr will be ignored. */ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr); /** * Call this to balance a successful call to AndroidBitmap_lockPixels. */ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap); #ifdef __cplusplus } #endif #endif /** @} */ include/android/choreographer.h0100644 0000000 0000000 00000004277 13077405420 015665 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @addtogroup Choreographer * @{ */ /** * @file choreographer.h */ #ifndef ANDROID_CHOREOGRAPHER_H #define ANDROID_CHOREOGRAPHER_H #include __BEGIN_DECLS struct AChoreographer; typedef struct AChoreographer AChoreographer; /** * Prototype of the function that is called when a new frame is being rendered. * It's passed the time that the frame is being rendered as nanoseconds in the * CLOCK_MONOTONIC time base, as well as the data pointer provided by the * application that registered a callback. All callbacks that run as part of * rendering a frame will observe the same frame time, so it should be used * whenever events need to be synchronized (e.g. animations). */ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); /** * Get the AChoreographer instance for the current thread. This must be called * on an ALooper thread. */ AChoreographer* AChoreographer_getInstance(); /** * Post a callback to be run on the next frame. The data pointer provided will * be passed to the callback function when it's called. */ void AChoreographer_postFrameCallback(AChoreographer* choreographer, AChoreographer_frameCallback callback, void* data); /** * Post a callback to be run on the frame following the specified delay. The * data pointer provided will be passed to the callback function when it's * called. */ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, AChoreographer_frameCallback callback, void* data, long delayMillis); __END_DECLS #endif // ANDROID_CHOREOGRAPHER_H /** @} */ include/android/configuration.h0100644 0000000 0000000 00000057246 13077405420 015710 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Configuration * @{ */ /** * @file configuration.h */ #ifndef ANDROID_CONFIGURATION_H #define ANDROID_CONFIGURATION_H #include #ifdef __cplusplus extern "C" { #endif struct AConfiguration; /** * {@link AConfiguration} is an opaque type used to get and set * various subsystem configurations. * * A {@link AConfiguration} pointer can be obtained using: * - AConfiguration_new() * - AConfiguration_fromAssetManager() */ typedef struct AConfiguration AConfiguration; /** * Define flags and constants for various subsystem configurations. */ enum { /** Orientation: not specified. */ ACONFIGURATION_ORIENTATION_ANY = 0x0000, /** * Orientation: value corresponding to the * port * resource qualifier. */ ACONFIGURATION_ORIENTATION_PORT = 0x0001, /** * Orientation: value corresponding to the * land * resource qualifier. */ ACONFIGURATION_ORIENTATION_LAND = 0x0002, /** @deprecated Not currently supported or used. */ ACONFIGURATION_ORIENTATION_SQUARE = 0x0003, /** Touchscreen: not specified. */ ACONFIGURATION_TOUCHSCREEN_ANY = 0x0000, /** * Touchscreen: value corresponding to the * notouch * resource qualifier. */ ACONFIGURATION_TOUCHSCREEN_NOTOUCH = 0x0001, /** @deprecated Not currently supported or used. */ ACONFIGURATION_TOUCHSCREEN_STYLUS = 0x0002, /** * Touchscreen: value corresponding to the * finger * resource qualifier. */ ACONFIGURATION_TOUCHSCREEN_FINGER = 0x0003, /** Density: default density. */ ACONFIGURATION_DENSITY_DEFAULT = 0, /** * Density: value corresponding to the * ldpi * resource qualifier. */ ACONFIGURATION_DENSITY_LOW = 120, /** * Density: value corresponding to the * mdpi * resource qualifier. */ ACONFIGURATION_DENSITY_MEDIUM = 160, /** * Density: value corresponding to the * tvdpi * resource qualifier. */ ACONFIGURATION_DENSITY_TV = 213, /** * Density: value corresponding to the * hdpi * resource qualifier. */ ACONFIGURATION_DENSITY_HIGH = 240, /** * Density: value corresponding to the * xhdpi * resource qualifier. */ ACONFIGURATION_DENSITY_XHIGH = 320, /** * Density: value corresponding to the * xxhdpi * resource qualifier. */ ACONFIGURATION_DENSITY_XXHIGH = 480, /** * Density: value corresponding to the * xxxhdpi * resource qualifier. */ ACONFIGURATION_DENSITY_XXXHIGH = 640, /** Density: any density. */ ACONFIGURATION_DENSITY_ANY = 0xfffe, /** Density: no density specified. */ ACONFIGURATION_DENSITY_NONE = 0xffff, /** Keyboard: not specified. */ ACONFIGURATION_KEYBOARD_ANY = 0x0000, /** * Keyboard: value corresponding to the * nokeys * resource qualifier. */ ACONFIGURATION_KEYBOARD_NOKEYS = 0x0001, /** * Keyboard: value corresponding to the * qwerty * resource qualifier. */ ACONFIGURATION_KEYBOARD_QWERTY = 0x0002, /** * Keyboard: value corresponding to the * 12key * resource qualifier. */ ACONFIGURATION_KEYBOARD_12KEY = 0x0003, /** Navigation: not specified. */ ACONFIGURATION_NAVIGATION_ANY = 0x0000, /** * Navigation: value corresponding to the * nonav * resource qualifier. */ ACONFIGURATION_NAVIGATION_NONAV = 0x0001, /** * Navigation: value corresponding to the * dpad * resource qualifier. */ ACONFIGURATION_NAVIGATION_DPAD = 0x0002, /** * Navigation: value corresponding to the * trackball * resource qualifier. */ ACONFIGURATION_NAVIGATION_TRACKBALL = 0x0003, /** * Navigation: value corresponding to the * wheel * resource qualifier. */ ACONFIGURATION_NAVIGATION_WHEEL = 0x0004, /** Keyboard availability: not specified. */ ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000, /** * Keyboard availability: value corresponding to the * keysexposed * resource qualifier. */ ACONFIGURATION_KEYSHIDDEN_NO = 0x0001, /** * Keyboard availability: value corresponding to the * keyshidden * resource qualifier. */ ACONFIGURATION_KEYSHIDDEN_YES = 0x0002, /** * Keyboard availability: value corresponding to the * keyssoft * resource qualifier. */ ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003, /** Navigation availability: not specified. */ ACONFIGURATION_NAVHIDDEN_ANY = 0x0000, /** * Navigation availability: value corresponding to the * navexposed * resource qualifier. */ ACONFIGURATION_NAVHIDDEN_NO = 0x0001, /** * Navigation availability: value corresponding to the * navhidden * resource qualifier. */ ACONFIGURATION_NAVHIDDEN_YES = 0x0002, /** Screen size: not specified. */ ACONFIGURATION_SCREENSIZE_ANY = 0x00, /** * Screen size: value indicating the screen is at least * approximately 320x426 dp units, corresponding to the * small * resource qualifier. */ ACONFIGURATION_SCREENSIZE_SMALL = 0x01, /** * Screen size: value indicating the screen is at least * approximately 320x470 dp units, corresponding to the * normal * resource qualifier. */ ACONFIGURATION_SCREENSIZE_NORMAL = 0x02, /** * Screen size: value indicating the screen is at least * approximately 480x640 dp units, corresponding to the * large * resource qualifier. */ ACONFIGURATION_SCREENSIZE_LARGE = 0x03, /** * Screen size: value indicating the screen is at least * approximately 720x960 dp units, corresponding to the * xlarge * resource qualifier. */ ACONFIGURATION_SCREENSIZE_XLARGE = 0x04, /** Screen layout: not specified. */ ACONFIGURATION_SCREENLONG_ANY = 0x00, /** * Screen layout: value that corresponds to the * notlong * resource qualifier. */ ACONFIGURATION_SCREENLONG_NO = 0x1, /** * Screen layout: value that corresponds to the * long * resource qualifier. */ ACONFIGURATION_SCREENLONG_YES = 0x2, ACONFIGURATION_SCREENROUND_ANY = 0x00, ACONFIGURATION_SCREENROUND_NO = 0x1, ACONFIGURATION_SCREENROUND_YES = 0x2, /** UI mode: not specified. */ ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00, /** * UI mode: value that corresponds to * no * UI mode type resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01, /** * UI mode: value that corresponds to * desk resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02, /** * UI mode: value that corresponds to * car resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03, /** * UI mode: value that corresponds to * television resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_TELEVISION = 0x04, /** * UI mode: value that corresponds to * appliance resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_APPLIANCE = 0x05, /** * UI mode: value that corresponds to * watch resource qualifier specified. */ ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06, /** UI night mode: not specified.*/ ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00, /** * UI night mode: value that corresponds to * notnight resource qualifier specified. */ ACONFIGURATION_UI_MODE_NIGHT_NO = 0x1, /** * UI night mode: value that corresponds to * night resource qualifier specified. */ ACONFIGURATION_UI_MODE_NIGHT_YES = 0x2, /** Screen width DPI: not specified. */ ACONFIGURATION_SCREEN_WIDTH_DP_ANY = 0x0000, /** Screen height DPI: not specified. */ ACONFIGURATION_SCREEN_HEIGHT_DP_ANY = 0x0000, /** Smallest screen width DPI: not specified.*/ ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY = 0x0000, /** Layout direction: not specified. */ ACONFIGURATION_LAYOUTDIR_ANY = 0x00, /** * Layout direction: value that corresponds to * ldltr resource qualifier specified. */ ACONFIGURATION_LAYOUTDIR_LTR = 0x01, /** * Layout direction: value that corresponds to * ldrtl resource qualifier specified. */ ACONFIGURATION_LAYOUTDIR_RTL = 0x02, /** * Bit mask for * mcc * configuration. */ ACONFIGURATION_MCC = 0x0001, /** * Bit mask for * mnc * configuration. */ ACONFIGURATION_MNC = 0x0002, /** * Bit mask for * locale * configuration. */ ACONFIGURATION_LOCALE = 0x0004, /** * Bit mask for * touchscreen * configuration. */ ACONFIGURATION_TOUCHSCREEN = 0x0008, /** * Bit mask for * keyboard * configuration. */ ACONFIGURATION_KEYBOARD = 0x0010, /** * Bit mask for * keyboardHidden * configuration. */ ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020, /** * Bit mask for * navigation * configuration. */ ACONFIGURATION_NAVIGATION = 0x0040, /** * Bit mask for * orientation * configuration. */ ACONFIGURATION_ORIENTATION = 0x0080, /** * Bit mask for * density * configuration. */ ACONFIGURATION_DENSITY = 0x0100, /** * Bit mask for * screen size * configuration. */ ACONFIGURATION_SCREEN_SIZE = 0x0200, /** * Bit mask for * platform version * configuration. */ ACONFIGURATION_VERSION = 0x0400, /** * Bit mask for screen layout configuration. */ ACONFIGURATION_SCREEN_LAYOUT = 0x0800, /** * Bit mask for * ui mode * configuration. */ ACONFIGURATION_UI_MODE = 0x1000, /** * Bit mask for * smallest screen width * configuration. */ ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000, /** * Bit mask for * layout direction * configuration. */ ACONFIGURATION_LAYOUTDIR = 0x4000, ACONFIGURATION_SCREEN_ROUND = 0x8000, /** * Constant used to to represent MNC (Mobile Network Code) zero. * 0 cannot be used, since it is used to represent an undefined MNC. */ ACONFIGURATION_MNC_ZERO = 0xffff, }; /** * Create a new AConfiguration, initialized with no values set. */ AConfiguration* AConfiguration_new(); /** * Free an AConfiguration that was previously created with * AConfiguration_new(). */ void AConfiguration_delete(AConfiguration* config); /** * Create and return a new AConfiguration based on the current configuration in * use in the given {@link AAssetManager}. */ void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am); /** * Copy the contents of 'src' to 'dest'. */ void AConfiguration_copy(AConfiguration* dest, AConfiguration* src); /** * Return the current MCC set in the configuration. 0 if not set. */ int32_t AConfiguration_getMcc(AConfiguration* config); /** * Set the current MCC in the configuration. 0 to clear. */ void AConfiguration_setMcc(AConfiguration* config, int32_t mcc); /** * Return the current MNC set in the configuration. 0 if not set. */ int32_t AConfiguration_getMnc(AConfiguration* config); /** * Set the current MNC in the configuration. 0 to clear. */ void AConfiguration_setMnc(AConfiguration* config, int32_t mnc); /** * Return the current language code set in the configuration. The output will * be filled with an array of two characters. They are not 0-terminated. If * a language is not set, they will be 0. */ void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage); /** * Set the current language code in the configuration, from the first two * characters in the string. */ void AConfiguration_setLanguage(AConfiguration* config, const char* language); /** * Return the current country code set in the configuration. The output will * be filled with an array of two characters. They are not 0-terminated. If * a country is not set, they will be 0. */ void AConfiguration_getCountry(AConfiguration* config, char* outCountry); /** * Set the current country code in the configuration, from the first two * characters in the string. */ void AConfiguration_setCountry(AConfiguration* config, const char* country); /** * Return the current ACONFIGURATION_ORIENTATION_* set in the configuration. */ int32_t AConfiguration_getOrientation(AConfiguration* config); /** * Set the current orientation in the configuration. */ void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation); /** * Return the current ACONFIGURATION_TOUCHSCREEN_* set in the configuration. */ int32_t AConfiguration_getTouchscreen(AConfiguration* config); /** * Set the current touchscreen in the configuration. */ void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen); /** * Return the current ACONFIGURATION_DENSITY_* set in the configuration. */ int32_t AConfiguration_getDensity(AConfiguration* config); /** * Set the current density in the configuration. */ void AConfiguration_setDensity(AConfiguration* config, int32_t density); /** * Return the current ACONFIGURATION_KEYBOARD_* set in the configuration. */ int32_t AConfiguration_getKeyboard(AConfiguration* config); /** * Set the current keyboard in the configuration. */ void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard); /** * Return the current ACONFIGURATION_NAVIGATION_* set in the configuration. */ int32_t AConfiguration_getNavigation(AConfiguration* config); /** * Set the current navigation in the configuration. */ void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation); /** * Return the current ACONFIGURATION_KEYSHIDDEN_* set in the configuration. */ int32_t AConfiguration_getKeysHidden(AConfiguration* config); /** * Set the current keys hidden in the configuration. */ void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden); /** * Return the current ACONFIGURATION_NAVHIDDEN_* set in the configuration. */ int32_t AConfiguration_getNavHidden(AConfiguration* config); /** * Set the current nav hidden in the configuration. */ void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden); /** * Return the current SDK (API) version set in the configuration. */ int32_t AConfiguration_getSdkVersion(AConfiguration* config); /** * Set the current SDK version in the configuration. */ void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion); /** * Return the current ACONFIGURATION_SCREENSIZE_* set in the configuration. */ int32_t AConfiguration_getScreenSize(AConfiguration* config); /** * Set the current screen size in the configuration. */ void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize); /** * Return the current ACONFIGURATION_SCREENLONG_* set in the configuration. */ int32_t AConfiguration_getScreenLong(AConfiguration* config); /** * Set the current screen long in the configuration. */ void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); /** * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration. */ int32_t AConfiguration_getScreenRound(AConfiguration* config); /** * Set the current screen round in the configuration. */ void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound); /** * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration. */ int32_t AConfiguration_getUiModeType(AConfiguration* config); /** * Set the current UI mode type in the configuration. */ void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType); /** * Return the current ACONFIGURATION_UI_MODE_NIGHT_* set in the configuration. */ int32_t AConfiguration_getUiModeNight(AConfiguration* config); /** * Set the current UI mode night in the configuration. */ void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight); /** * Return the current configuration screen width in dp units, or * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set. */ int32_t AConfiguration_getScreenWidthDp(AConfiguration* config); /** * Set the configuration's current screen width in dp units. */ void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value); /** * Return the current configuration screen height in dp units, or * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set. */ int32_t AConfiguration_getScreenHeightDp(AConfiguration* config); /** * Set the configuration's current screen width in dp units. */ void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value); /** * Return the configuration's smallest screen width in dp units, or * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set. */ int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config); /** * Set the configuration's smallest screen width in dp units. */ void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value); /** * Return the configuration's layout direction, or * ACONFIGURATION_LAYOUTDIR_ANY if not set. */ int32_t AConfiguration_getLayoutDirection(AConfiguration* config); /** * Set the configuration's layout direction. */ void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value); /** * Perform a diff between two configurations. Returns a bit mask of * ACONFIGURATION_* constants, each bit set meaning that configuration element * is different between them. */ int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2); /** * Determine whether 'base' is a valid configuration for use within the * environment 'requested'. Returns 0 if there are any values in 'base' * that conflict with 'requested'. Returns 1 if it does not conflict. */ int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested); /** * Determine whether the configuration in 'test' is better than the existing * configuration in 'base'. If 'requested' is non-NULL, this decision is based * on the overall configuration given there. If it is NULL, this decision is * simply based on which configuration is more specific. Returns non-0 if * 'test' is better than 'base'. * * This assumes you have already filtered the configurations with * AConfiguration_match(). */ int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test, AConfiguration* requested); #ifdef __cplusplus }; #endif #endif // ANDROID_CONFIGURATION_H /** @} */ include/android/input.h0100644 0000000 0000000 00000143657 13077405420 014202 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Input * @{ */ /** * @file input.h */ #ifndef _ANDROID_INPUT_H #define _ANDROID_INPUT_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ /* * Structures and functions to receive and process input events in * native code. * * NOTE: These functions MUST be implemented by /system/lib/libui.so */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Key states (may be returned by queries about the current state of a * particular key code, scan code or switch). */ enum { /** The key state is unknown or the requested key itself is not supported. */ AKEY_STATE_UNKNOWN = -1, /** The key is up. */ AKEY_STATE_UP = 0, /** The key is down. */ AKEY_STATE_DOWN = 1, /** The key is down but is a virtual key press that is being emulated by the system. */ AKEY_STATE_VIRTUAL = 2 }; /** * Meta key / modifer state. */ enum { /** No meta keys are pressed. */ AMETA_NONE = 0, /** This mask is used to check whether one of the ALT meta keys is pressed. */ AMETA_ALT_ON = 0x02, /** This mask is used to check whether the left ALT meta key is pressed. */ AMETA_ALT_LEFT_ON = 0x10, /** This mask is used to check whether the right ALT meta key is pressed. */ AMETA_ALT_RIGHT_ON = 0x20, /** This mask is used to check whether one of the SHIFT meta keys is pressed. */ AMETA_SHIFT_ON = 0x01, /** This mask is used to check whether the left SHIFT meta key is pressed. */ AMETA_SHIFT_LEFT_ON = 0x40, /** This mask is used to check whether the right SHIFT meta key is pressed. */ AMETA_SHIFT_RIGHT_ON = 0x80, /** This mask is used to check whether the SYM meta key is pressed. */ AMETA_SYM_ON = 0x04, /** This mask is used to check whether the FUNCTION meta key is pressed. */ AMETA_FUNCTION_ON = 0x08, /** This mask is used to check whether one of the CTRL meta keys is pressed. */ AMETA_CTRL_ON = 0x1000, /** This mask is used to check whether the left CTRL meta key is pressed. */ AMETA_CTRL_LEFT_ON = 0x2000, /** This mask is used to check whether the right CTRL meta key is pressed. */ AMETA_CTRL_RIGHT_ON = 0x4000, /** This mask is used to check whether one of the META meta keys is pressed. */ AMETA_META_ON = 0x10000, /** This mask is used to check whether the left META meta key is pressed. */ AMETA_META_LEFT_ON = 0x20000, /** This mask is used to check whether the right META meta key is pressed. */ AMETA_META_RIGHT_ON = 0x40000, /** This mask is used to check whether the CAPS LOCK meta key is on. */ AMETA_CAPS_LOCK_ON = 0x100000, /** This mask is used to check whether the NUM LOCK meta key is on. */ AMETA_NUM_LOCK_ON = 0x200000, /** This mask is used to check whether the SCROLL LOCK meta key is on. */ AMETA_SCROLL_LOCK_ON = 0x400000, }; struct AInputEvent; /** * Input events. * * Input events are opaque structures. Use the provided accessors functions to * read their properties. */ typedef struct AInputEvent AInputEvent; /** * Input event types. */ enum { /** Indicates that the input event is a key event. */ AINPUT_EVENT_TYPE_KEY = 1, /** Indicates that the input event is a motion event. */ AINPUT_EVENT_TYPE_MOTION = 2 }; /** * Key event actions. */ enum { /** The key has been pressed down. */ AKEY_EVENT_ACTION_DOWN = 0, /** The key has been released. */ AKEY_EVENT_ACTION_UP = 1, /** * Multiple duplicate key events have occurred in a row, or a * complex string is being delivered. The repeat_count property * of the key event contains the number of times the given key * code should be executed. */ AKEY_EVENT_ACTION_MULTIPLE = 2 }; /** * Key event flags. */ enum { /** This mask is set if the device woke because of this key event. */ AKEY_EVENT_FLAG_WOKE_HERE = 0x1, /** This mask is set if the key event was generated by a software keyboard. */ AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2, /** This mask is set if we don't want the key event to cause us to leave touch mode. */ AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4, /** * This mask is set if an event was known to come from a trusted * part of the system. That is, the event is known to come from * the user, and could not have been spoofed by a third party * component. */ AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8, /** * This mask is used for compatibility, to identify enter keys that are * coming from an IME whose enter key has been auto-labelled "next" or * "done". This allows TextView to dispatch these as normal enter keys * for old applications, but still do the appropriate action when * receiving them. */ AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10, /** * When associated with up key events, this indicates that the key press * has been canceled. Typically this is used with virtual touch screen * keys, where the user can slide from the virtual key area on to the * display: in that case, the application will receive a canceled up * event and should not perform the action normally associated with the * key. Note that for this to work, the application can not perform an * action for a key until it receives an up or the long press timeout has * expired. */ AKEY_EVENT_FLAG_CANCELED = 0x20, /** * This key event was generated by a virtual (on-screen) hard key area. * Typically this is an area of the touchscreen, outside of the regular * display, dedicated to "hardware" buttons. */ AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40, /** * This flag is set for the first key repeat that occurs after the * long press timeout. */ AKEY_EVENT_FLAG_LONG_PRESS = 0x80, /** * Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long * press action was executed while it was down. */ AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100, /** * Set for AKEY_EVENT_ACTION_UP when this event's key code is still being * tracked from its initial down. That is, somebody requested that tracking * started on the key down and a long press has not caused * the tracking to be canceled. */ AKEY_EVENT_FLAG_TRACKING = 0x200, /** * Set when a key event has been synthesized to implement default behavior * for an event that the application did not handle. * Fallback key events are generated by unhandled trackball motions * (to emulate a directional keypad) and by certain unhandled key presses * that are declared in the key map (such as special function numeric keypad * keys when numlock is off). */ AKEY_EVENT_FLAG_FALLBACK = 0x400, }; /** * Bit shift for the action bits holding the pointer index as * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK. */ #define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8 /** Motion event actions */ enum { /** Bit mask of the parts of the action code that are the action itself. */ AMOTION_EVENT_ACTION_MASK = 0xff, /** * Bits in the action code that represent a pointer index, used with * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer * index where the data for the pointer going up or down can be found. */ AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, /** A pressed gesture has started, the motion contains the initial starting location. */ AMOTION_EVENT_ACTION_DOWN = 0, /** * A pressed gesture has finished, the motion contains the final release location * as well as any intermediate points since the last down or move event. */ AMOTION_EVENT_ACTION_UP = 1, /** * A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as * any intermediate points since the last down or move event. */ AMOTION_EVENT_ACTION_MOVE = 2, /** * The current gesture has been aborted. * You will not receive any more points in it. You should treat this as * an up event, but not perform any action that you normally would. */ AMOTION_EVENT_ACTION_CANCEL = 3, /** * A movement has happened outside of the normal bounds of the UI element. * This does not provide a full gesture, but only the initial location of the movement/touch. */ AMOTION_EVENT_ACTION_OUTSIDE = 4, /** * A non-primary pointer has gone down. * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. */ AMOTION_EVENT_ACTION_POINTER_DOWN = 5, /** * A non-primary pointer has gone up. * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. */ AMOTION_EVENT_ACTION_POINTER_UP = 6, /** * A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). * The motion contains the most recent point, as well as any intermediate points since * the last hover move event. */ AMOTION_EVENT_ACTION_HOVER_MOVE = 7, /** * The motion event contains relative vertical and/or horizontal scroll offsets. * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL * and AMOTION_EVENT_AXIS_HSCROLL. * The pointer may or may not be down when this event is dispatched. * This action is always delivered to the winder under the pointer, which * may not be the window currently touched. */ AMOTION_EVENT_ACTION_SCROLL = 8, /** The pointer is not down but has entered the boundaries of a window or view. */ AMOTION_EVENT_ACTION_HOVER_ENTER = 9, /** The pointer is not down but has exited the boundaries of a window or view. */ AMOTION_EVENT_ACTION_HOVER_EXIT = 10, /* One or more buttons have been pressed. */ AMOTION_EVENT_ACTION_BUTTON_PRESS = 11, /* One or more buttons have been released. */ AMOTION_EVENT_ACTION_BUTTON_RELEASE = 12, }; /** * Motion event flags. */ enum { /** * This flag indicates that the window that received this motion event is partly * or wholly obscured by another visible window above it. This flag is set to true * even if the event did not directly pass through the obscured area. * A security sensitive application can check this flag to identify situations in which * a malicious application may have covered up part of its content for the purpose * of misleading the user or hijacking touches. An appropriate response might be * to drop the suspect touches or to take additional precautions to confirm the user's * actual intent. */ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1, }; /** * Motion event edge touch flags. */ enum { /** No edges intersected. */ AMOTION_EVENT_EDGE_FLAG_NONE = 0, /** Flag indicating the motion event intersected the top edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_TOP = 0x01, /** Flag indicating the motion event intersected the bottom edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02, /** Flag indicating the motion event intersected the left edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04, /** Flag indicating the motion event intersected the right edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08 }; /** * Constants that identify each individual axis of a motion event. * @anchor AMOTION_EVENT_AXIS */ enum { /** * Axis constant: X axis of a motion event. * * - For a touch screen, reports the absolute X screen position of the center of * the touch contact area. The units are display pixels. * - For a touch pad, reports the absolute X surface position of the center of the touch * contact area. The units are device-dependent. * - For a mouse, reports the absolute X screen position of the mouse pointer. * The units are display pixels. * - For a trackball, reports the relative horizontal displacement of the trackball. * The value is normalized to a range from -1.0 (left) to 1.0 (right). * - For a joystick, reports the absolute X position of the joystick. * The value is normalized to a range from -1.0 (left) to 1.0 (right). */ AMOTION_EVENT_AXIS_X = 0, /** * Axis constant: Y axis of a motion event. * * - For a touch screen, reports the absolute Y screen position of the center of * the touch contact area. The units are display pixels. * - For a touch pad, reports the absolute Y surface position of the center of the touch * contact area. The units are device-dependent. * - For a mouse, reports the absolute Y screen position of the mouse pointer. * The units are display pixels. * - For a trackball, reports the relative vertical displacement of the trackball. * The value is normalized to a range from -1.0 (up) to 1.0 (down). * - For a joystick, reports the absolute Y position of the joystick. * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near). */ AMOTION_EVENT_AXIS_Y = 1, /** * Axis constant: Pressure axis of a motion event. * * - For a touch screen or touch pad, reports the approximate pressure applied to the surface * by a finger or other tool. The value is normalized to a range from * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1 * may be generated depending on the calibration of the input device. * - For a trackball, the value is set to 1 if the trackball button is pressed * or 0 otherwise. * - For a mouse, the value is set to 1 if the primary mouse button is pressed * or 0 otherwise. */ AMOTION_EVENT_AXIS_PRESSURE = 2, /** * Axis constant: Size axis of a motion event. * * - For a touch screen or touch pad, reports the approximate size of the contact area in * relation to the maximum detectable size for the device. The value is normalized * to a range from 0 (smallest detectable size) to 1 (largest detectable size), * although it is not a linear scale. This value is of limited use. * To obtain calibrated size information, see * {@link AMOTION_EVENT_AXIS_TOUCH_MAJOR} or {@link AMOTION_EVENT_AXIS_TOOL_MAJOR}. */ AMOTION_EVENT_AXIS_SIZE = 3, /** * Axis constant: TouchMajor axis of a motion event. * * - For a touch screen, reports the length of the major axis of an ellipse that * represents the touch area at the point of contact. * The units are display pixels. * - For a touch pad, reports the length of the major axis of an ellipse that * represents the touch area at the point of contact. * The units are device-dependent. */ AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4, /** * Axis constant: TouchMinor axis of a motion event. * * - For a touch screen, reports the length of the minor axis of an ellipse that * represents the touch area at the point of contact. * The units are display pixels. * - For a touch pad, reports the length of the minor axis of an ellipse that * represents the touch area at the point of contact. * The units are device-dependent. * * When the touch is circular, the major and minor axis lengths will be equal to one another. */ AMOTION_EVENT_AXIS_TOUCH_MINOR = 5, /** * Axis constant: ToolMajor axis of a motion event. * * - For a touch screen, reports the length of the major axis of an ellipse that * represents the size of the approaching finger or tool used to make contact. * - For a touch pad, reports the length of the major axis of an ellipse that * represents the size of the approaching finger or tool used to make contact. * The units are device-dependent. * * When the touch is circular, the major and minor axis lengths will be equal to one another. * * The tool size may be larger than the touch size since the tool may not be fully * in contact with the touch sensor. */ AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, /** * Axis constant: ToolMinor axis of a motion event. * * - For a touch screen, reports the length of the minor axis of an ellipse that * represents the size of the approaching finger or tool used to make contact. * - For a touch pad, reports the length of the minor axis of an ellipse that * represents the size of the approaching finger or tool used to make contact. * The units are device-dependent. * * When the touch is circular, the major and minor axis lengths will be equal to one another. * * The tool size may be larger than the touch size since the tool may not be fully * in contact with the touch sensor. */ AMOTION_EVENT_AXIS_TOOL_MINOR = 7, /** * Axis constant: Orientation axis of a motion event. * * - For a touch screen or touch pad, reports the orientation of the finger * or tool in radians relative to the vertical plane of the device. * An angle of 0 radians indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians * (finger pointing fully right). * - For a stylus, the orientation indicates the direction in which the stylus * is pointing in relation to the vertical axis of the current orientation of the screen. * The range is from -PI radians to PI radians, where 0 is pointing up, * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians * is pointing right. See also {@link AMOTION_EVENT_AXIS_TILT}. */ AMOTION_EVENT_AXIS_ORIENTATION = 8, /** * Axis constant: Vertical Scroll axis of a motion event. * * - For a mouse, reports the relative movement of the vertical scroll wheel. * The value is normalized to a range from -1.0 (down) to 1.0 (up). * * This axis should be used to scroll views vertically. */ AMOTION_EVENT_AXIS_VSCROLL = 9, /** * Axis constant: Horizontal Scroll axis of a motion event. * * - For a mouse, reports the relative movement of the horizontal scroll wheel. * The value is normalized to a range from -1.0 (left) to 1.0 (right). * * This axis should be used to scroll views horizontally. */ AMOTION_EVENT_AXIS_HSCROLL = 10, /** * Axis constant: Z axis of a motion event. * * - For a joystick, reports the absolute Z position of the joystick. * The value is normalized to a range from -1.0 (high) to 1.0 (low). * On game pads with two analog joysticks, this axis is often reinterpreted * to report the absolute X position of the second joystick instead. */ AMOTION_EVENT_AXIS_Z = 11, /** * Axis constant: X Rotation axis of a motion event. * * - For a joystick, reports the absolute rotation angle about the X axis. * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). */ AMOTION_EVENT_AXIS_RX = 12, /** * Axis constant: Y Rotation axis of a motion event. * * - For a joystick, reports the absolute rotation angle about the Y axis. * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). */ AMOTION_EVENT_AXIS_RY = 13, /** * Axis constant: Z Rotation axis of a motion event. * * - For a joystick, reports the absolute rotation angle about the Z axis. * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). * On game pads with two analog joysticks, this axis is often reinterpreted * to report the absolute Y position of the second joystick instead. */ AMOTION_EVENT_AXIS_RZ = 14, /** * Axis constant: Hat X axis of a motion event. * * - For a joystick, reports the absolute X position of the directional hat control. * The value is normalized to a range from -1.0 (left) to 1.0 (right). */ AMOTION_EVENT_AXIS_HAT_X = 15, /** * Axis constant: Hat Y axis of a motion event. * * - For a joystick, reports the absolute Y position of the directional hat control. * The value is normalized to a range from -1.0 (up) to 1.0 (down). */ AMOTION_EVENT_AXIS_HAT_Y = 16, /** * Axis constant: Left Trigger axis of a motion event. * * - For a joystick, reports the absolute position of the left trigger control. * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). */ AMOTION_EVENT_AXIS_LTRIGGER = 17, /** * Axis constant: Right Trigger axis of a motion event. * * - For a joystick, reports the absolute position of the right trigger control. * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). */ AMOTION_EVENT_AXIS_RTRIGGER = 18, /** * Axis constant: Throttle axis of a motion event. * * - For a joystick, reports the absolute position of the throttle control. * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed). */ AMOTION_EVENT_AXIS_THROTTLE = 19, /** * Axis constant: Rudder axis of a motion event. * * - For a joystick, reports the absolute position of the rudder control. * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right). */ AMOTION_EVENT_AXIS_RUDDER = 20, /** * Axis constant: Wheel axis of a motion event. * * - For a joystick, reports the absolute position of the steering wheel control. * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right). */ AMOTION_EVENT_AXIS_WHEEL = 21, /** * Axis constant: Gas axis of a motion event. * * - For a joystick, reports the absolute position of the gas (accelerator) control. * The value is normalized to a range from 0.0 (no acceleration) * to 1.0 (maximum acceleration). */ AMOTION_EVENT_AXIS_GAS = 22, /** * Axis constant: Brake axis of a motion event. * * - For a joystick, reports the absolute position of the brake control. * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking). */ AMOTION_EVENT_AXIS_BRAKE = 23, /** * Axis constant: Distance axis of a motion event. * * - For a stylus, reports the distance of the stylus from the screen. * A value of 0.0 indicates direct contact and larger values indicate increasing * distance from the surface. */ AMOTION_EVENT_AXIS_DISTANCE = 24, /** * Axis constant: Tilt axis of a motion event. * * - For a stylus, reports the tilt angle of the stylus in radians where * 0 radians indicates that the stylus is being held perpendicular to the * surface, and PI/2 radians indicates that the stylus is being held flat * against the surface. */ AMOTION_EVENT_AXIS_TILT = 25, /** * Axis constant: Generic scroll axis of a motion event. * * - This is used for scroll axis motion events that can't be classified as strictly * vertical or horizontal. The movement of a rotating scroller is an example of this. */ AMOTION_EVENT_AXIS_SCROLL = 26, /** * Axis constant: The movement of x position of a motion event. * * - For a mouse, reports a difference of x position between the previous position. * This is useful when pointer is captured, in that case the mouse pointer doesn't * change the location but this axis reports the difference which allows the app * to see how the mouse is moved. */ AMOTION_EVENT_AXIS_RELATIVE_X = 27, /** * Axis constant: The movement of y position of a motion event. * * Same as {@link RELATIVE_X}, but for y position. */ AMOTION_EVENT_AXIS_RELATIVE_Y = 28, /** * Axis constant: Generic 1 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_1 = 32, /** * Axis constant: Generic 2 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_2 = 33, /** * Axis constant: Generic 3 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_3 = 34, /** * Axis constant: Generic 4 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_4 = 35, /** * Axis constant: Generic 5 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_5 = 36, /** * Axis constant: Generic 6 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_6 = 37, /** * Axis constant: Generic 7 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_7 = 38, /** * Axis constant: Generic 8 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_8 = 39, /** * Axis constant: Generic 9 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_9 = 40, /** * Axis constant: Generic 10 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_10 = 41, /** * Axis constant: Generic 11 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_11 = 42, /** * Axis constant: Generic 12 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_12 = 43, /** * Axis constant: Generic 13 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_13 = 44, /** * Axis constant: Generic 14 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_14 = 45, /** * Axis constant: Generic 15 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_15 = 46, /** * Axis constant: Generic 16 axis of a motion event. * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_16 = 47, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. }; /** * Constants that identify buttons that are associated with motion events. * Refer to the documentation on the MotionEvent class for descriptions of each button. */ enum { /** primary */ AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, /** secondary */ AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, /** tertiary */ AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, /** back */ AMOTION_EVENT_BUTTON_BACK = 1 << 3, /** forward */ AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5, AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6, }; /** * Constants that identify tool types. * Refer to the documentation on the MotionEvent class for descriptions of each tool type. */ enum { /** unknown */ AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, /** finger */ AMOTION_EVENT_TOOL_TYPE_FINGER = 1, /** stylus */ AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, /** mouse */ AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, /** eraser */ AMOTION_EVENT_TOOL_TYPE_ERASER = 4, }; /** * Input source masks. * * Refer to the documentation on android.view.InputDevice for more details about input sources * and their correct interpretation. */ enum { /** mask */ AINPUT_SOURCE_CLASS_MASK = 0x000000ff, /** none */ AINPUT_SOURCE_CLASS_NONE = 0x00000000, /** button */ AINPUT_SOURCE_CLASS_BUTTON = 0x00000001, /** pointer */ AINPUT_SOURCE_CLASS_POINTER = 0x00000002, /** navigation */ AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004, /** position */ AINPUT_SOURCE_CLASS_POSITION = 0x00000008, /** joystick */ AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010, }; /** * Input sources. */ enum { /** unknown */ AINPUT_SOURCE_UNKNOWN = 0x00000000, /** keyboard */ AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON, /** dpad */ AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON, /** gamepad */ AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, /** touchscreen */ AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, /** mouse */ AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, /** stylus */ AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, /** bluetooth stylus */ AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS, /** trackball */ AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, /** touchpad */ AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, /** navigation */ AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE, /** joystick */ AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, /** rotary encoder */ AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE, /** any */ AINPUT_SOURCE_ANY = 0xffffff00, }; /** * Keyboard types. * * Refer to the documentation on android.view.InputDevice for more details. */ enum { /** none */ AINPUT_KEYBOARD_TYPE_NONE = 0, /** non alphabetic */ AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1, /** alphabetic */ AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2, }; /** * Constants used to retrieve information about the range of motion for a particular * coordinate of a motion event. * * Refer to the documentation on android.view.InputDevice for more details about input sources * and their correct interpretation. * * @deprecated These constants are deprecated. Use {@link AMOTION_EVENT_AXIS AMOTION_EVENT_AXIS_*} constants instead. */ enum { /** x */ AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X, /** y */ AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y, /** pressure */ AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE, /** size */ AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE, /** touch major */ AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR, /** touch minor */ AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR, /** tool major */ AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR, /** tool minor */ AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR, /** orientation */ AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION, }; /** * Input event accessors. * * Note that most functions can only be used on input events that are of a given type. * Calling these functions on input events of other types will yield undefined behavior. */ /*** Accessors for all input events. ***/ /** Get the input event type. */ int32_t AInputEvent_getType(const AInputEvent* event); /** Get the id for the device that an input event came from. * * Input events can be generated by multiple different input devices. * Use the input device id to obtain information about the input * device that was responsible for generating a particular event. * * An input device id of 0 indicates that the event didn't come from a physical device; * other numbers are arbitrary and you shouldn't depend on the values. * Use the provided input device query API to obtain information about input devices. */ int32_t AInputEvent_getDeviceId(const AInputEvent* event); /** Get the input event source. */ int32_t AInputEvent_getSource(const AInputEvent* event); /*** Accessors for key events only. ***/ /** Get the key event action. */ int32_t AKeyEvent_getAction(const AInputEvent* key_event); /** Get the key event flags. */ int32_t AKeyEvent_getFlags(const AInputEvent* key_event); /** * Get the key code of the key event. * This is the physical key that was pressed, not the Unicode character. */ int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event); /** * Get the hardware key id of this key event. * These values are not reliable and vary from device to device. */ int32_t AKeyEvent_getScanCode(const AInputEvent* key_event); /** Get the meta key state. */ int32_t AKeyEvent_getMetaState(const AInputEvent* key_event); /** * Get the repeat count of the event. * For both key up an key down events, this is the number of times the key has * repeated with the first down starting at 0 and counting up from there. For * multiple key events, this is the number of down/up pairs that have occurred. */ int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event); /** * Get the time of the most recent key down event, in the * java.lang.System.nanoTime() time base. If this is a down event, * this will be the same as eventTime. * Note that when chording keys, this value is the down time of the most recently * pressed key, which may not be the same physical key of this event. */ int64_t AKeyEvent_getDownTime(const AInputEvent* key_event); /** * Get the time this event occurred, in the * java.lang.System.nanoTime() time base. */ int64_t AKeyEvent_getEventTime(const AInputEvent* key_event); /*** Accessors for motion events only. ***/ /** Get the combined motion event action code and pointer index. */ int32_t AMotionEvent_getAction(const AInputEvent* motion_event); /** Get the motion event flags. */ int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); /** * Get the state of any meta / modifier keys that were in effect when the * event was generated. */ int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); /** Get the button state of all buttons that are pressed. */ int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); /** * Get a bitfield indicating which edges, if any, were touched by this motion event. * For touch events, clients can use this to determine if the user's finger was * touching the edge of the display. */ int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event); /** * Get the time when the user originally pressed down to start a stream of * position events, in the java.lang.System.nanoTime() time base. */ int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event); /** * Get the time when this specific event was generated, * in the java.lang.System.nanoTime() time base. */ int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event); /** * Get the X coordinate offset. * For touch events on the screen, this is the delta that was added to the raw * screen coordinates to adjust for the absolute position of the containing windows * and views. */ float AMotionEvent_getXOffset(const AInputEvent* motion_event); /** * Get the Y coordinate offset. * For touch events on the screen, this is the delta that was added to the raw * screen coordinates to adjust for the absolute position of the containing windows * and views. */ float AMotionEvent_getYOffset(const AInputEvent* motion_event); /** * Get the precision of the X coordinates being reported. * You can multiply this number with an X coordinate sample to find the * actual hardware value of the X coordinate. */ float AMotionEvent_getXPrecision(const AInputEvent* motion_event); /** * Get the precision of the Y coordinates being reported. * You can multiply this number with a Y coordinate sample to find the * actual hardware value of the Y coordinate. */ float AMotionEvent_getYPrecision(const AInputEvent* motion_event); /** * Get the number of pointers of data contained in this event. * Always >= 1. */ size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); /** * Get the pointer identifier associated with a particular pointer * data index in this event. The identifier tells you the actual pointer * number associated with the data, accounting for individual pointers * going up and down since the start of the current gesture. */ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); /** * Get the tool type of a pointer for the given pointer index. * The tool type indicates the type of tool used to make contact such as a * finger or stylus, if known. */ int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); /** * Get the original raw X coordinate of this event. * For touch events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. */ float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index); /** * Get the original raw X coordinate of this event. * For touch events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. */ float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current X coordinate of this event for the given pointer index. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current Y coordinate of this event for the given pointer index. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current pressure of this event for the given pointer index. * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), * although values higher than 1 may be generated depending on the calibration of * the input device. */ float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current scaled value of the approximate size for the given pointer index. * This represents some approximation of the area of the screen being * pressed; the actual value in pixels corresponding to the * touch is normalized with the device specific range of values * and scaled to a value between 0 and 1. The value of size can be used to * determine fat touch events. */ float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current length of the major axis of an ellipse that describes the touch area * at the point of contact for the given pointer index. */ float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current length of the minor axis of an ellipse that describes the touch area * at the point of contact for the given pointer index. */ float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current length of the major axis of an ellipse that describes the size * of the approaching tool for the given pointer index. * The tool area represents the estimated size of the finger or pen that is * touching the device independent of its actual touch area at the point of contact. */ float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current length of the minor axis of an ellipse that describes the size * of the approaching tool for the given pointer index. * The tool area represents the estimated size of the finger or pen that is * touching the device independent of its actual touch area at the point of contact. */ float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index); /** * Get the current orientation of the touch area and tool area in radians clockwise from * vertical for the given pointer index. * An angle of 0 degrees indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians * (finger pointing fully right). */ float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); /** Get the value of the request axis for the given pointer index. */ float AMotionEvent_getAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_index); /** * Get the number of historical points in this event. These are movements that * have occurred between this event and the previous event. This only applies * to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0. * Historical samples are indexed from oldest to newest. */ size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event); /** * Get the time that a historical movement occurred between this event and * the previous event, in the java.lang.System.nanoTime() time base. */ int64_t AMotionEvent_getHistoricalEventTime(const AInputEvent* motion_event, size_t history_index); /** * Get the historical raw X coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. * For touch events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical raw Y coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. * For touch events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window * and views. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical X coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getHistoricalX(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical Y coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ float AMotionEvent_getHistoricalY(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical pressure of this event for the given pointer index that * occurred between this event and the previous motion event. * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), * although values higher than 1 may be generated depending on the calibration of * the input device. */ float AMotionEvent_getHistoricalPressure(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the current scaled value of the approximate size for the given pointer index that * occurred between this event and the previous motion event. * This represents some approximation of the area of the screen being * pressed; the actual value in pixels corresponding to the * touch is normalized with the device specific range of values * and scaled to a value between 0 and 1. The value of size can be used to * determine fat touch events. */ float AMotionEvent_getHistoricalSize(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical length of the major axis of an ellipse that describes the touch area * at the point of contact for the given pointer index that * occurred between this event and the previous motion event. */ float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical length of the minor axis of an ellipse that describes the touch area * at the point of contact for the given pointer index that * occurred between this event and the previous motion event. */ float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical length of the major axis of an ellipse that describes the size * of the approaching tool for the given pointer index that * occurred between this event and the previous motion event. * The tool area represents the estimated size of the finger or pen that is * touching the device independent of its actual touch area at the point of contact. */ float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical length of the minor axis of an ellipse that describes the size * of the approaching tool for the given pointer index that * occurred between this event and the previous motion event. * The tool area represents the estimated size of the finger or pen that is * touching the device independent of its actual touch area at the point of contact. */ float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical orientation of the touch area and tool area in radians clockwise from * vertical for the given pointer index that * occurred between this event and the previous motion event. * An angle of 0 degrees indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians * (finger pointing fully right). */ float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); /** * Get the historical value of the request axis for the given pointer index * that occurred between this event and the previous motion event. */ float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_index, size_t history_index); struct AInputQueue; /** * Input queue * * An input queue is the facility through which you retrieve input * events. */ typedef struct AInputQueue AInputQueue; /** * Add this input queue to a looper for processing. See * ALooper_addFd() for information on the ident, callback, and data params. */ void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, int ident, ALooper_callbackFunc callback, void* data); /** * Remove the input queue from the looper it is currently attached to. */ void AInputQueue_detachLooper(AInputQueue* queue); /** * Returns true if there are one or more events available in the * input queue. Returns 1 if the queue has events; 0 if * it does not have events; and a negative value if there is an error. */ int32_t AInputQueue_hasEvents(AInputQueue* queue); /** * Returns the next available event from the queue. Returns a negative * value if no events are available or an error has occurred. */ int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent); /** * Sends the key for standard pre-dispatching -- that is, possibly deliver * it to the current IME to be consumed before the app. Returns 0 if it * was not pre-dispatched, meaning you can process it right now. If non-zero * is returned, you must abandon the current event processing and allow the * event to appear again in the event queue (if it does not get consumed during * pre-dispatching). */ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); /** * Report that dispatching has finished with the given event. * This must be called after receiving an event with AInputQueue_get_event(). */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); #ifdef __cplusplus } #endif #endif // _ANDROID_INPUT_H /** @} */ include/android/keycodes.h0100644 0000000 0000000 00000070004 13077405420 014632 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Input * @{ */ /** * @file keycodes.h */ #ifndef _ANDROID_KEYCODES_H #define _ANDROID_KEYCODES_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ #include #ifdef __cplusplus extern "C" { #endif /** * Key codes. */ enum { /** Unknown key code. */ AKEYCODE_UNKNOWN = 0, /** Soft Left key. * Usually situated below the display on phones and used as a multi-function * feature key for selecting a software defined function shown on the bottom left * of the display. */ AKEYCODE_SOFT_LEFT = 1, /** Soft Right key. * Usually situated below the display on phones and used as a multi-function * feature key for selecting a software defined function shown on the bottom right * of the display. */ AKEYCODE_SOFT_RIGHT = 2, /** Home key. * This key is handled by the framework and is never delivered to applications. */ AKEYCODE_HOME = 3, /** Back key. */ AKEYCODE_BACK = 4, /** Call key. */ AKEYCODE_CALL = 5, /** End Call key. */ AKEYCODE_ENDCALL = 6, /** '0' key. */ AKEYCODE_0 = 7, /** '1' key. */ AKEYCODE_1 = 8, /** '2' key. */ AKEYCODE_2 = 9, /** '3' key. */ AKEYCODE_3 = 10, /** '4' key. */ AKEYCODE_4 = 11, /** '5' key. */ AKEYCODE_5 = 12, /** '6' key. */ AKEYCODE_6 = 13, /** '7' key. */ AKEYCODE_7 = 14, /** '8' key. */ AKEYCODE_8 = 15, /** '9' key. */ AKEYCODE_9 = 16, /** '*' key. */ AKEYCODE_STAR = 17, /** '#' key. */ AKEYCODE_POUND = 18, /** Directional Pad Up key. * May also be synthesized from trackball motions. */ AKEYCODE_DPAD_UP = 19, /** Directional Pad Down key. * May also be synthesized from trackball motions. */ AKEYCODE_DPAD_DOWN = 20, /** Directional Pad Left key. * May also be synthesized from trackball motions. */ AKEYCODE_DPAD_LEFT = 21, /** Directional Pad Right key. * May also be synthesized from trackball motions. */ AKEYCODE_DPAD_RIGHT = 22, /** Directional Pad Center key. * May also be synthesized from trackball motions. */ AKEYCODE_DPAD_CENTER = 23, /** Volume Up key. * Adjusts the speaker volume up. */ AKEYCODE_VOLUME_UP = 24, /** Volume Down key. * Adjusts the speaker volume down. */ AKEYCODE_VOLUME_DOWN = 25, /** Power key. */ AKEYCODE_POWER = 26, /** Camera key. * Used to launch a camera application or take pictures. */ AKEYCODE_CAMERA = 27, /** Clear key. */ AKEYCODE_CLEAR = 28, /** 'A' key. */ AKEYCODE_A = 29, /** 'B' key. */ AKEYCODE_B = 30, /** 'C' key. */ AKEYCODE_C = 31, /** 'D' key. */ AKEYCODE_D = 32, /** 'E' key. */ AKEYCODE_E = 33, /** 'F' key. */ AKEYCODE_F = 34, /** 'G' key. */ AKEYCODE_G = 35, /** 'H' key. */ AKEYCODE_H = 36, /** 'I' key. */ AKEYCODE_I = 37, /** 'J' key. */ AKEYCODE_J = 38, /** 'K' key. */ AKEYCODE_K = 39, /** 'L' key. */ AKEYCODE_L = 40, /** 'M' key. */ AKEYCODE_M = 41, /** 'N' key. */ AKEYCODE_N = 42, /** 'O' key. */ AKEYCODE_O = 43, /** 'P' key. */ AKEYCODE_P = 44, /** 'Q' key. */ AKEYCODE_Q = 45, /** 'R' key. */ AKEYCODE_R = 46, /** 'S' key. */ AKEYCODE_S = 47, /** 'T' key. */ AKEYCODE_T = 48, /** 'U' key. */ AKEYCODE_U = 49, /** 'V' key. */ AKEYCODE_V = 50, /** 'W' key. */ AKEYCODE_W = 51, /** 'X' key. */ AKEYCODE_X = 52, /** 'Y' key. */ AKEYCODE_Y = 53, /** 'Z' key. */ AKEYCODE_Z = 54, /** ',' key. */ AKEYCODE_COMMA = 55, /** '.' key. */ AKEYCODE_PERIOD = 56, /** Left Alt modifier key. */ AKEYCODE_ALT_LEFT = 57, /** Right Alt modifier key. */ AKEYCODE_ALT_RIGHT = 58, /** Left Shift modifier key. */ AKEYCODE_SHIFT_LEFT = 59, /** Right Shift modifier key. */ AKEYCODE_SHIFT_RIGHT = 60, /** Tab key. */ AKEYCODE_TAB = 61, /** Space key. */ AKEYCODE_SPACE = 62, /** Symbol modifier key. * Used to enter alternate symbols. */ AKEYCODE_SYM = 63, /** Explorer special function key. * Used to launch a browser application. */ AKEYCODE_EXPLORER = 64, /** Envelope special function key. * Used to launch a mail application. */ AKEYCODE_ENVELOPE = 65, /** Enter key. */ AKEYCODE_ENTER = 66, /** Backspace key. * Deletes characters before the insertion point, unlike {@link AKEYCODE_FORWARD_DEL}. */ AKEYCODE_DEL = 67, /** '`' (backtick) key. */ AKEYCODE_GRAVE = 68, /** '-'. */ AKEYCODE_MINUS = 69, /** '=' key. */ AKEYCODE_EQUALS = 70, /** '[' key. */ AKEYCODE_LEFT_BRACKET = 71, /** ']' key. */ AKEYCODE_RIGHT_BRACKET = 72, /** '\' key. */ AKEYCODE_BACKSLASH = 73, /** ';' key. */ AKEYCODE_SEMICOLON = 74, /** ''' (apostrophe) key. */ AKEYCODE_APOSTROPHE = 75, /** '/' key. */ AKEYCODE_SLASH = 76, /** '@' key. */ AKEYCODE_AT = 77, /** Number modifier key. * Used to enter numeric symbols. * This key is not {@link AKEYCODE_NUM_LOCK}; it is more like {@link AKEYCODE_ALT_LEFT}. */ AKEYCODE_NUM = 78, /** Headset Hook key. * Used to hang up calls and stop media. */ AKEYCODE_HEADSETHOOK = 79, /** Camera Focus key. * Used to focus the camera. */ AKEYCODE_FOCUS = 80, /** '+' key. */ AKEYCODE_PLUS = 81, /** Menu key. */ AKEYCODE_MENU = 82, /** Notification key. */ AKEYCODE_NOTIFICATION = 83, /** Search key. */ AKEYCODE_SEARCH = 84, /** Play/Pause media key. */ AKEYCODE_MEDIA_PLAY_PAUSE= 85, /** Stop media key. */ AKEYCODE_MEDIA_STOP = 86, /** Play Next media key. */ AKEYCODE_MEDIA_NEXT = 87, /** Play Previous media key. */ AKEYCODE_MEDIA_PREVIOUS = 88, /** Rewind media key. */ AKEYCODE_MEDIA_REWIND = 89, /** Fast Forward media key. */ AKEYCODE_MEDIA_FAST_FORWARD = 90, /** Mute key. * Mutes the microphone, unlike {@link AKEYCODE_VOLUME_MUTE}. */ AKEYCODE_MUTE = 91, /** Page Up key. */ AKEYCODE_PAGE_UP = 92, /** Page Down key. */ AKEYCODE_PAGE_DOWN = 93, /** Picture Symbols modifier key. * Used to switch symbol sets (Emoji, Kao-moji). */ AKEYCODE_PICTSYMBOLS = 94, /** Switch Charset modifier key. * Used to switch character sets (Kanji, Katakana). */ AKEYCODE_SWITCH_CHARSET = 95, /** A Button key. * On a game controller, the A button should be either the button labeled A * or the first button on the bottom row of controller buttons. */ AKEYCODE_BUTTON_A = 96, /** B Button key. * On a game controller, the B button should be either the button labeled B * or the second button on the bottom row of controller buttons. */ AKEYCODE_BUTTON_B = 97, /** C Button key. * On a game controller, the C button should be either the button labeled C * or the third button on the bottom row of controller buttons. */ AKEYCODE_BUTTON_C = 98, /** X Button key. * On a game controller, the X button should be either the button labeled X * or the first button on the upper row of controller buttons. */ AKEYCODE_BUTTON_X = 99, /** Y Button key. * On a game controller, the Y button should be either the button labeled Y * or the second button on the upper row of controller buttons. */ AKEYCODE_BUTTON_Y = 100, /** Z Button key. * On a game controller, the Z button should be either the button labeled Z * or the third button on the upper row of controller buttons. */ AKEYCODE_BUTTON_Z = 101, /** L1 Button key. * On a game controller, the L1 button should be either the button labeled L1 (or L) * or the top left trigger button. */ AKEYCODE_BUTTON_L1 = 102, /** R1 Button key. * On a game controller, the R1 button should be either the button labeled R1 (or R) * or the top right trigger button. */ AKEYCODE_BUTTON_R1 = 103, /** L2 Button key. * On a game controller, the L2 button should be either the button labeled L2 * or the bottom left trigger button. */ AKEYCODE_BUTTON_L2 = 104, /** R2 Button key. * On a game controller, the R2 button should be either the button labeled R2 * or the bottom right trigger button. */ AKEYCODE_BUTTON_R2 = 105, /** Left Thumb Button key. * On a game controller, the left thumb button indicates that the left (or only) * joystick is pressed. */ AKEYCODE_BUTTON_THUMBL = 106, /** Right Thumb Button key. * On a game controller, the right thumb button indicates that the right * joystick is pressed. */ AKEYCODE_BUTTON_THUMBR = 107, /** Start Button key. * On a game controller, the button labeled Start. */ AKEYCODE_BUTTON_START = 108, /** Select Button key. * On a game controller, the button labeled Select. */ AKEYCODE_BUTTON_SELECT = 109, /** Mode Button key. * On a game controller, the button labeled Mode. */ AKEYCODE_BUTTON_MODE = 110, /** Escape key. */ AKEYCODE_ESCAPE = 111, /** Forward Delete key. * Deletes characters ahead of the insertion point, unlike {@link AKEYCODE_DEL}. */ AKEYCODE_FORWARD_DEL = 112, /** Left Control modifier key. */ AKEYCODE_CTRL_LEFT = 113, /** Right Control modifier key. */ AKEYCODE_CTRL_RIGHT = 114, /** Caps Lock key. */ AKEYCODE_CAPS_LOCK = 115, /** Scroll Lock key. */ AKEYCODE_SCROLL_LOCK = 116, /** Left Meta modifier key. */ AKEYCODE_META_LEFT = 117, /** Right Meta modifier key. */ AKEYCODE_META_RIGHT = 118, /** Function modifier key. */ AKEYCODE_FUNCTION = 119, /** System Request / Print Screen key. */ AKEYCODE_SYSRQ = 120, /** Break / Pause key. */ AKEYCODE_BREAK = 121, /** Home Movement key. * Used for scrolling or moving the cursor around to the start of a line * or to the top of a list. */ AKEYCODE_MOVE_HOME = 122, /** End Movement key. * Used for scrolling or moving the cursor around to the end of a line * or to the bottom of a list. */ AKEYCODE_MOVE_END = 123, /** Insert key. * Toggles insert / overwrite edit mode. */ AKEYCODE_INSERT = 124, /** Forward key. * Navigates forward in the history stack. Complement of {@link AKEYCODE_BACK}. */ AKEYCODE_FORWARD = 125, /** Play media key. */ AKEYCODE_MEDIA_PLAY = 126, /** Pause media key. */ AKEYCODE_MEDIA_PAUSE = 127, /** Close media key. * May be used to close a CD tray, for example. */ AKEYCODE_MEDIA_CLOSE = 128, /** Eject media key. * May be used to eject a CD tray, for example. */ AKEYCODE_MEDIA_EJECT = 129, /** Record media key. */ AKEYCODE_MEDIA_RECORD = 130, /** F1 key. */ AKEYCODE_F1 = 131, /** F2 key. */ AKEYCODE_F2 = 132, /** F3 key. */ AKEYCODE_F3 = 133, /** F4 key. */ AKEYCODE_F4 = 134, /** F5 key. */ AKEYCODE_F5 = 135, /** F6 key. */ AKEYCODE_F6 = 136, /** F7 key. */ AKEYCODE_F7 = 137, /** F8 key. */ AKEYCODE_F8 = 138, /** F9 key. */ AKEYCODE_F9 = 139, /** F10 key. */ AKEYCODE_F10 = 140, /** F11 key. */ AKEYCODE_F11 = 141, /** F12 key. */ AKEYCODE_F12 = 142, /** Num Lock key. * This is the Num Lock key; it is different from {@link AKEYCODE_NUM}. * This key alters the behavior of other keys on the numeric keypad. */ AKEYCODE_NUM_LOCK = 143, /** Numeric keypad '0' key. */ AKEYCODE_NUMPAD_0 = 144, /** Numeric keypad '1' key. */ AKEYCODE_NUMPAD_1 = 145, /** Numeric keypad '2' key. */ AKEYCODE_NUMPAD_2 = 146, /** Numeric keypad '3' key. */ AKEYCODE_NUMPAD_3 = 147, /** Numeric keypad '4' key. */ AKEYCODE_NUMPAD_4 = 148, /** Numeric keypad '5' key. */ AKEYCODE_NUMPAD_5 = 149, /** Numeric keypad '6' key. */ AKEYCODE_NUMPAD_6 = 150, /** Numeric keypad '7' key. */ AKEYCODE_NUMPAD_7 = 151, /** Numeric keypad '8' key. */ AKEYCODE_NUMPAD_8 = 152, /** Numeric keypad '9' key. */ AKEYCODE_NUMPAD_9 = 153, /** Numeric keypad '/' key (for division). */ AKEYCODE_NUMPAD_DIVIDE = 154, /** Numeric keypad '*' key (for multiplication). */ AKEYCODE_NUMPAD_MULTIPLY = 155, /** Numeric keypad '-' key (for subtraction). */ AKEYCODE_NUMPAD_SUBTRACT = 156, /** Numeric keypad '+' key (for addition). */ AKEYCODE_NUMPAD_ADD = 157, /** Numeric keypad '.' key (for decimals or digit grouping). */ AKEYCODE_NUMPAD_DOT = 158, /** Numeric keypad ',' key (for decimals or digit grouping). */ AKEYCODE_NUMPAD_COMMA = 159, /** Numeric keypad Enter key. */ AKEYCODE_NUMPAD_ENTER = 160, /** Numeric keypad '=' key. */ AKEYCODE_NUMPAD_EQUALS = 161, /** Numeric keypad '(' key. */ AKEYCODE_NUMPAD_LEFT_PAREN = 162, /** Numeric keypad ')' key. */ AKEYCODE_NUMPAD_RIGHT_PAREN = 163, /** Volume Mute key. * Mutes the speaker, unlike {@link AKEYCODE_MUTE}. * This key should normally be implemented as a toggle such that the first press * mutes the speaker and the second press restores the original volume. */ AKEYCODE_VOLUME_MUTE = 164, /** Info key. * Common on TV remotes to show additional information related to what is * currently being viewed. */ AKEYCODE_INFO = 165, /** Channel up key. * On TV remotes, increments the television channel. */ AKEYCODE_CHANNEL_UP = 166, /** Channel down key. * On TV remotes, decrements the television channel. */ AKEYCODE_CHANNEL_DOWN = 167, /** Zoom in key. */ AKEYCODE_ZOOM_IN = 168, /** Zoom out key. */ AKEYCODE_ZOOM_OUT = 169, /** TV key. * On TV remotes, switches to viewing live TV. */ AKEYCODE_TV = 170, /** Window key. * On TV remotes, toggles picture-in-picture mode or other windowing functions. */ AKEYCODE_WINDOW = 171, /** Guide key. * On TV remotes, shows a programming guide. */ AKEYCODE_GUIDE = 172, /** DVR key. * On some TV remotes, switches to a DVR mode for recorded shows. */ AKEYCODE_DVR = 173, /** Bookmark key. * On some TV remotes, bookmarks content or web pages. */ AKEYCODE_BOOKMARK = 174, /** Toggle captions key. * Switches the mode for closed-captioning text, for example during television shows. */ AKEYCODE_CAPTIONS = 175, /** Settings key. * Starts the system settings activity. */ AKEYCODE_SETTINGS = 176, /** TV power key. * On TV remotes, toggles the power on a television screen. */ AKEYCODE_TV_POWER = 177, /** TV input key. * On TV remotes, switches the input on a television screen. */ AKEYCODE_TV_INPUT = 178, /** Set-top-box power key. * On TV remotes, toggles the power on an external Set-top-box. */ AKEYCODE_STB_POWER = 179, /** Set-top-box input key. * On TV remotes, switches the input mode on an external Set-top-box. */ AKEYCODE_STB_INPUT = 180, /** A/V Receiver power key. * On TV remotes, toggles the power on an external A/V Receiver. */ AKEYCODE_AVR_POWER = 181, /** A/V Receiver input key. * On TV remotes, switches the input mode on an external A/V Receiver. */ AKEYCODE_AVR_INPUT = 182, /** Red "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ AKEYCODE_PROG_RED = 183, /** Green "programmable" key. * On TV remotes, actsas a contextual/programmable key. */ AKEYCODE_PROG_GREEN = 184, /** Yellow "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ AKEYCODE_PROG_YELLOW = 185, /** Blue "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ AKEYCODE_PROG_BLUE = 186, /** App switch key. * Should bring up the application switcher dialog. */ AKEYCODE_APP_SWITCH = 187, /** Generic Game Pad Button #1.*/ AKEYCODE_BUTTON_1 = 188, /** Generic Game Pad Button #2.*/ AKEYCODE_BUTTON_2 = 189, /** Generic Game Pad Button #3.*/ AKEYCODE_BUTTON_3 = 190, /** Generic Game Pad Button #4.*/ AKEYCODE_BUTTON_4 = 191, /** Generic Game Pad Button #5.*/ AKEYCODE_BUTTON_5 = 192, /** Generic Game Pad Button #6.*/ AKEYCODE_BUTTON_6 = 193, /** Generic Game Pad Button #7.*/ AKEYCODE_BUTTON_7 = 194, /** Generic Game Pad Button #8.*/ AKEYCODE_BUTTON_8 = 195, /** Generic Game Pad Button #9.*/ AKEYCODE_BUTTON_9 = 196, /** Generic Game Pad Button #10.*/ AKEYCODE_BUTTON_10 = 197, /** Generic Game Pad Button #11.*/ AKEYCODE_BUTTON_11 = 198, /** Generic Game Pad Button #12.*/ AKEYCODE_BUTTON_12 = 199, /** Generic Game Pad Button #13.*/ AKEYCODE_BUTTON_13 = 200, /** Generic Game Pad Button #14.*/ AKEYCODE_BUTTON_14 = 201, /** Generic Game Pad Button #15.*/ AKEYCODE_BUTTON_15 = 202, /** Generic Game Pad Button #16.*/ AKEYCODE_BUTTON_16 = 203, /** Language Switch key. * Toggles the current input language such as switching between English and Japanese on * a QWERTY keyboard. On some devices, the same function may be performed by * pressing Shift+Spacebar. */ AKEYCODE_LANGUAGE_SWITCH = 204, /** Manner Mode key. * Toggles silent or vibrate mode on and off to make the device behave more politely * in certain settings such as on a crowded train. On some devices, the key may only * operate when long-pressed. */ AKEYCODE_MANNER_MODE = 205, /** 3D Mode key. * Toggles the display between 2D and 3D mode. */ AKEYCODE_3D_MODE = 206, /** Contacts special function key. * Used to launch an address book application. */ AKEYCODE_CONTACTS = 207, /** Calendar special function key. * Used to launch a calendar application. */ AKEYCODE_CALENDAR = 208, /** Music special function key. * Used to launch a music player application. */ AKEYCODE_MUSIC = 209, /** Calculator special function key. * Used to launch a calculator application. */ AKEYCODE_CALCULATOR = 210, /** Japanese full-width / half-width key. */ AKEYCODE_ZENKAKU_HANKAKU = 211, /** Japanese alphanumeric key. */ AKEYCODE_EISU = 212, /** Japanese non-conversion key. */ AKEYCODE_MUHENKAN = 213, /** Japanese conversion key. */ AKEYCODE_HENKAN = 214, /** Japanese katakana / hiragana key. */ AKEYCODE_KATAKANA_HIRAGANA = 215, /** Japanese Yen key. */ AKEYCODE_YEN = 216, /** Japanese Ro key. */ AKEYCODE_RO = 217, /** Japanese kana key. */ AKEYCODE_KANA = 218, /** Assist key. * Launches the global assist activity. Not delivered to applications. */ AKEYCODE_ASSIST = 219, /** Brightness Down key. * Adjusts the screen brightness down. */ AKEYCODE_BRIGHTNESS_DOWN = 220, /** Brightness Up key. * Adjusts the screen brightness up. */ AKEYCODE_BRIGHTNESS_UP = 221, /** Audio Track key. * Switches the audio tracks. */ AKEYCODE_MEDIA_AUDIO_TRACK = 222, /** Sleep key. * Puts the device to sleep. Behaves somewhat like {@link AKEYCODE_POWER} but it * has no effect if the device is already asleep. */ AKEYCODE_SLEEP = 223, /** Wakeup key. * Wakes up the device. Behaves somewhat like {@link AKEYCODE_POWER} but it * has no effect if the device is already awake. */ AKEYCODE_WAKEUP = 224, /** Pairing key. * Initiates peripheral pairing mode. Useful for pairing remote control * devices or game controllers, especially if no other input mode is * available. */ AKEYCODE_PAIRING = 225, /** Media Top Menu key. * Goes to the top of media menu. */ AKEYCODE_MEDIA_TOP_MENU = 226, /** '11' key. */ AKEYCODE_11 = 227, /** '12' key. */ AKEYCODE_12 = 228, /** Last Channel key. * Goes to the last viewed channel. */ AKEYCODE_LAST_CHANNEL = 229, /** TV data service key. * Displays data services like weather, sports. */ AKEYCODE_TV_DATA_SERVICE = 230, /** Voice Assist key. * Launches the global voice assist activity. Not delivered to applications. */ AKEYCODE_VOICE_ASSIST = 231, /** Radio key. * Toggles TV service / Radio service. */ AKEYCODE_TV_RADIO_SERVICE = 232, /** Teletext key. * Displays Teletext service. */ AKEYCODE_TV_TELETEXT = 233, /** Number entry key. * Initiates to enter multi-digit channel nubmber when each digit key is assigned * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC * User Control Code. */ AKEYCODE_TV_NUMBER_ENTRY = 234, /** Analog Terrestrial key. * Switches to analog terrestrial broadcast service. */ AKEYCODE_TV_TERRESTRIAL_ANALOG = 235, /** Digital Terrestrial key. * Switches to digital terrestrial broadcast service. */ AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236, /** Satellite key. * Switches to digital satellite broadcast service. */ AKEYCODE_TV_SATELLITE = 237, /** BS key. * Switches to BS digital satellite broadcasting service available in Japan. */ AKEYCODE_TV_SATELLITE_BS = 238, /** CS key. * Switches to CS digital satellite broadcasting service available in Japan. */ AKEYCODE_TV_SATELLITE_CS = 239, /** BS/CS key. * Toggles between BS and CS digital satellite services. */ AKEYCODE_TV_SATELLITE_SERVICE = 240, /** Toggle Network key. * Toggles selecting broacast services. */ AKEYCODE_TV_NETWORK = 241, /** Antenna/Cable key. * Toggles broadcast input source between antenna and cable. */ AKEYCODE_TV_ANTENNA_CABLE = 242, /** HDMI #1 key. * Switches to HDMI input #1. */ AKEYCODE_TV_INPUT_HDMI_1 = 243, /** HDMI #2 key. * Switches to HDMI input #2. */ AKEYCODE_TV_INPUT_HDMI_2 = 244, /** HDMI #3 key. * Switches to HDMI input #3. */ AKEYCODE_TV_INPUT_HDMI_3 = 245, /** HDMI #4 key. * Switches to HDMI input #4. */ AKEYCODE_TV_INPUT_HDMI_4 = 246, /** Composite #1 key. * Switches to composite video input #1. */ AKEYCODE_TV_INPUT_COMPOSITE_1 = 247, /** Composite #2 key. * Switches to composite video input #2. */ AKEYCODE_TV_INPUT_COMPOSITE_2 = 248, /** Component #1 key. * Switches to component video input #1. */ AKEYCODE_TV_INPUT_COMPONENT_1 = 249, /** Component #2 key. * Switches to component video input #2. */ AKEYCODE_TV_INPUT_COMPONENT_2 = 250, /** VGA #1 key. * Switches to VGA (analog RGB) input #1. */ AKEYCODE_TV_INPUT_VGA_1 = 251, /** Audio description key. * Toggles audio description off / on. */ AKEYCODE_TV_AUDIO_DESCRIPTION = 252, /** Audio description mixing volume up key. * Louden audio description volume as compared with normal audio volume. */ AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253, /** Audio description mixing volume down key. * Lessen audio description volume as compared with normal audio volume. */ AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254, /** Zoom mode key. * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */ AKEYCODE_TV_ZOOM_MODE = 255, /** Contents menu key. * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control * Code */ AKEYCODE_TV_CONTENTS_MENU = 256, /** Media context menu key. * Goes to the context menu of media contents. Corresponds to Media Context-sensitive * Menu (0x11) of CEC User Control Code. */ AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257, /** Timer programming key. * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of * CEC User Control Code. */ AKEYCODE_TV_TIMER_PROGRAMMING = 258, /** Help key. */ AKEYCODE_HELP = 259, AKEYCODE_NAVIGATE_PREVIOUS = 260, AKEYCODE_NAVIGATE_NEXT = 261, AKEYCODE_NAVIGATE_IN = 262, AKEYCODE_NAVIGATE_OUT = 263, /** Primary stem key for Wear * Main power/reset button on watch. */ AKEYCODE_STEM_PRIMARY = 264, /** Generic stem key 1 for Wear */ AKEYCODE_STEM_1 = 265, /** Generic stem key 2 for Wear */ AKEYCODE_STEM_2 = 266, /** Generic stem key 3 for Wear */ AKEYCODE_STEM_3 = 267, /** Directional Pad Up-Left */ AKEYCODE_DPAD_UP_LEFT = 268, /** Directional Pad Down-Left */ AKEYCODE_DPAD_DOWN_LEFT = 269, /** Directional Pad Up-Right */ AKEYCODE_DPAD_UP_RIGHT = 270, /** Directional Pad Down-Right */ AKEYCODE_DPAD_DOWN_RIGHT = 271, /** Skip forward media key */ AKEYCODE_MEDIA_SKIP_FORWARD = 272, /** Skip backward media key */ AKEYCODE_MEDIA_SKIP_BACKWARD = 273, /** Step forward media key. * Steps media forward one from at a time. */ AKEYCODE_MEDIA_STEP_FORWARD = 274, /** Step backward media key. * Steps media backward one from at a time. */ AKEYCODE_MEDIA_STEP_BACKWARD = 275, /** Put device to sleep unless a wakelock is held. */ AKEYCODE_SOFT_SLEEP = 276, /** Cut key. */ AKEYCODE_CUT = 277, /** Copy key. */ AKEYCODE_COPY = 278, /** Paste key. */ AKEYCODE_PASTE = 279 // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. }; #ifdef __cplusplus } #endif #endif // _ANDROID_KEYCODES_H /** @} */ include/android/looper.h0100644 0000000 0000000 00000022222 13077405420 014323 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Looper * @{ */ /** * @file looper.h */ #ifndef ANDROID_LOOPER_H #define ANDROID_LOOPER_H #ifdef __cplusplus extern "C" { #endif struct ALooper; /** * ALooper * * A looper is the state tracking an event loop for a thread. * Loopers do not define event structures or other such things; rather * they are a lower-level facility to attach one or more discrete objects * listening for an event. An "event" here is simply data available on * a file descriptor: each attached object has an associated file descriptor, * and waiting for "events" means (internally) polling on all of these file * descriptors until one or more of them have data available. * * A thread can have only one ALooper associated with it. */ typedef struct ALooper ALooper; /** * Returns the looper associated with the calling thread, or NULL if * there is not one. */ ALooper* ALooper_forThread(); /** Option for for ALooper_prepare(). */ enum { /** * This looper will accept calls to ALooper_addFd() that do not * have a callback (that is provide NULL for the callback). In * this case the caller of ALooper_pollOnce() or ALooper_pollAll() * MUST check the return from these functions to discover when * data is available on such fds and process it. */ ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0 }; /** * Prepares a looper associated with the calling thread, and returns it. * If the thread already has a looper, it is returned. Otherwise, a new * one is created, associated with the thread, and returned. * * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0. */ ALooper* ALooper_prepare(int opts); /** Result from ALooper_pollOnce() and ALooper_pollAll(). */ enum { /** * The poll was awoken using wake() before the timeout expired * and no callbacks were executed and no other file descriptors were ready. */ ALOOPER_POLL_WAKE = -1, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * One or more callbacks were executed. */ ALOOPER_POLL_CALLBACK = -2, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * The timeout expired. */ ALOOPER_POLL_TIMEOUT = -3, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * An error occurred. */ ALOOPER_POLL_ERROR = -4, }; /** * Acquire a reference on the given ALooper object. This prevents the object * from being deleted until the reference is removed. This is only needed * to safely hand an ALooper from one thread to another. */ void ALooper_acquire(ALooper* looper); /** * Remove a reference that was previously acquired with ALooper_acquire(). */ void ALooper_release(ALooper* looper); /** * Flags for file descriptor events that a looper can monitor. * * These flag bits can be combined to monitor multiple events at once. */ enum { /** * The file descriptor is available for read operations. */ ALOOPER_EVENT_INPUT = 1 << 0, /** * The file descriptor is available for write operations. */ ALOOPER_EVENT_OUTPUT = 1 << 1, /** * The file descriptor has encountered an error condition. * * The looper always sends notifications about errors; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_ERROR = 1 << 2, /** * The file descriptor was hung up. * For example, indicates that the remote end of a pipe or socket was closed. * * The looper always sends notifications about hangups; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_HANGUP = 1 << 3, /** * The file descriptor is invalid. * For example, the file descriptor was closed prematurely. * * The looper always sends notifications about invalid file descriptors; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_INVALID = 1 << 4, }; /** * For callback-based event loops, this is the prototype of the function * that is called when a file descriptor event occurs. * It is given the file descriptor it is associated with, * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT), * and the data pointer that was originally supplied. * * Implementations should return 1 to continue receiving callbacks, or 0 * to have this file descriptor and callback unregistered from the looper. */ typedef int (*ALooper_callbackFunc)(int fd, int events, void* data); /** * Waits for events to be available, with optional timeout in milliseconds. * Invokes callbacks for all file descriptors on which an event occurred. * * If the timeout is zero, returns immediately without blocking. * If the timeout is negative, waits indefinitely until an event appears. * * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before * the timeout expired and no callbacks were invoked and no other file * descriptors were ready. * * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. * * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given * timeout expired. * * Returns ALOOPER_POLL_ERROR if an error occurred. * * Returns a value >= 0 containing an identifier (the same identifier * `ident` passed to ALooper_addFd()) if its file descriptor has data * and it has no callback function (requiring the caller here to * handle it). In this (and only this) case outFd, outEvents and * outData will contain the poll events and data associated with the * fd, otherwise they will be set to NULL. * * This method does not return until it has finished invoking the appropriate callbacks * for all file descriptors that were signalled. */ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); /** * Like ALooper_pollOnce(), but performs all pending callbacks until all * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. */ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); /** * Wakes the poll asynchronously. * * This method can be called on any thread. * This method returns immediately. */ void ALooper_wake(ALooper* looper); /** * Adds a new file descriptor to be polled by the looper. * If the same file descriptor was previously added, it is replaced. * * "fd" is the file descriptor to be added. * "ident" is an identifier for this event, which is returned from ALooper_pollOnce(). * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback. * "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT. * "callback" is the function to call when there is an event on the file descriptor. * "data" is a private data pointer to supply to the callback. * * There are two main uses of this function: * * (1) If "callback" is non-NULL, then this function will be called when there is * data on the file descriptor. It should execute any events it has pending, * appropriately reading from the file descriptor. The 'ident' is ignored in this case. * * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce * when its file descriptor has data available, requiring the caller to take * care of processing it. * * Returns 1 if the file descriptor was added or -1 if an error occurred. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */ int ALooper_addFd(ALooper* looper, int fd, int ident, int events, ALooper_callbackFunc callback, void* data); /** * Removes a previously added file descriptor from the looper. * * When this method returns, it is safe to close the file descriptor since the looper * will no longer have a reference to it. However, it is possible for the callback to * already be running or for it to run one last time if the file descriptor was already * signalled. Calling code is responsible for ensuring that this case is safely handled. * For example, if the callback takes care of removing itself during its own execution either * by returning 0 or by calling this method, then it can be guaranteed to not be invoked * again at any later time unless registered anew. * * Returns 1 if the file descriptor was removed, 0 if none was previously registered * or -1 if an error occurred. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */ int ALooper_removeFd(ALooper* looper, int fd); #ifdef __cplusplus }; #endif #endif // ANDROID_LOOPER_H /** @} */ include/android/multinetwork.h0100644 0000000 0000000 00000007363 13077405420 015600 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_MULTINETWORK_H #define ANDROID_MULTINETWORK_H #include #include #include __BEGIN_DECLS /** * The corresponding C type for android.net.Network#getNetworkHandle() return * values. The Java signed long value can be safely cast to a net_handle_t: * * [C] ((net_handle_t) java_long_network_handle) * [C++] static_cast(java_long_network_handle) * * as appropriate. */ typedef uint64_t net_handle_t; /** * The value NETWORK_UNSPECIFIED indicates no specific network. * * For some functions (documented below), a previous binding may be cleared * by an invocation with NETWORK_UNSPECIFIED. * * Depending on the context it may indicate an error. It is expressly * not used to indicate some notion of the "current default network". */ #define NETWORK_UNSPECIFIED ((net_handle_t)0) /** * All functions below that return an int return 0 on success or -1 * on failure with an appropriate errno value set. */ /** * Set the network to be used by the given socket file descriptor. * * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED. * * This is the equivalent of: * * [ android.net.Network#bindSocket() ] * https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket) */ int android_setsocknetwork(net_handle_t network, int fd); /** * Binds the current process to |network|. All sockets created in the future * (and not explicitly bound via android_setsocknetwork()) will be bound to * |network|. All host name resolutions will be limited to |network| as well. * Note that if the network identified by |network| ever disconnects, all * sockets created in this way will cease to work and all host name * resolutions will fail. This is by design so an application doesn't * accidentally use sockets it thinks are still bound to a particular network. * * To clear a previous process binding invoke with NETWORK_UNSPECIFIED. * * This is the equivalent of: * * [ android.net.ConnectivityManager#setProcessDefaultNetwork() ] * https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network) */ int android_setprocnetwork(net_handle_t network); /** * Perform hostname resolution via the DNS servers associated with |network|. * * All arguments (apart from |network|) are used identically as those passed * to getaddrinfo(3). Return and error values are identical to those of * getaddrinfo(3), and in particular gai_strerror(3) can be used as expected. * Similar to getaddrinfo(3): * - |hints| may be NULL (in which case man page documented defaults apply) * - either |node| or |service| may be NULL, but not both * - |res| must not be NULL * * This is the equivalent of: * * [ android.net.Network#getAllByName() ] * https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String) */ int android_getaddrinfofornetwork(net_handle_t network, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); __END_DECLS #endif // ANDROID_MULTINETWORK_H include/android/native_activity.h0100644 0000000 0000000 00000027004 13077405420 016230 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup NativeActivity Native Activity * @{ */ /** * @file native_activity.h */ #ifndef ANDROID_NATIVE_ACTIVITY_H #define ANDROID_NATIVE_ACTIVITY_H #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * {@link ANativeActivityCallbacks} */ struct ANativeActivityCallbacks; /** * This structure defines the native side of an android.app.NativeActivity. * It is created by the framework, and handed to the application's native * code as it is being launched. */ typedef struct ANativeActivity { /** * Pointer to the callback function table of the native application. * You can set the functions here to your own callbacks. The callbacks * pointer itself here should not be changed; it is allocated and managed * for you by the framework. */ struct ANativeActivityCallbacks* callbacks; /** * The global handle on the process's Java VM. */ JavaVM* vm; /** * JNI context for the main thread of the app. Note that this field * can ONLY be used from the main thread of the process; that is, the * thread that calls into the ANativeActivityCallbacks. */ JNIEnv* env; /** * The NativeActivity object handle. * * IMPORTANT NOTE: This member is mis-named. It should really be named * 'activity' instead of 'clazz', since it's a reference to the * NativeActivity instance created by the system for you. * * We unfortunately cannot change this without breaking NDK * source-compatibility. */ jobject clazz; /** * Path to this application's internal data directory. */ const char* internalDataPath; /** * Path to this application's external (removable/mountable) data directory. */ const char* externalDataPath; /** * The platform's SDK version code. */ int32_t sdkVersion; /** * This is the native instance of the application. It is not used by * the framework, but can be set by the application to its own instance * state. */ void* instance; /** * Pointer to the Asset Manager instance for the application. The application * uses this to access binary assets bundled inside its own .apk file. */ AAssetManager* assetManager; /** * Available starting with Honeycomb: path to the directory containing * the application's OBB files (if any). If the app doesn't have any * OBB files, this directory may not exist. */ const char* obbPath; } ANativeActivity; /** * These are the callbacks the framework makes into a native application. * All of these callbacks happen on the main thread of the application. * By default, all callbacks are NULL; set to a pointer to your own function * to have it called. */ typedef struct ANativeActivityCallbacks { /** * NativeActivity has started. See Java documentation for Activity.onStart() * for more information. */ void (*onStart)(ANativeActivity* activity); /** * NativeActivity has resumed. See Java documentation for Activity.onResume() * for more information. */ void (*onResume)(ANativeActivity* activity); /** * Framework is asking NativeActivity to save its current instance state. * See Java documentation for Activity.onSaveInstanceState() for more * information. The returned pointer needs to be created with malloc(); * the framework will call free() on it for you. You also must fill in * outSize with the number of bytes in the allocation. Note that the * saved state will be persisted, so it can not contain any active * entities (pointers to memory, file descriptors, etc). */ void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize); /** * NativeActivity has paused. See Java documentation for Activity.onPause() * for more information. */ void (*onPause)(ANativeActivity* activity); /** * NativeActivity has stopped. See Java documentation for Activity.onStop() * for more information. */ void (*onStop)(ANativeActivity* activity); /** * NativeActivity is being destroyed. See Java documentation for Activity.onDestroy() * for more information. */ void (*onDestroy)(ANativeActivity* activity); /** * Focus has changed in this NativeActivity's window. This is often used, * for example, to pause a game when it loses input focus. */ void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus); /** * The drawing window for this native activity has been created. You * can use the given native window object to start drawing. */ void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity has been resized. You should * retrieve the new size from the window and ensure that your rendering in * it now matches. */ void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity needs to be redrawn. To avoid * transient artifacts during screen changes (such resizing after rotation), * applications should not return from this function until they have finished * drawing their window in its current state. */ void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity is going to be destroyed. * You MUST ensure that you do not touch the window object after returning * from this function: in the common case of drawing to the window from * another thread, that means the implementation of this callback must * properly synchronize with the other thread to stop its drawing before * returning from here. */ void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window); /** * The input queue for this native activity's window has been created. * You can use the given input queue to start retrieving input events. */ void (*onInputQueueCreated)(ANativeActivity* activity, AInputQueue* queue); /** * The input queue for this native activity's window is being destroyed. * You should no longer try to reference this object upon returning from this * function. */ void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue); /** * The rectangle in the window in which content should be placed has changed. */ void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect); /** * The current device AConfiguration has changed. The new configuration can * be retrieved from assetManager. */ void (*onConfigurationChanged)(ANativeActivity* activity); /** * The system is running low on memory. Use this callback to release * resources you do not need, to help the system avoid killing more * important processes. */ void (*onLowMemory)(ANativeActivity* activity); } ANativeActivityCallbacks; /** * This is the function that must be in the native code to instantiate the * application's native activity. It is called with the activity instance (see * above); if the code is being instantiated from a previously saved instance, * the savedState will be non-NULL and point to the saved data. You must make * any copy of this data you need -- it will be released after you return from * this function. */ typedef void ANativeActivity_createFunc(ANativeActivity* activity, void* savedState, size_t savedStateSize); /** * The name of the function that NativeInstance looks for when launching its * native code. This is the default function that is used, you can specify * "android.app.func_name" string meta-data in your manifest to use a different * function. */ extern ANativeActivity_createFunc ANativeActivity_onCreate; /** * Finish the given activity. Its finish() method will be called, causing it * to be stopped and destroyed. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_finish(ANativeActivity* activity); /** * Change the window format of the given activity. Calls getWindow().setFormat() * of the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); /** * Change the window flags of the given activity. Calls getWindow().setFlags() * of the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. See window.h for flag constants. */ void ANativeActivity_setWindowFlags(ANativeActivity* activity, uint32_t addFlags, uint32_t removeFlags); /** * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager * API for documentation. */ enum { /** * Implicit request to show the input window, not as the result * of a direct request by the user. */ ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, /** * The user has forced the input method open (such as by * long-pressing menu) so it should not be closed until they * explicitly do so. */ ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, }; /** * Show the IME while in the given activity. Calls InputMethodManager.showSoftInput() * for the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags); /** * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager * API for documentation. */ enum { /** * The soft input window should only be hidden if it was not * explicitly shown by the user. */ ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, /** * The soft input window should normally be hidden, unless it was * originally shown with {@link ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED}. */ ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, }; /** * Hide the IME while in the given activity. Calls InputMethodManager.hideSoftInput() * for the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_ACTIVITY_H /** @} */ include/android/native_window.h0100644 0000000 0000000 00000010334 13077405420 015701 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup NativeActivity Native Activity * @{ */ /** * @file native_window.h */ #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H #include #ifdef __cplusplus extern "C" { #endif /** * Pixel formats that a window can use. */ enum { /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/ WINDOW_FORMAT_RGBA_8888 = 1, /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Unused: 8 bits. **/ WINDOW_FORMAT_RGBX_8888 = 2, /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/ WINDOW_FORMAT_RGB_565 = 4, }; struct ANativeWindow; /** * {@link ANativeWindow} is opaque type that provides access to a native window. * * A pointer can be obtained using ANativeWindow_fromSurface(). */ typedef struct ANativeWindow ANativeWindow; /** * {@link ANativeWindow} is a struct that represents a windows buffer. * * A pointer can be obtained using ANativeWindow_lock(). */ typedef struct ANativeWindow_Buffer { // The number of pixels that are show horizontally. int32_t width; // The number of pixels that are shown vertically. int32_t height; // The number of *pixels* that a line in the buffer takes in // memory. This may be >= width. int32_t stride; // The format of the buffer. One of WINDOW_FORMAT_* int32_t format; // The actual bits. void* bits; // Do not touch. uint32_t reserved[6]; } ANativeWindow_Buffer; /** * Acquire a reference on the given ANativeWindow object. This prevents the object * from being deleted until the reference is removed. */ void ANativeWindow_acquire(ANativeWindow* window); /** * Remove a reference that was previously acquired with ANativeWindow_acquire(). */ void ANativeWindow_release(ANativeWindow* window); /** * Return the current width in pixels of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getWidth(ANativeWindow* window); /** * Return the current height in pixels of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getHeight(ANativeWindow* window); /** * Return the current pixel format of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getFormat(ANativeWindow* window); /** * Change the format and size of the window buffers. * * The width and height control the number of pixels in the buffers, not the * dimensions of the window on screen. If these are different than the * window's physical size, then it buffer will be scaled to match that size * when compositing it to the screen. * * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * * width and height must be either both zero or both non-zero. * */ int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format); /** * Lock the window's next drawing surface for writing. * inOutDirtyBounds is used as an in/out parameter, upon entering the * function, it contains the dirty region, that is, the region the caller * intends to redraw. When the function returns, inOutDirtyBounds is updated * with the actual area the caller needs to redraw -- this region is often * extended by ANativeWindow_lock. */ int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); /** * Unlock the window's drawing surface after previously locking it, * posting the new buffer to the display. */ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_WINDOW_H /** @} */ include/android/native_window_jni.h0100644 0000000 0000000 00000002440 13077405420 016540 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup NativeActivity Native Activity * @{ */ /** * @file native_window_jni.h */ #ifndef ANDROID_NATIVE_WINDOW_JNI_H #define ANDROID_NATIVE_WINDOW_JNI_H #include #include #ifdef __cplusplus extern "C" { #endif /** * Return the ANativeWindow associated with a Java Surface object, * for interacting with it through native code. This acquires a reference * on the ANativeWindow that is returned; be sure to use ANativeWindow_release() * when done with it so that it doesn't leak. */ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_WINDOW_H /** @} */ include/android/obb.h0100644 0000000 0000000 00000003155 13077405420 013571 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Storage * @{ */ /** * @file obb.h */ #ifndef ANDROID_OBB_H #define ANDROID_OBB_H #include #ifdef __cplusplus extern "C" { #endif struct AObbInfo; /** {@link AObbInfo} is an opaque type representing information for obb storage. */ typedef struct AObbInfo AObbInfo; /** Flag for an obb file, returned by AObbInfo_getFlags(). */ enum { /** overlay */ AOBBINFO_OVERLAY = 0x0001, }; /** * Scan an OBB and get information about it. */ AObbInfo* AObbScanner_getObbInfo(const char* filename); /** * Destroy the AObbInfo object. You must call this when finished with the object. */ void AObbInfo_delete(AObbInfo* obbInfo); /** * Get the package name for the OBB. */ const char* AObbInfo_getPackageName(AObbInfo* obbInfo); /** * Get the version of an OBB file. */ int32_t AObbInfo_getVersion(AObbInfo* obbInfo); /** * Get the flags of an OBB file. */ int32_t AObbInfo_getFlags(AObbInfo* obbInfo); #ifdef __cplusplus }; #endif #endif // ANDROID_OBB_H /** @} */ include/android/rect.h0100644 0000000 0000000 00000002520 13077405420 013757 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup NativeActivity Native Activity * @{ */ /** * @file rect.h */ #ifndef ANDROID_RECT_H #define ANDROID_RECT_H #include #ifdef __cplusplus extern "C" { #endif /** * {@link ARect} is a struct that represents a rectangular window area. * * It is used with {@link * ANativeActivityCallbacks::onContentRectChanged} event callback and * ANativeWindow_lock() function. */ typedef struct ARect { #ifdef __cplusplus typedef int32_t value_type; #endif /** left position */ int32_t left; /** top position */ int32_t top; /** left position */ int32_t right; /** bottom position */ int32_t bottom; } ARect; #ifdef __cplusplus }; #endif #endif // ANDROID_RECT_H /** @} */ include/android/sensor.h0100644 0000000 0000000 00000034100 13077405420 014332 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Sensor * @{ */ /** * @file sensor.h */ #ifndef ANDROID_SENSOR_H #define ANDROID_SENSOR_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ /** * Structures and functions to receive and process sensor events in * native code. * */ #include #include #ifdef __cplusplus extern "C" { #endif /** * Sensor types. * (keep in sync with hardware/sensors.h) */ enum { /** * {@link ASENSOR_TYPE_ACCELEROMETER} * reporting-mode: continuous * * All values are in SI units (m/s^2) and measure the acceleration of the * device minus the force of gravity. */ ASENSOR_TYPE_ACCELEROMETER = 1, /** * {@link ASENSOR_TYPE_MAGNETIC_FIELD} * reporting-mode: continuous * * All values are in micro-Tesla (uT) and measure the geomagnetic * field in the X, Y and Z axis. */ ASENSOR_TYPE_MAGNETIC_FIELD = 2, /** * {@link ASENSOR_TYPE_GYROSCOPE} * reporting-mode: continuous * * All values are in radians/second and measure the rate of rotation * around the X, Y and Z axis. */ ASENSOR_TYPE_GYROSCOPE = 4, /** * {@link ASENSOR_TYPE_LIGHT} * reporting-mode: on-change * * The light sensor value is returned in SI lux units. */ ASENSOR_TYPE_LIGHT = 5, /** * {@link ASENSOR_TYPE_PROXIMITY} * reporting-mode: on-change * * The proximity sensor which turns the screen off and back on during calls is the * wake-up proximity sensor. Implement wake-up proximity sensor before implementing * a non wake-up proximity sensor. For the wake-up proximity sensor set the flag * SENSOR_FLAG_WAKE_UP. * The value corresponds to the distance to the nearest object in centimeters. */ ASENSOR_TYPE_PROXIMITY = 8, /** * {@link ASENSOR_TYPE_LINEAR_ACCELERATION} * reporting-mode: continuous * * All values are in SI units (m/s^2) and measure the acceleration of the * device not including the force of gravity. */ ASENSOR_TYPE_LINEAR_ACCELERATION = 10 }; /** * Sensor accuracy measure. */ enum { /** no contact */ ASENSOR_STATUS_NO_CONTACT = -1, /** unreliable */ ASENSOR_STATUS_UNRELIABLE = 0, /** low accuracy */ ASENSOR_STATUS_ACCURACY_LOW = 1, /** medium accuracy */ ASENSOR_STATUS_ACCURACY_MEDIUM = 2, /** high accuracy */ ASENSOR_STATUS_ACCURACY_HIGH = 3 }; /** * Sensor Reporting Modes. */ enum { /** continuous reporting */ AREPORTING_MODE_CONTINUOUS = 0, /** reporting on change */ AREPORTING_MODE_ON_CHANGE = 1, /** on shot reporting */ AREPORTING_MODE_ONE_SHOT = 2, /** special trigger reporting */ AREPORTING_MODE_SPECIAL_TRIGGER = 3 }; /* * A few useful constants */ /** Earth's gravity in m/s^2 */ #define ASENSOR_STANDARD_GRAVITY (9.80665f) /** Maximum magnetic field on Earth's surface in uT */ #define ASENSOR_MAGNETIC_FIELD_EARTH_MAX (60.0f) /** Minimum magnetic field on Earth's surface in uT*/ #define ASENSOR_MAGNETIC_FIELD_EARTH_MIN (30.0f) /** * A sensor event. */ /* NOTE: Must match hardware/sensors.h */ typedef struct ASensorVector { union { float v[3]; struct { float x; float y; float z; }; struct { float azimuth; float pitch; float roll; }; }; int8_t status; uint8_t reserved[3]; } ASensorVector; typedef struct AMetaDataEvent { int32_t what; int32_t sensor; } AMetaDataEvent; typedef struct AUncalibratedEvent { union { float uncalib[3]; struct { float x_uncalib; float y_uncalib; float z_uncalib; }; }; union { float bias[3]; struct { float x_bias; float y_bias; float z_bias; }; }; } AUncalibratedEvent; typedef struct AHeartRateEvent { float bpm; int8_t status; } AHeartRateEvent; typedef struct ADynamicSensorEvent { int32_t connected; int32_t handle; } ADynamicSensorEvent; typedef struct { int32_t type; int32_t serial; union { int32_t data_int32[14]; float data_float[14]; }; } AAdditionalInfoEvent; /* NOTE: Must match hardware/sensors.h */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; int32_t type; int32_t reserved0; int64_t timestamp; union { union { float data[16]; ASensorVector vector; ASensorVector acceleration; ASensorVector magnetic; float temperature; float distance; float light; float pressure; float relative_humidity; AUncalibratedEvent uncalibrated_gyro; AUncalibratedEvent uncalibrated_magnetic; AMetaDataEvent meta_data; AHeartRateEvent heart_rate; ADynamicSensorEvent dynamic_sensor_meta; AAdditionalInfoEvent additional_info; }; union { uint64_t data[8]; uint64_t step_counter; } u64; }; uint32_t flags; int32_t reserved1[3]; } ASensorEvent; struct ASensorManager; /** * {@link ASensorManager} is an opaque type to manage sensors and * events queues. * * {@link ASensorManager} is a singleton that can be obtained using * ASensorManager_getInstance(). * * This file provides a set of functions that uses {@link * ASensorManager} to access and list hardware sensors, and * create and destroy event queues: * - ASensorManager_getSensorList() * - ASensorManager_getDefaultSensor() * - ASensorManager_getDefaultSensorEx() * - ASensorManager_createEventQueue() * - ASensorManager_destroyEventQueue() */ typedef struct ASensorManager ASensorManager; struct ASensorEventQueue; /** * {@link ASensorEventQueue} is an opaque type that provides access to * {@link ASensorEvent} from hardware sensors. * * A new {@link ASensorEventQueue} can be obtained using ASensorManager_createEventQueue(). * * This file provides a set of functions to enable and disable * sensors, check and get events, and set event rates on a {@link * ASensorEventQueue}. * - ASensorEventQueue_enableSensor() * - ASensorEventQueue_disableSensor() * - ASensorEventQueue_hasEvents() * - ASensorEventQueue_getEvents() * - ASensorEventQueue_setEventRate() */ typedef struct ASensorEventQueue ASensorEventQueue; struct ASensor; /** * {@link ASensor} is an opaque type that provides information about * an hardware sensors. * * A {@link ASensor} pointer can be obtained using * ASensorManager_getDefaultSensor(), * ASensorManager_getDefaultSensorEx() or from a {@link ASensorList}. * * This file provides a set of functions to access properties of a * {@link ASensor}: * - ASensor_getName() * - ASensor_getVendor() * - ASensor_getType() * - ASensor_getResolution() * - ASensor_getMinDelay() * - ASensor_getFifoMaxEventCount() * - ASensor_getFifoReservedEventCount() * - ASensor_getStringType() * - ASensor_getReportingMode() * - ASensor_isWakeUpSensor() */ typedef struct ASensor ASensor; /** * {@link ASensorRef} is a type for constant pointers to {@link ASensor}. * * This is used to define entry in {@link ASensorList} arrays. */ typedef ASensor const* ASensorRef; /** * {@link ASensorList} is an array of reference to {@link ASensor}. * * A {@link ASensorList} can be initialized using ASensorManager_getSensorList(). */ typedef ASensorRef const* ASensorList; /*****************************************************************************/ /** * Get a reference to the sensor manager. ASensorManager is a singleton * per package as different packages may have access to different sensors. * * Deprecated: Use ASensorManager_getInstanceForPackage(const char*) instead. * * Example: * * ASensorManager* sensorManager = ASensorManager_getInstance(); * */ __attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance(); /* * Get a reference to the sensor manager. ASensorManager is a singleton * per package as different packages may have access to different sensors. * * Example: * * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); * */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName); /** * Returns the list of available sensors. */ int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list); /** * Returns the default sensor for the given type, or NULL if no sensor * of that type exists. */ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type); /** * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor * of this type and wakeUp properties exists. */ ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp); /** * Creates a new sensor event queue and associate it with a looper. * * "ident" is a identifier for the events that will be returned when * calling ALooper_pollOnce(). The identifier must be >= 0, or * ALOOPER_POLL_CALLBACK if providing a non-NULL callback. */ ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, ALooper* looper, int ident, ALooper_callbackFunc callback, void* data); /** * Destroys the event queue and free all resources associated to it. */ int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue); /*****************************************************************************/ /** * Enable the selected sensor with a specified sampling period and max batch report latency. * Returns a negative error code on failure. */ int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor, int32_t samplingPeriodUs, int maxBatchReportLatencyUs); /** * Enable the selected sensor. Returns a negative error code on failure. */ int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** * Disable the selected sensor. Returns a negative error code on failure. */ int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** * Sets the delivery rate of events in microseconds for the given sensor. * Note that this is a hint only, generally event will arrive at a higher * rate. It is an error to set a rate inferior to the value returned by * ASensor_getMinDelay(). * Returns a negative error code on failure. */ int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec); /** * Returns true if there are one or more events available in the * sensor queue. Returns 1 if the queue has events; 0 if * it does not have events; and a negative value if there is an error. */ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); /** * Returns the next available events from the queue. Returns a negative * value if no events are available or an error has occurred, otherwise * the number of events returned. * * Examples: * ASensorEvent event; * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); * * ASensorEvent eventBuffer[8]; * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); * */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); /*****************************************************************************/ /** * Returns this sensor's name (non localized) */ const char* ASensor_getName(ASensor const* sensor); /** * Returns this sensor's vendor's name (non localized) */ const char* ASensor_getVendor(ASensor const* sensor); /** * Return this sensor's type */ int ASensor_getType(ASensor const* sensor); /** * Returns this sensors's resolution */ float ASensor_getResolution(ASensor const* sensor); /** * Returns the minimum delay allowed between events in microseconds. * A value of zero means that this sensor doesn't report events at a * constant rate, but rather only when a new data is available. */ int ASensor_getMinDelay(ASensor const* sensor); /** * Returns the maximum size of batches for this sensor. Batches will often be * smaller, as the hardware fifo might be used for other sensors. */ int ASensor_getFifoMaxEventCount(ASensor const* sensor); /** * Returns the hardware batch fifo size reserved to this sensor. */ int ASensor_getFifoReservedEventCount(ASensor const* sensor); /** * Returns this sensor's string type. */ const char* ASensor_getStringType(ASensor const* sensor); /** * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants. */ int ASensor_getReportingMode(ASensor const* sensor); /** * Returns true if this is a wake up sensor, false otherwise. */ bool ASensor_isWakeUpSensor(ASensor const* sensor); #ifdef __cplusplus }; #endif #endif // ANDROID_SENSOR_H /** @} */ include/android/storage_manager.h0100644 0000000 0000000 00000010576 13077405420 016172 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup Storage * @{ */ /** * @file storage_manager.h */ #ifndef ANDROID_STORAGE_MANAGER_H #define ANDROID_STORAGE_MANAGER_H #include #ifdef __cplusplus extern "C" { #endif struct AStorageManager; /** * {@link AStorageManager} manages application OBB storage, a pointer * can be obtained with AStorageManager_new(). */ typedef struct AStorageManager AStorageManager; /** * The different states of a OBB storage passed to AStorageManager_obbCallbackFunc(). */ enum { /** * The OBB container is now mounted and ready for use. Can be returned * as the status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_MOUNTED = 1, /** * The OBB container is now unmounted and not usable. Can be returned * as the status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_UNMOUNTED = 2, /** * There was an internal system error encountered while trying to * mount the OBB. Can be returned as the status for callbacks made * during asynchronous OBB actions. */ AOBB_STATE_ERROR_INTERNAL = 20, /** * The OBB could not be mounted by the system. Can be returned as the * status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_COULD_NOT_MOUNT = 21, /** * The OBB could not be unmounted. This most likely indicates that a * file is in use on the OBB. Can be returned as the status for * callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_COULD_NOT_UNMOUNT = 22, /** * A call was made to unmount the OBB when it was not mounted. Can be * returned as the status for callbacks made during asynchronous OBB * actions. */ AOBB_STATE_ERROR_NOT_MOUNTED = 23, /** * The OBB has already been mounted. Can be returned as the status for * callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_ALREADY_MOUNTED = 24, /** * The current application does not have permission to use this OBB. * This could be because the OBB indicates it's owned by a different * package. Can be returned as the status for callbacks made during * asynchronous OBB actions. */ AOBB_STATE_ERROR_PERMISSION_DENIED = 25, }; /** * Obtains a new instance of AStorageManager. */ AStorageManager* AStorageManager_new(); /** * Release AStorageManager instance. */ void AStorageManager_delete(AStorageManager* mgr); /** * Callback function for asynchronous calls made on OBB files. * * "state" is one of the following constants: * - {@link AOBB_STATE_MOUNTED} * - {@link AOBB_STATE_UNMOUNTED} * - {@link AOBB_STATE_ERROR_INTERNAL} * - {@link AOBB_STATE_ERROR_COULD_NOT_MOUNT} * - {@link AOBB_STATE_ERROR_COULD_NOT_UNMOUNT} * - {@link AOBB_STATE_ERROR_NOT_MOUNTED} * - {@link AOBB_STATE_ERROR_ALREADY_MOUNTED} * - {@link AOBB_STATE_ERROR_PERMISSION_DENIED} */ typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int32_t state, void* data); /** * Attempts to mount an OBB file. This is an asynchronous operation. */ void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key, AStorageManager_obbCallbackFunc cb, void* data); /** * Attempts to unmount an OBB file. This is an asynchronous operation. */ void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force, AStorageManager_obbCallbackFunc cb, void* data); /** * Check whether an OBB is mounted. */ int AStorageManager_isObbMounted(AStorageManager* mgr, const char* filename); /** * Get the mounted path for an OBB. */ const char* AStorageManager_getMountedObbPath(AStorageManager* mgr, const char* filename); #ifdef __cplusplus }; #endif #endif // ANDROID_STORAGE_MANAGER_H /** @} */ include/android/trace.h0100644 0000000 0000000 00000003507 13077405420 014126 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_NATIVE_TRACE_H #define ANDROID_NATIVE_TRACE_H #include #ifdef __cplusplus extern "C" { #endif /** * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary * when tracing is enabled. */ bool ATrace_isEnabled(); /** * Writes a tracing message to indicate that the given section of code has begun. This call must be * followed by a corresponding call to endSection() on the same thread. * * Note: At this time the vertical bar character '|' and newline character '\n' are used internally * by the tracing mechanism. If sectionName contains these characters they will be replaced with a * space character in the trace. */ void ATrace_beginSection(const char* sectionName); /** * Writes a tracing message to indicate that a given section of code has ended. This call must be * preceeded by a corresponding call to beginSection(char*) on the same thread. Calling this method * will mark the end of the most recently begun section of code, so care must be taken to ensure * that beginSection / endSection pairs are properly nested and called from the same thread. */ void ATrace_endSection(); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_TRACE_H include/android/window.h0100644 0000000 0000000 00000022526 13077405420 014341 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ /** * @addtogroup NativeActivity Native Activity * @{ */ /** * @file window.h */ #ifndef ANDROID_WINDOW_H #define ANDROID_WINDOW_H #ifdef __cplusplus extern "C" { #endif /** * Window flags, as per the Java API at android.view.WindowManager.LayoutParams. */ enum { /** * As long as this window is visible to the user, allow the lock * screen to activate while the screen is on. This can be used * independently, or in combination with {@link * AWINDOW_FLAG_KEEP_SCREEN_ON} and/or {@link * AWINDOW_FLAG_SHOW_WHEN_LOCKED} */ AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, /** Everything behind this window will be dimmed. */ AWINDOW_FLAG_DIM_BEHIND = 0x00000002, /** * Blur everything behind this window. * @deprecated Blurring is no longer supported. */ AWINDOW_FLAG_BLUR_BEHIND = 0x00000004, /** * This window won't ever get key input focus, so the * user can not send key or other button events to it. Those will * instead go to whatever focusable window is behind it. This flag * will also enable {@link AWINDOW_FLAG_NOT_TOUCH_MODAL} whether or not that * is explicitly set. * * Setting this flag also implies that the window will not need to * interact with * a soft input method, so it will be Z-ordered and positioned * independently of any active input method (typically this means it * gets Z-ordered on top of the input method, so it can use the full * screen for its content and cover the input method if needed. You * can use {@link AWINDOW_FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */ AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008, /** this window can never receive touch events. */ AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010, /** * Even when this window is focusable (its * {@link AWINDOW_FLAG_NOT_FOCUSABLE} is not set), allow any pointer events * outside of the window to be sent to the windows behind it. Otherwise * it will consume all pointer events itself, regardless of whether they * are inside of the window. */ AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020, /** * When set, if the device is asleep when the touch * screen is pressed, you will receive this first touch event. Usually * the first touch event is consumed by the system since the user can * not see what they are pressing on. * * @deprecated This flag has no effect. */ AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, /** * As long as this window is visible to the user, keep * the device's screen turned on and bright. */ AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080, /** * Place the window within the entire screen, ignoring * decorations around the border (such as the status bar). The * window must correctly position its contents to take the screen * decoration into account. */ AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100, /** allow window to extend outside of the screen. */ AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200, /** * Hide all screen decorations (such as the status * bar) while this window is displayed. This allows the window to * use the entire display space for itself -- the status bar will * be hidden when an app window with this flag set is on the top * layer. A fullscreen window will ignore a value of {@link * AWINDOW_SOFT_INPUT_ADJUST_RESIZE}; the window will stay * fullscreen and will not resize. */ AWINDOW_FLAG_FULLSCREEN = 0x00000400, /** * Override {@link AWINDOW_FLAG_FULLSCREEN} and force the * screen decorations (such as the status bar) to be shown. */ AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, /** * Turn on dithering when compositing this window to * the screen. * @deprecated This flag is no longer used. */ AWINDOW_FLAG_DITHER = 0x00001000, /** * Treat the content of the window as secure, preventing * it from appearing in screenshots or from being viewed on non-secure * displays. */ AWINDOW_FLAG_SECURE = 0x00002000, /** * A special mode where the layout parameters are used * to perform scaling of the surface when it is composited to the * screen. */ AWINDOW_FLAG_SCALED = 0x00004000, /** * Intended for windows that will often be used when the user is * holding the screen against their face, it will aggressively * filter the event stream to prevent unintended presses in this * situation that may not be desired for a particular window, when * such an event stream is detected, the application will receive * a {@link AMOTION_EVENT_ACTION_CANCEL} to indicate this so * applications can handle this accordingly by taking no action on * the event until the finger is released. */ AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, /** * A special option only for use in combination with * {@link AWINDOW_FLAG_LAYOUT_IN_SCREEN}. When requesting layout in the * screen your window may appear on top of or behind screen decorations * such as the status bar. By also including this flag, the window * manager will report the inset rectangle needed to ensure your * content is not covered by screen decorations. */ AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000, /** * Invert the state of {@link AWINDOW_FLAG_NOT_FOCUSABLE} with * respect to how this window interacts with the current method. * That is, if FLAG_NOT_FOCUSABLE is set and this flag is set, * then the window will behave as if it needs to interact with the * input method and thus be placed behind/away from it; if {@link * AWINDOW_FLAG_NOT_FOCUSABLE} is not set and this flag is set, * then the window will behave as if it doesn't need to interact * with the input method and can be placed to use more space and * cover the input method. */ AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000, /** * If you have set {@link AWINDOW_FLAG_NOT_TOUCH_MODAL}, you * can set this flag to receive a single special MotionEvent with * the action * {@link AMOTION_EVENT_ACTION_OUTSIDE} for * touches that occur outside of your window. Note that you will not * receive the full down/move/up gesture, only the location of the * first down as an {@link AMOTION_EVENT_ACTION_OUTSIDE}. */ AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, /** * Special flag to let windows be shown when the screen * is locked. This will let application windows take precedence over * key guard or any other lock screens. Can be used with * {@link AWINDOW_FLAG_KEEP_SCREEN_ON} to turn screen on and display windows * directly before showing the key guard window. Can be used with * {@link AWINDOW_FLAG_DISMISS_KEYGUARD} to automatically fully dismisss * non-secure keyguards. This flag only applies to the top-most * full-screen window. */ AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000, /** * Ask that the system wallpaper be shown behind * your window. The window surface must be translucent to be able * to actually see the wallpaper behind it; this flag just ensures * that the wallpaper surface will be there if this window actually * has translucent regions. */ AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000, /** * When set as a window is being added or made * visible, once the window has been shown then the system will * poke the power manager's user activity (as if the user had woken * up the device) to turn the screen on. */ AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000, /** * When set the window will cause the keyguard to * be dismissed, only if it is not a secure lock keyguard. Because such * a keyguard is not needed for security, it will never re-appear if * the user navigates to another window (in contrast to * {@link AWINDOW_FLAG_SHOW_WHEN_LOCKED}, which will only temporarily * hide both secure and non-secure keyguards but ensure they reappear * when the user moves to another UI that doesn't hide them). * If the keyguard is currently active and is secure (requires an * unlock pattern) than the user will still need to confirm it before * seeing this window, unless {@link AWINDOW_FLAG_SHOW_WHEN_LOCKED} has * also been set. */ AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000, }; #ifdef __cplusplus }; #endif #endif // ANDROID_WINDOW_H /** @} */ include/batteryservice/0040755 0000000 0000000 00000000000 13077405420 014270 5ustar000000000 0000000 include/batteryservice/BatteryService.h0100644 0000000 0000000 00000006357 13077405420 017404 0ustar000000000 0000000 /* * Copyright (C) 2013 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_BATTERYSERVICE_H #define ANDROID_BATTERYSERVICE_H #include #include #include #include namespace android { // must be kept in sync with definitions in BatteryManager.java enum { BATTERY_STATUS_UNKNOWN = 1, // equals BatteryManager.BATTERY_STATUS_UNKNOWN constant BATTERY_STATUS_CHARGING = 2, // equals BatteryManager.BATTERY_STATUS_CHARGING constant BATTERY_STATUS_DISCHARGING = 3, // equals BatteryManager.BATTERY_STATUS_DISCHARGING constant BATTERY_STATUS_NOT_CHARGING = 4, // equals BatteryManager.BATTERY_STATUS_NOT_CHARGING constant BATTERY_STATUS_FULL = 5, // equals BatteryManager.BATTERY_STATUS_FULL constant }; // must be kept in sync with definitions in BatteryManager.java enum { BATTERY_HEALTH_UNKNOWN = 1, // equals BatteryManager.BATTERY_HEALTH_UNKNOWN constant BATTERY_HEALTH_GOOD = 2, // equals BatteryManager.BATTERY_HEALTH_GOOD constant BATTERY_HEALTH_OVERHEAT = 3, // equals BatteryManager.BATTERY_HEALTH_OVERHEAT constant BATTERY_HEALTH_DEAD = 4, // equals BatteryManager.BATTERY_HEALTH_DEAD constant BATTERY_HEALTH_OVER_VOLTAGE = 5, // equals BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE constant BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6, // equals BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE constant BATTERY_HEALTH_COLD = 7, // equals BatteryManager.BATTERY_HEALTH_COLD constant }; // must be kept in sync with definitions in BatteryProperty.java enum { BATTERY_PROP_CHARGE_COUNTER = 1, // equals BatteryProperty.CHARGE_COUNTER constant BATTERY_PROP_CURRENT_NOW = 2, // equals BatteryProperty.CURRENT_NOW constant BATTERY_PROP_CURRENT_AVG = 3, // equals BatteryProperty.CURRENT_AVG constant BATTERY_PROP_CAPACITY = 4, // equals BatteryProperty.CAPACITY constant BATTERY_PROP_ENERGY_COUNTER = 5, // equals BatteryProperty.ENERGY_COUNTER constant }; struct BatteryProperties { bool chargerAcOnline; bool chargerUsbOnline; bool chargerWirelessOnline; int maxChargingCurrent; int maxChargingVoltage; int batteryStatus; int batteryHealth; bool batteryPresent; int batteryLevel; int batteryVoltage; int batteryTemperature; int batteryCurrent; int batteryCycleCount; int batteryFullCharge; int batteryChargeCounter; String8 batteryTechnology; status_t writeToParcel(Parcel* parcel) const; status_t readFromParcel(Parcel* parcel); }; struct BatteryProperty { int64_t valueInt64; status_t writeToParcel(Parcel* parcel) const; status_t readFromParcel(Parcel* parcel); }; }; // namespace android #endif // ANDROID_BATTERYSERVICE_H include/batteryservice/IBatteryPropertiesListener.h0100644 0000000 0000000 00000002643 13077405420 021751 0ustar000000000 0000000 /* * Copyright (C) 2013 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_IBATTERYPROPERTIESLISTENER_H #define ANDROID_IBATTERYPROPERTIESLISTENER_H #include #include #include namespace android { // must be kept in sync with interface defined in IBatteryPropertiesListener.aidl enum { TRANSACT_BATTERYPROPERTIESCHANGED = IBinder::FIRST_CALL_TRANSACTION, }; // ---------------------------------------------------------------------------- class IBatteryPropertiesListener : public IInterface { public: DECLARE_META_INTERFACE(BatteryPropertiesListener); virtual void batteryPropertiesChanged(struct BatteryProperties props) = 0; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IBATTERYPROPERTIESLISTENER_H include/batteryservice/IBatteryPropertiesRegistrar.h0100644 0000000 0000000 00000003243 13077405420 022123 0ustar000000000 0000000 /* * Copyright (C) 2013 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_IBATTERYPROPERTIESREGISTRAR_H #define ANDROID_IBATTERYPROPERTIESREGISTRAR_H #include #include namespace android { // must be kept in sync with interface defined in IBatteryPropertiesRegistrar.aidl enum { REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION, UNREGISTER_LISTENER, GET_PROPERTY, }; class IBatteryPropertiesRegistrar : public IInterface { public: DECLARE_META_INTERFACE(BatteryPropertiesRegistrar); virtual void registerListener(const sp& listener) = 0; virtual void unregisterListener(const sp& listener) = 0; virtual status_t getProperty(int id, struct BatteryProperty *val) = 0; }; class BnBatteryPropertiesRegistrar : public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; }; // namespace android #endif // ANDROID_IBATTERYPROPERTIESREGISTRAR_H include/binder/0040755 0000000 0000000 00000000000 13077405420 012500 5ustar000000000 0000000 include/binder/AppOpsManager.h0100644 0000000 0000000 00000007241 13077405420 015347 0ustar000000000 0000000 /* * Copyright (C) 2013 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_APP_OPS_MANAGER_H #define ANDROID_APP_OPS_MANAGER_H #include #include // --------------------------------------------------------------------------- namespace android { class AppOpsManager { public: enum { MODE_ALLOWED = IAppOpsService::MODE_ALLOWED, MODE_IGNORED = IAppOpsService::MODE_IGNORED, MODE_ERRORED = IAppOpsService::MODE_ERRORED }; enum { OP_NONE = -1, OP_COARSE_LOCATION = 0, OP_FINE_LOCATION = 1, OP_GPS = 2, OP_VIBRATE = 3, OP_READ_CONTACTS = 4, OP_WRITE_CONTACTS = 5, OP_READ_CALL_LOG = 6, OP_WRITE_CALL_LOG = 7, OP_READ_CALENDAR = 8, OP_WRITE_CALENDAR = 9, OP_WIFI_SCAN = 10, OP_POST_NOTIFICATION = 11, OP_NEIGHBORING_CELLS = 12, OP_CALL_PHONE = 13, OP_READ_SMS = 14, OP_WRITE_SMS = 15, OP_RECEIVE_SMS = 16, OP_RECEIVE_EMERGECY_SMS = 17, OP_RECEIVE_MMS = 18, OP_RECEIVE_WAP_PUSH = 19, OP_SEND_SMS = 20, OP_READ_ICC_SMS = 21, OP_WRITE_ICC_SMS = 22, OP_WRITE_SETTINGS = 23, OP_SYSTEM_ALERT_WINDOW = 24, OP_ACCESS_NOTIFICATIONS = 25, OP_CAMERA = 26, OP_RECORD_AUDIO = 27, OP_PLAY_AUDIO = 28, OP_READ_CLIPBOARD = 29, OP_WRITE_CLIPBOARD = 30, OP_TAKE_MEDIA_BUTTONS = 31, OP_TAKE_AUDIO_FOCUS = 32, OP_AUDIO_MASTER_VOLUME = 33, OP_AUDIO_VOICE_VOLUME = 34, OP_AUDIO_RING_VOLUME = 35, OP_AUDIO_MEDIA_VOLUME = 36, OP_AUDIO_ALARM_VOLUME = 37, OP_AUDIO_NOTIFICATION_VOLUME = 38, OP_AUDIO_BLUETOOTH_VOLUME = 39, OP_WAKE_LOCK = 40, OP_MONITOR_LOCATION = 41, OP_MONITOR_HIGH_POWER_LOCATION = 42, OP_GET_USAGE_STATS = 43, OP_MUTE_MICROPHONE = 44, OP_TOAST_WINDOW = 45, OP_PROJECT_MEDIA = 46, OP_ACTIVATE_VPN = 47, OP_WRITE_WALLPAPER = 48, OP_ASSIST_STRUCTURE = 49, OP_ASSIST_SCREENSHOT = 50, OP_READ_PHONE_STATE = 51, OP_ADD_VOICEMAIL = 52, OP_USE_SIP = 53, OP_PROCESS_OUTGOING_CALLS = 54, OP_USE_FINGERPRINT = 55, OP_BODY_SENSORS = 56 }; AppOpsManager(); int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage); void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); private: Mutex mLock; sp mService; sp getService(); }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_APP_OPS_MANAGER_H include/binder/Binder.h0100644 0000000 0000000 00000007063 13077405420 014057 0ustar000000000 0000000 /* * Copyright (C) 2008 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_BINDER_H #define ANDROID_BINDER_H #include #include #include // --------------------------------------------------------------------------- namespace android { class BBinder : public IBinder { public: BBinder(); virtual const String16& getInterfaceDescriptor() const; virtual bool isBinderAlive() const; virtual status_t pingBinder(); virtual status_t dump(int fd, const Vector& args); virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual status_t linkToDeath(const sp& recipient, void* cookie = NULL, uint32_t flags = 0); virtual status_t unlinkToDeath( const wp& recipient, void* cookie = NULL, uint32_t flags = 0, wp* outRecipient = NULL); virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func); virtual void* findObject(const void* objectID) const; virtual void detachObject(const void* objectID); virtual BBinder* localBinder(); protected: virtual ~BBinder(); virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); private: BBinder(const BBinder& o); BBinder& operator=(const BBinder& o); class Extras; std::atomic mExtras; void* mReserved0; }; // --------------------------------------------------------------------------- class BpRefBase : public virtual RefBase { protected: BpRefBase(const sp& o); virtual ~BpRefBase(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); inline IBinder* remote() { return mRemote; } inline IBinder* remote() const { return mRemote; } private: BpRefBase(const BpRefBase& o); BpRefBase& operator=(const BpRefBase& o); IBinder* const mRemote; RefBase::weakref_type* mRefs; std::atomic mState; }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_BINDER_H include/binder/BinderService.h0100644 0000000 0000000 00000003565 13077405420 015403 0ustar000000000 0000000 /* * Copyright (C) 2010 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_BINDER_SERVICE_H #define ANDROID_BINDER_SERVICE_H #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { template class BinderService { public: static status_t publish(bool allowIsolated = false) { sp sm(defaultServiceManager()); return sm->addService( String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated); } static void publishAndJoinThreadPool(bool allowIsolated = false) { publish(allowIsolated); joinThreadPool(); } static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; } private: static void joinThreadPool() { sp ps(ProcessState::self()); ps->startThreadPool(); ps->giveThreadPoolName(); IPCThreadState::self()->joinThreadPool(); } }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_BINDER_SERVICE_H include/binder/BpBinder.h0100644 0000000 0000000 00000010146 13077405420 014335 0ustar000000000 0000000 /* * Copyright (C) 2005 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_BPBINDER_H #define ANDROID_BPBINDER_H #include #include #include // --------------------------------------------------------------------------- namespace android { class BpBinder : public IBinder { public: BpBinder(int32_t handle); inline int32_t handle() const { return mHandle; } virtual const String16& getInterfaceDescriptor() const; virtual bool isBinderAlive() const; virtual status_t pingBinder(); virtual status_t dump(int fd, const Vector& args); virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual status_t linkToDeath(const sp& recipient, void* cookie = NULL, uint32_t flags = 0); virtual status_t unlinkToDeath( const wp& recipient, void* cookie = NULL, uint32_t flags = 0, wp* outRecipient = NULL); virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func); virtual void* findObject(const void* objectID) const; virtual void detachObject(const void* objectID); virtual BpBinder* remoteBinder(); status_t setConstantData(const void* data, size_t size); void sendObituary(); class ObjectManager { public: ObjectManager(); ~ObjectManager(); void attach( const void* objectID, void* object, void* cleanupCookie, IBinder::object_cleanup_func func); void* find(const void* objectID) const; void detach(const void* objectID); void kill(); private: ObjectManager(const ObjectManager&); ObjectManager& operator=(const ObjectManager&); struct entry_t { void* object; void* cleanupCookie; IBinder::object_cleanup_func func; }; KeyedVector mObjects; }; protected: virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); private: const int32_t mHandle; struct Obituary { wp recipient; void* cookie; uint32_t flags; }; void reportOneDeath(const Obituary& obit); bool isDescriptorCached() const; mutable Mutex mLock; volatile int32_t mAlive; volatile int32_t mObitsSent; Vector* mObituaries; ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_BPBINDER_H include/binder/BufferedTextOutput.h0100644 0000000 0000000 00000003632 13077405420 016462 0ustar000000000 0000000 /* * Copyright (C) 2006 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_BUFFEREDTEXTOUTPUT_H #define ANDROID_BUFFEREDTEXTOUTPUT_H #include #include #include // --------------------------------------------------------------------------- namespace android { class BufferedTextOutput : public TextOutput { public: //** Flags for constructor */ enum { MULTITHREADED = 0x0001 }; BufferedTextOutput(uint32_t flags = 0); virtual ~BufferedTextOutput(); virtual status_t print(const char* txt, size_t len); virtual void moveIndent(int delta); virtual void pushBundle(); virtual void popBundle(); protected: virtual status_t writeLines(const struct iovec& vec, size_t N) = 0; private: struct BufferState; struct ThreadState; static ThreadState*getThreadState(); static void threadDestructor(void *st); BufferState*getBuffer() const; uint32_t mFlags; const int32_t mSeq; const int32_t mIndex; Mutex mLock; BufferState* mGlobalState; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_BUFFEREDTEXTOUTPUT_H include/binder/Debug.h0100644 0000000 0000000 00000002665 13077405420 013705 0ustar000000000 0000000 /* * Copyright (C) 2005 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_BINDER_DEBUG_H #define ANDROID_BINDER_DEBUG_H #include #include namespace android { // --------------------------------------------------------------------------- #ifdef __cplusplus extern "C" { #endif const char* stringForIndent(int32_t indentLevel); typedef void (*debugPrintFunc)(void* cookie, const char* txt); void printTypeCode(uint32_t typeCode, debugPrintFunc func = 0, void* cookie = 0); void printHexData(int32_t indent, const void *buf, size_t length, size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16, size_t alignment=0, bool cArrayStyle=false, debugPrintFunc func = 0, void* cookie = 0); #ifdef __cplusplus } #endif // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_BINDER_DEBUG_H include/binder/IAppOpsCallback.h0100644 0000000 0000000 00000003063 13077405420 015600 0ustar000000000 0000000 /* * Copyright (C) 2013 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_IAPP_OPS_CALLBACK_H #define ANDROID_IAPP_OPS_CALLBACK_H #include namespace android { // ---------------------------------------------------------------------- class IAppOpsCallback : public IInterface { public: DECLARE_META_INTERFACE(AppOpsCallback); virtual void opChanged(int32_t op, const String16& packageName) = 0; enum { OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION }; }; // ---------------------------------------------------------------------- class BnAppOpsCallback : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IAPP_OPS_CALLBACK_H include/binder/IAppOpsService.h0100644 0000000 0000000 00000005627 13077405420 015514 0ustar000000000 0000000 /* * Copyright (C) 2013 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_IAPP_OPS_SERVICE_H #define ANDROID_IAPP_OPS_SERVICE_H #include #include namespace android { // ---------------------------------------------------------------------- class IAppOpsService : public IInterface { public: DECLARE_META_INTERFACE(AppOpsService); virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, const String16& packageName) = 0; virtual void finishOperation(const sp& token, int32_t code, int32_t uid, const String16& packageName) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp& callback) = 0; virtual void stopWatchingMode(const sp& callback) = 0; virtual sp getToken(const sp& clientToken) = 0; virtual int32_t permissionToOpCode(const String16& permission) = 0; enum { CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3, START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4, STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5, GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, }; enum { MODE_ALLOWED = 0, MODE_IGNORED = 1, MODE_ERRORED = 2 }; }; // ---------------------------------------------------------------------- class BnAppOpsService : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IAPP_OPS_SERVICE_H include/binder/IBatteryStats.h0100644 0000000 0000000 00000005134 13077405420 015413 0ustar000000000 0000000 /* * Copyright (C) 2013 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_IBATTERYSTATS_H #define ANDROID_IBATTERYSTATS_H #include namespace android { // ---------------------------------------------------------------------- class IBatteryStats : public IInterface { public: DECLARE_META_INTERFACE(BatteryStats); virtual void noteStartSensor(int uid, int sensor) = 0; virtual void noteStopSensor(int uid, int sensor) = 0; virtual void noteStartVideo(int uid) = 0; virtual void noteStopVideo(int uid) = 0; virtual void noteStartAudio(int uid) = 0; virtual void noteStopAudio(int uid) = 0; virtual void noteResetVideo() = 0; virtual void noteResetAudio() = 0; virtual void noteFlashlightOn(int uid) = 0; virtual void noteFlashlightOff(int uid) = 0; virtual void noteStartCamera(int uid) = 0; virtual void noteStopCamera(int uid) = 0; virtual void noteResetCamera() = 0; virtual void noteResetFlashlight() = 0; enum { NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_STOP_SENSOR_TRANSACTION, NOTE_START_VIDEO_TRANSACTION, NOTE_STOP_VIDEO_TRANSACTION, NOTE_START_AUDIO_TRANSACTION, NOTE_STOP_AUDIO_TRANSACTION, NOTE_RESET_VIDEO_TRANSACTION, NOTE_RESET_AUDIO_TRANSACTION, NOTE_FLASHLIGHT_ON_TRANSACTION, NOTE_FLASHLIGHT_OFF_TRANSACTION, NOTE_START_CAMERA_TRANSACTION, NOTE_STOP_CAMERA_TRANSACTION, NOTE_RESET_CAMERA_TRANSACTION, NOTE_RESET_FLASHLIGHT_TRANSACTION }; }; // ---------------------------------------------------------------------- class BnBatteryStats : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IBATTERYSTATS_H include/binder/IBinder.h0100644 0000000 0000000 00000014133 13077405420 014164 0ustar000000000 0000000 /* * Copyright (C) 2008 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_IBINDER_H #define ANDROID_IBINDER_H #include #include #include #include // linux/binder.h already defines this, but we can't just include it from there // because there are host builds that include this file. #ifndef B_PACK_CHARS #define B_PACK_CHARS(c1, c2, c3, c4) \ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) #endif // B_PACK_CHARS // --------------------------------------------------------------------------- namespace android { class BBinder; class BpBinder; class IInterface; class Parcel; class IResultReceiver; /** * Base class and low-level protocol for a remotable object. * You can derive from this class to create an object for which other * processes can hold references to it. Communication between processes * (method calls, property get and set) is down through a low-level * protocol implemented on top of the transact() API. */ class IBinder : public virtual RefBase { public: enum { FIRST_CALL_TRANSACTION = 0x00000001, LAST_CALL_TRANSACTION = 0x00ffffff, PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'), SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'), INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'), SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'), // Corresponds to TF_ONE_WAY -- an asynchronous call. FLAG_ONEWAY = 0x00000001 }; IBinder(); /** * Check if this IBinder implements the interface named by * @a descriptor. If it does, the base pointer to it is returned, * which you can safely static_cast<> to the concrete C++ interface. */ virtual sp queryLocalInterface(const String16& descriptor); /** * Return the canonical name of the interface provided by this IBinder * object. */ virtual const String16& getInterfaceDescriptor() const = 0; virtual bool isBinderAlive() const = 0; virtual status_t pingBinder() = 0; virtual status_t dump(int fd, const Vector& args) = 0; static status_t shellCommand(const sp& target, int in, int out, int err, Vector& args, const sp& resultReceiver); virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) = 0; class DeathRecipient : public virtual RefBase { public: virtual void binderDied(const wp& who) = 0; }; /** * Register the @a recipient for a notification if this binder * goes away. If this binder object unexpectedly goes away * (typically because its hosting process has been killed), * then DeathRecipient::binderDied() will be called with a reference * to this. * * The @a cookie is optional -- if non-NULL, it should be a * memory address that you own (that is, you know it is unique). * * @note You will only receive death notifications for remote binders, * as local binders by definition can't die without you dying as well. * Trying to use this function on a local binder will result in an * INVALID_OPERATION code being returned and nothing happening. * * @note This link always holds a weak reference to its recipient. * * @note You will only receive a weak reference to the dead * binder. You should not try to promote this to a strong reference. * (Nor should you need to, as there is nothing useful you can * directly do with it now that it has passed on.) */ virtual status_t linkToDeath(const sp& recipient, void* cookie = NULL, uint32_t flags = 0) = 0; /** * Remove a previously registered death notification. * The @a recipient will no longer be called if this object * dies. The @a cookie is optional. If non-NULL, you can * supply a NULL @a recipient, and the recipient previously * added with that cookie will be unlinked. */ virtual status_t unlinkToDeath( const wp& recipient, void* cookie = NULL, uint32_t flags = 0, wp* outRecipient = NULL) = 0; virtual bool checkSubclass(const void* subclassID) const; typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie); virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) = 0; virtual void* findObject(const void* objectID) const = 0; virtual void detachObject(const void* objectID) = 0; virtual BBinder* localBinder(); virtual BpBinder* remoteBinder(); protected: virtual ~IBinder(); private: }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_IBINDER_H include/binder/IInterface.h0100644 0000000 0000000 00000012342 13077405420 014661 0ustar000000000 0000000 /* * Copyright (C) 2005 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_IINTERFACE_H #define ANDROID_IINTERFACE_H #include namespace android { // ---------------------------------------------------------------------- class IInterface : public virtual RefBase { public: IInterface(); static sp asBinder(const IInterface*); static sp asBinder(const sp&); protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0; }; // ---------------------------------------------------------------------- template inline sp interface_cast(const sp& obj) { return INTERFACE::asInterface(obj); } // ---------------------------------------------------------------------- template class BnInterface : public INTERFACE, public BBinder { public: virtual sp queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); }; // ---------------------------------------------------------------------- template class BpInterface : public INTERFACE, public BpRefBase { public: BpInterface(const sp& remote); protected: virtual IBinder* onAsBinder(); }; // ---------------------------------------------------------------------- #define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; \ static android::sp asInterface( \ const android::sp& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE(); \ #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp I##INTERFACE::asInterface( \ const android::sp& obj) \ { \ android::sp intr; \ if (obj != NULL) { \ intr = static_cast( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \ #define CHECK_INTERFACE(interface, data, reply) \ if (!data.checkInterface(this)) { return PERMISSION_DENIED; } \ // ---------------------------------------------------------------------- // No user-serviceable parts after this... template inline sp BnInterface::queryLocalInterface( const String16& _descriptor) { if (_descriptor == INTERFACE::descriptor) return this; return NULL; } template inline const String16& BnInterface::getInterfaceDescriptor() const { return INTERFACE::getInterfaceDescriptor(); } template IBinder* BnInterface::onAsBinder() { return this; } template inline BpInterface::BpInterface(const sp& remote) : BpRefBase(remote) { } template inline IBinder* BpInterface::onAsBinder() { return remote(); } // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IINTERFACE_H include/binder/IMediaResourceMonitor.h0100644 0000000 0000000 00000003242 13077405420 017057 0ustar000000000 0000000 /* * Copyright 2016 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_I_MEDIA_RESOURCE_MONITOR_H #define ANDROID_I_MEDIA_RESOURCE_MONITOR_H #include namespace android { // ---------------------------------------------------------------------- class IMediaResourceMonitor : public IInterface { public: DECLARE_META_INTERFACE(MediaResourceMonitor); // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX. enum { TYPE_VIDEO_CODEC = 0, TYPE_AUDIO_CODEC = 1, }; virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0; enum { NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION, }; }; // ---------------------------------------------------------------------- class BnMediaResourceMonitor : public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H include/binder/IMemory.h0100644 0000000 0000000 00000005135 13077405420 014233 0ustar000000000 0000000 /* * Copyright (C) 2007 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_IMEMORY_H #define ANDROID_IMEMORY_H #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class IMemoryHeap : public IInterface { public: DECLARE_META_INTERFACE(MemoryHeap); // flags returned by getFlags() enum { READ_ONLY = 0x00000001 }; virtual int getHeapID() const = 0; virtual void* getBase() const = 0; virtual size_t getSize() const = 0; virtual uint32_t getFlags() const = 0; virtual uint32_t getOffset() const = 0; // these are there just for backward source compatibility int32_t heapID() const { return getHeapID(); } void* base() const { return getBase(); } size_t virtualSize() const { return getSize(); } }; class BnMemoryHeap : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); BnMemoryHeap(); protected: virtual ~BnMemoryHeap(); }; // ---------------------------------------------------------------------------- class IMemory : public IInterface { public: DECLARE_META_INTERFACE(Memory); virtual sp getMemory(ssize_t* offset=0, size_t* size=0) const = 0; // helpers void* fastPointer(const sp& heap, ssize_t offset) const; void* pointer() const; size_t size() const; ssize_t offset() const; }; class BnMemory : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); BnMemory(); protected: virtual ~BnMemory(); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IMEMORY_H include/binder/IPCThreadState.h0100644 0000000 0000000 00000013242 13077405420 015414 0ustar000000000 0000000 /* * Copyright (C) 2005 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_IPC_THREAD_STATE_H #define ANDROID_IPC_THREAD_STATE_H #include #include #include #include #if defined(_WIN32) typedef int uid_t; #endif // --------------------------------------------------------------------------- namespace android { class IPCThreadState { public: static IPCThreadState* self(); static IPCThreadState* selfOrNull(); // self(), but won't instantiate sp process(); status_t clearLastError(); pid_t getCallingPid() const; uid_t getCallingUid() const; void setStrictModePolicy(int32_t policy); int32_t getStrictModePolicy() const; void setLastTransactionBinderFlags(int32_t flags); int32_t getLastTransactionBinderFlags() const; int64_t clearCallingIdentity(); void restoreCallingIdentity(int64_t token); int setupPolling(int* fd); status_t handlePolledCommands(); void flushCommands(); void joinThreadPool(bool isMain = true); // Stop the local process. void stopProcess(bool immediate = true); status_t transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); void incStrongHandle(int32_t handle); void decStrongHandle(int32_t handle); void incWeakHandle(int32_t handle); void decWeakHandle(int32_t handle); status_t attemptIncStrongHandle(int32_t handle); static void expungeHandle(int32_t handle, IBinder* binder); status_t requestDeathNotification( int32_t handle, BpBinder* proxy); status_t clearDeathNotification( int32_t handle, BpBinder* proxy); static void shutdown(); // Call this to disable switching threads to background scheduling when // receiving incoming IPC calls. This is specifically here for the // Android system process, since it expects to have background apps calling // in to it but doesn't want to acquire locks in its services while in // the background. static void disableBackgroundScheduling(bool disable); // Call blocks until the number of executing binder threads is less than // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); private: IPCThreadState(); ~IPCThreadState(); status_t sendReply(const Parcel& reply, uint32_t flags); status_t waitForResponse(Parcel *reply, status_t *acquireResult=NULL); status_t talkWithDriver(bool doReceive=true); status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer); status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); void clearCaller(); static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsSize, void* cookie); const sp mProcess; const pid_t mMyThreadId; Vector mPendingStrongDerefs; Vector mPendingWeakDerefs; Parcel mIn; Parcel mOut; status_t mLastError; pid_t mCallingPid; uid_t mCallingUid; int32_t mStrictModePolicy; int32_t mLastTransactionBinderFlags; }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_IPC_THREAD_STATE_H include/binder/IPermissionController.h0100644 0000000 0000000 00000003705 13077405420 017160 0ustar000000000 0000000 /* * Copyright (C) 2005 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_IPERMISSION_CONTROLLER_H #define ANDROID_IPERMISSION_CONTROLLER_H #include #include namespace android { // ---------------------------------------------------------------------- class IPermissionController : public IInterface { public: DECLARE_META_INTERFACE(PermissionController); virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0; virtual void getPackagesForUid(const uid_t uid, Vector &packages) = 0; virtual bool isRuntimePermission(const String16& permission) = 0; enum { CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2 }; }; // ---------------------------------------------------------------------- class BnPermissionController : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IPERMISSION_CONTROLLER_H include/binder/IProcessInfoService.h0100644 0000000 0000000 00000003322 13077405420 016532 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_I_PROCESS_INFO_SERVICE_H #define ANDROID_I_PROCESS_INFO_SERVICE_H #include namespace android { // ---------------------------------------------------------------------- class IProcessInfoService : public IInterface { public: DECLARE_META_INTERFACE(ProcessInfoService); virtual status_t getProcessStatesFromPids( size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states) = 0; virtual status_t getProcessStatesAndOomScoresFromPids( size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states, /*out*/ int32_t* scores) = 0; enum { GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION, GET_PROCESS_STATES_AND_OOM_SCORES_FROM_PIDS, }; }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_I_PROCESS_INFO_SERVICE_H include/binder/IResultReceiver.h0100644 0000000 0000000 00000003007 13077405420 015722 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #ifndef ANDROID_IRESULT_RECEIVER_H #define ANDROID_IRESULT_RECEIVER_H #include namespace android { // ---------------------------------------------------------------------- class IResultReceiver : public IInterface { public: DECLARE_META_INTERFACE(ResultReceiver); virtual void send(int32_t resultCode) = 0; enum { OP_SEND = IBinder::FIRST_CALL_TRANSACTION }; }; // ---------------------------------------------------------------------- class BnResultReceiver : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IRESULT_RECEIVER_H include/binder/IServiceManager.h0100644 0000000 0000000 00000005071 13077405420 015655 0ustar000000000 0000000 /* * Copyright (C) 2005 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_ISERVICE_MANAGER_H #define ANDROID_ISERVICE_MANAGER_H #include #include #include #include namespace android { // ---------------------------------------------------------------------- class IServiceManager : public IInterface { public: DECLARE_META_INTERFACE(ServiceManager); /** * Retrieve an existing service, blocking for a few seconds * if it doesn't yet exist. */ virtual sp getService( const String16& name) const = 0; /** * Retrieve an existing service, non-blocking. */ virtual sp checkService( const String16& name) const = 0; /** * Register a service. */ virtual status_t addService( const String16& name, const sp& service, bool allowIsolated = false) = 0; /** * Return list of all existing services. */ virtual Vector listServices() = 0; enum { GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, CHECK_SERVICE_TRANSACTION, ADD_SERVICE_TRANSACTION, LIST_SERVICES_TRANSACTION, }; }; sp defaultServiceManager(); template status_t getService(const String16& name, sp* outService) { const sp sm = defaultServiceManager(); if (sm != NULL) { *outService = interface_cast(sm->getService(name)); if ((*outService) != NULL) return NO_ERROR; } return NAME_NOT_FOUND; } bool checkCallingPermission(const String16& permission); bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid); bool checkPermission(const String16& permission, pid_t pid, uid_t uid); }; // namespace android #endif // ANDROID_ISERVICE_MANAGER_H include/binder/MemoryBase.h0100644 0000000 0000000 00000002706 13077405420 014716 0ustar000000000 0000000 /* * Copyright (C) 2008 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_MEMORY_BASE_H #define ANDROID_MEMORY_BASE_H #include #include #include namespace android { // --------------------------------------------------------------------------- class MemoryBase : public BnMemory { public: MemoryBase(const sp& heap, ssize_t offset, size_t size); virtual ~MemoryBase(); virtual sp getMemory(ssize_t* offset, size_t* size) const; protected: size_t getSize() const { return mSize; } ssize_t getOffset() const { return mOffset; } const sp& getHeap() const { return mHeap; } private: size_t mSize; ssize_t mOffset; sp mHeap; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_MEMORY_BASE_H include/binder/MemoryDealer.h0100644 0000000 0000000 00000003604 13077405420 015236 0ustar000000000 0000000 /* * Copyright (C) 2007 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_MEMORY_DEALER_H #define ANDROID_MEMORY_DEALER_H #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class SimpleBestFitAllocator; // ---------------------------------------------------------------------------- class MemoryDealer : public RefBase { public: MemoryDealer(size_t size, const char* name = 0, uint32_t flags = 0 /* or bits such as MemoryHeapBase::READ_ONLY */ ); virtual sp allocate(size_t size); virtual void deallocate(size_t offset); virtual void dump(const char* what) const; // allocations are aligned to some value. return that value so clients can account for it. static size_t getAllocationAlignment(); sp getMemoryHeap() const { return heap(); } protected: virtual ~MemoryDealer(); private: const sp& heap() const; SimpleBestFitAllocator* allocator() const; sp mHeap; SimpleBestFitAllocator* mAllocator; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_MEMORY_DEALER_H include/binder/MemoryHeapBase.h0100644 0000000 0000000 00000005631 13077405420 015514 0ustar000000000 0000000 /* * Copyright (C) 2008 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_MEMORY_HEAP_BASE_H #define ANDROID_MEMORY_HEAP_BASE_H #include #include #include namespace android { // --------------------------------------------------------------------------- class MemoryHeapBase : public virtual BnMemoryHeap { public: enum { READ_ONLY = IMemoryHeap::READ_ONLY, // memory won't be mapped locally, but will be mapped in the remote // process. DONT_MAP_LOCALLY = 0x00000100, NO_CACHING = 0x00000200 }; /* * maps the memory referenced by fd. but DOESN'T take ownership * of the filedescriptor (it makes a copy with dup() */ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0); /* * maps memory from the given device */ MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0); /* * maps memory from ashmem, with the given name for debugging */ MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL); virtual ~MemoryHeapBase(); /* implement IMemoryHeap interface */ virtual int getHeapID() const; /* virtual address of the heap. returns MAP_FAILED in case of error */ virtual void* getBase() const; virtual size_t getSize() const; virtual uint32_t getFlags() const; virtual uint32_t getOffset() const; const char* getDevice() const; /* this closes this heap -- use carefully */ void dispose(); /* this is only needed as a workaround, use only if you know * what you are doing */ status_t setDevice(const char* device) { if (mDevice == 0) mDevice = device; return mDevice ? NO_ERROR : ALREADY_EXISTS; } protected: MemoryHeapBase(); // init() takes ownership of fd status_t init(int fd, void *base, int size, int flags = 0, const char* device = NULL); private: status_t mapfd(int fd, size_t size, uint32_t offset = 0); int mFD; size_t mSize; void* mBase; uint32_t mFlags; const char* mDevice; bool mNeedUnmap; uint32_t mOffset; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_MEMORY_HEAP_BASE_H include/binder/Parcel.h0100644 0000000 0000000 00000072736 13077405420 014073 0ustar000000000 0000000 /* * Copyright (C) 2005 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_PARCEL_H #define ANDROID_PARCEL_H #include #include #include #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { template class Flattenable; template class LightFlattenable; class IBinder; class IPCThreadState; class ProcessState; class String8; class TextOutput; class Parcel { friend class IPCThreadState; public: class ReadableBlob; class WritableBlob; Parcel(); ~Parcel(); const uint8_t* data() const; size_t dataSize() const; size_t dataAvail() const; size_t dataPosition() const; size_t dataCapacity() const; status_t setDataSize(size_t size); void setDataPosition(size_t pos) const; status_t setDataCapacity(size_t size); status_t setData(const uint8_t* buffer, size_t len); status_t appendFrom(const Parcel *parcel, size_t start, size_t len); bool allowFds() const; bool pushAllowFds(bool allowFds); void restoreAllowFds(bool lastValue); bool hasFileDescriptors() const; // Writes the RPC header. status_t writeInterfaceToken(const String16& interface); // Parses the RPC header, returning true if the interface name // in the header matches the expected interface from the caller. // // Additionally, enforceInterface does part of the work of // propagating the StrictMode policy mask, populating the current // IPCThreadState, which as an optimization may optionally be // passed in. bool enforceInterface(const String16& interface, IPCThreadState* threadState = NULL) const; bool checkInterface(IBinder*) const; void freeData(); private: const binder_size_t* objects() const; public: size_t objectsCount() const; status_t errorCheck() const; void setError(status_t err); status_t write(const void* data, size_t len); void* writeInplace(size_t len); status_t writeUnpadded(const void* data, size_t len); status_t writeInt32(int32_t val); status_t writeUint32(uint32_t val); status_t writeInt64(int64_t val); status_t writeUint64(uint64_t val); status_t writeFloat(float val); status_t writeDouble(double val); status_t writeCString(const char* str); status_t writeString8(const String8& str); status_t writeString16(const String16& str); status_t writeString16(const std::unique_ptr& str); status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp& val); status_t writeWeakBinder(const wp& val); status_t writeInt32Array(size_t len, const int32_t *val); status_t writeByteArray(size_t len, const uint8_t *val); status_t writeBool(bool val); status_t writeChar(char16_t val); status_t writeByte(int8_t val); // Take a UTF8 encoded string, convert to UTF16, write it to the parcel. status_t writeUtf8AsUtf16(const std::string& str); status_t writeUtf8AsUtf16(const std::unique_ptr& str); status_t writeByteVector(const std::unique_ptr>& val); status_t writeByteVector(const std::vector& val); status_t writeByteVector(const std::unique_ptr>& val); status_t writeByteVector(const std::vector& val); status_t writeInt32Vector(const std::unique_ptr>& val); status_t writeInt32Vector(const std::vector& val); status_t writeInt64Vector(const std::unique_ptr>& val); status_t writeInt64Vector(const std::vector& val); status_t writeFloatVector(const std::unique_ptr>& val); status_t writeFloatVector(const std::vector& val); status_t writeDoubleVector(const std::unique_ptr>& val); status_t writeDoubleVector(const std::vector& val); status_t writeBoolVector(const std::unique_ptr>& val); status_t writeBoolVector(const std::vector& val); status_t writeCharVector(const std::unique_ptr>& val); status_t writeCharVector(const std::vector& val); status_t writeString16Vector( const std::unique_ptr>>& val); status_t writeString16Vector(const std::vector& val); status_t writeUtf8VectorAsUtf16Vector( const std::unique_ptr>>& val); status_t writeUtf8VectorAsUtf16Vector(const std::vector& val); status_t writeStrongBinderVector(const std::unique_ptr>>& val); status_t writeStrongBinderVector(const std::vector>& val); template status_t writeParcelableVector(const std::unique_ptr>>& val); template status_t writeParcelableVector(const std::vector& val); template status_t writeNullableParcelable(const std::unique_ptr& parcelable); status_t writeParcelable(const Parcelable& parcelable); template status_t write(const Flattenable& val); template status_t write(const LightFlattenable& val); // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). // Doesn't take ownership of the native_handle. status_t writeNativeHandle(const native_handle* handle); // Place a file descriptor into the parcel. The given fd must remain // valid for the lifetime of the parcel. // The Parcel does not take ownership of the given fd unless you ask it to. status_t writeFileDescriptor(int fd, bool takeOwnership = false); // Place a file descriptor into the parcel. A dup of the fd is made, which // will be closed once the parcel is destroyed. status_t writeDupFileDescriptor(int fd); // Place a file descriptor into the parcel. This will not affect the // semantics of the smart file descriptor. A new descriptor will be // created, and will be closed when the parcel is destroyed. status_t writeUniqueFileDescriptor( const ScopedFd& fd); // Place a vector of file desciptors into the parcel. Each descriptor is // dup'd as in writeDupFileDescriptor status_t writeUniqueFileDescriptorVector( const std::unique_ptr>& val); status_t writeUniqueFileDescriptorVector( const std::vector& val); // Writes a blob to the parcel. // If the blob is small, then it is stored in-place, otherwise it is // transferred by way of an anonymous shared memory region. Prefer sending // immutable blobs if possible since they may be subsequently transferred between // processes without further copying whereas mutable blobs always need to be copied. // The caller should call release() on the blob after writing its contents. status_t writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob); // Write an existing immutable blob file descriptor to the parcel. // This allows the client to send the same blob to multiple processes // as long as it keeps a dup of the blob file descriptor handy for later. status_t writeDupImmutableBlobFileDescriptor(int fd); status_t writeObject(const flat_binder_object& val, bool nullMetaData); // Like Parcel.java's writeNoException(). Just writes a zero int32. // Currently the native implementation doesn't do any of the StrictMode // stack gathering and serialization that the Java implementation does. status_t writeNoException(); void remove(size_t start, size_t amt); status_t read(void* outData, size_t len) const; const void* readInplace(size_t len) const; int32_t readInt32() const; status_t readInt32(int32_t *pArg) const; uint32_t readUint32() const; status_t readUint32(uint32_t *pArg) const; int64_t readInt64() const; status_t readInt64(int64_t *pArg) const; uint64_t readUint64() const; status_t readUint64(uint64_t *pArg) const; float readFloat() const; status_t readFloat(float *pArg) const; double readDouble() const; status_t readDouble(double *pArg) const; intptr_t readIntPtr() const; status_t readIntPtr(intptr_t *pArg) const; bool readBool() const; status_t readBool(bool *pArg) const; char16_t readChar() const; status_t readChar(char16_t *pArg) const; int8_t readByte() const; status_t readByte(int8_t *pArg) const; // Read a UTF16 encoded string, convert to UTF8 status_t readUtf8FromUtf16(std::string* str) const; status_t readUtf8FromUtf16(std::unique_ptr* str) const; const char* readCString() const; String8 readString8() const; String16 readString16() const; status_t readString16(String16* pArg) const; status_t readString16(std::unique_ptr* pArg) const; const char16_t* readString16Inplace(size_t* outLen) const; sp readStrongBinder() const; status_t readStrongBinder(sp* val) const; wp readWeakBinder() const; template status_t readParcelableVector( std::unique_ptr>>* val) const; template status_t readParcelableVector(std::vector* val) const; status_t readParcelable(Parcelable* parcelable) const; template status_t readParcelable(std::unique_ptr* parcelable) const; template status_t readStrongBinder(sp* val) const; status_t readStrongBinderVector(std::unique_ptr>>* val) const; status_t readStrongBinderVector(std::vector>* val) const; status_t readByteVector(std::unique_ptr>* val) const; status_t readByteVector(std::vector* val) const; status_t readByteVector(std::unique_ptr>* val) const; status_t readByteVector(std::vector* val) const; status_t readInt32Vector(std::unique_ptr>* val) const; status_t readInt32Vector(std::vector* val) const; status_t readInt64Vector(std::unique_ptr>* val) const; status_t readInt64Vector(std::vector* val) const; status_t readFloatVector(std::unique_ptr>* val) const; status_t readFloatVector(std::vector* val) const; status_t readDoubleVector(std::unique_ptr>* val) const; status_t readDoubleVector(std::vector* val) const; status_t readBoolVector(std::unique_ptr>* val) const; status_t readBoolVector(std::vector* val) const; status_t readCharVector(std::unique_ptr>* val) const; status_t readCharVector(std::vector* val) const; status_t readString16Vector( std::unique_ptr>>* val) const; status_t readString16Vector(std::vector* val) const; status_t readUtf8VectorFromUtf16Vector( std::unique_ptr>>* val) const; status_t readUtf8VectorFromUtf16Vector(std::vector* val) const; template status_t read(Flattenable& val) const; template status_t read(LightFlattenable& val) const; // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error // code on exceptions, but also deals with skipping over rich // response headers. Callers should use this to read & parse the // response headers rather than doing it by hand. int32_t readExceptionCode() const; // Retrieve native_handle from the parcel. This returns a copy of the // parcel's native_handle (the caller takes ownership). The caller // must free the native_handle with native_handle_close() and // native_handle_delete(). native_handle* readNativeHandle() const; // Retrieve a file descriptor from the parcel. This returns the raw fd // in the parcel, which you do not own -- use dup() to get your own copy. int readFileDescriptor() const; // Retrieve a smart file descriptor from the parcel. status_t readUniqueFileDescriptor( ScopedFd* val) const; // Retrieve a vector of smart file descriptors from the parcel. status_t readUniqueFileDescriptorVector( std::unique_ptr>* val) const; status_t readUniqueFileDescriptorVector( std::vector* val) const; // Reads a blob from the parcel. // The caller should call release() on the blob after reading its contents. status_t readBlob(size_t len, ReadableBlob* outBlob) const; const flat_binder_object* readObject(bool nullMetaData) const; // Explicitly close all file descriptors in the parcel. void closeFileDescriptors(); // Debugging: get metrics on current allocations. static size_t getGlobalAllocSize(); static size_t getGlobalAllocCount(); private: typedef void (*release_func)(Parcel* parcel, const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsSize, void* cookie); uintptr_t ipcData() const; size_t ipcDataSize() const; uintptr_t ipcObjects() const; size_t ipcObjectsCount() const; void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie); public: void print(TextOutput& to, uint32_t flags = 0) const; private: Parcel(const Parcel& o); Parcel& operator=(const Parcel& o); status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); status_t growData(size_t len); status_t restartWrite(size_t desired); status_t continueWrite(size_t desired); status_t writePointer(uintptr_t val); status_t readPointer(uintptr_t *pArg) const; uintptr_t readPointer() const; void freeDataNoInit(); void initState(); void scanForFds() const; template status_t readAligned(T *pArg) const; template T readAligned() const; template status_t writeAligned(T val); status_t writeRawNullableParcelable(const Parcelable* parcelable); template status_t unsafeReadTypedVector(std::vector* val, status_t(Parcel::*read_func)(U*) const) const; template status_t readNullableTypedVector(std::unique_ptr>* val, status_t(Parcel::*read_func)(T*) const) const; template status_t readTypedVector(std::vector* val, status_t(Parcel::*read_func)(T*) const) const; template status_t unsafeWriteTypedVector(const std::vector& val, status_t(Parcel::*write_func)(U)); template status_t writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(const T&)); template status_t writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(T)); template status_t writeTypedVector(const std::vector& val, status_t(Parcel::*write_func)(const T&)); template status_t writeTypedVector(const std::vector& val, status_t(Parcel::*write_func)(T)); status_t mError; uint8_t* mData; size_t mDataSize; size_t mDataCapacity; mutable size_t mDataPos; binder_size_t* mObjects; size_t mObjectsSize; size_t mObjectsCapacity; mutable size_t mNextObjectHint; mutable bool mFdsKnown; mutable bool mHasFds; bool mAllowFds; release_func mOwner; void* mOwnerCookie; class Blob { public: Blob(); ~Blob(); void clear(); void release(); inline size_t size() const { return mSize; } inline int fd() const { return mFd; }; inline bool isMutable() const { return mMutable; } protected: void init(int fd, void* data, size_t size, bool isMutable); int mFd; // owned by parcel so not closed when released void* mData; size_t mSize; bool mMutable; }; class FlattenableHelperInterface { protected: ~FlattenableHelperInterface() { } public: virtual size_t getFlattenedSize() const = 0; virtual size_t getFdCount() const = 0; virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const = 0; virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) = 0; }; template class FlattenableHelper : public FlattenableHelperInterface { friend class Parcel; const Flattenable& val; explicit FlattenableHelper(const Flattenable& val) : val(val) { } public: virtual size_t getFlattenedSize() const { return val.getFlattenedSize(); } virtual size_t getFdCount() const { return val.getFdCount(); } virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const { return val.flatten(buffer, size, fds, count); } virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) { return const_cast&>(val).unflatten(buffer, size, fds, count); } }; status_t write(const FlattenableHelperInterface& val); status_t read(FlattenableHelperInterface& val) const; public: class ReadableBlob : public Blob { friend class Parcel; public: inline const void* data() const { return mData; } inline void* mutableData() { return isMutable() ? mData : NULL; } }; class WritableBlob : public Blob { friend class Parcel; public: inline void* data() { return mData; } }; private: size_t mOpenAshmemSize; public: // TODO: Remove once ABI can be changed. size_t getBlobAshmemSize() const; size_t getOpenAshmemSize() const; }; // --------------------------------------------------------------------------- template status_t Parcel::write(const Flattenable& val) { const FlattenableHelper helper(val); return write(helper); } template status_t Parcel::write(const LightFlattenable& val) { size_t size(val.getFlattenedSize()); if (!val.isFixedSize()) { status_t err = writeInt32(size); if (err != NO_ERROR) { return err; } } if (size) { void* buffer = writeInplace(size); if (buffer == NULL) return NO_MEMORY; return val.flatten(buffer, size); } return NO_ERROR; } template status_t Parcel::read(Flattenable& val) const { FlattenableHelper helper(val); return read(helper); } template status_t Parcel::read(LightFlattenable& val) const { size_t size; if (val.isFixedSize()) { size = val.getFlattenedSize(); } else { int32_t s; status_t err = readInt32(&s); if (err != NO_ERROR) { return err; } size = s; } if (size) { void const* buffer = readInplace(size); return buffer == NULL ? NO_MEMORY : val.unflatten(buffer, size); } return NO_ERROR; } template status_t Parcel::readStrongBinder(sp* val) const { sp tmp; status_t ret = readStrongBinder(&tmp); if (ret == OK) { *val = interface_cast(tmp); if (val->get() == nullptr) { return UNKNOWN_ERROR; } } return ret; } template status_t Parcel::unsafeReadTypedVector( std::vector* val, status_t(Parcel::*read_func)(U*) const) const { int32_t size; status_t status = this->readInt32(&size); if (status != OK) { return status; } if (size < 0) { return UNEXPECTED_NULL; } if (val->max_size() < size) { return NO_MEMORY; } val->resize(size); if (val->size() < size) { return NO_MEMORY; } for (auto& v: *val) { status = (this->*read_func)(&v); if (status != OK) { return status; } } return OK; } template status_t Parcel::readTypedVector(std::vector* val, status_t(Parcel::*read_func)(T*) const) const { return unsafeReadTypedVector(val, read_func); } template status_t Parcel::readNullableTypedVector(std::unique_ptr>* val, status_t(Parcel::*read_func)(T*) const) const { const int32_t start = dataPosition(); int32_t size; status_t status = readInt32(&size); val->reset(); if (status != OK || size < 0) { return status; } setDataPosition(start); val->reset(new std::vector()); status = unsafeReadTypedVector(val->get(), read_func); if (status != OK) { val->reset(); } return status; } template status_t Parcel::unsafeWriteTypedVector(const std::vector& val, status_t(Parcel::*write_func)(U)) { if (val.size() > std::numeric_limits::max()) { return BAD_VALUE; } status_t status = this->writeInt32(val.size()); if (status != OK) { return status; } for (const auto& item : val) { status = (this->*write_func)(item); if (status != OK) { return status; } } return OK; } template status_t Parcel::writeTypedVector(const std::vector& val, status_t(Parcel::*write_func)(const T&)) { return unsafeWriteTypedVector(val, write_func); } template status_t Parcel::writeTypedVector(const std::vector& val, status_t(Parcel::*write_func)(T)) { return unsafeWriteTypedVector(val, write_func); } template status_t Parcel::writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(const T&)) { if (val.get() == nullptr) { return this->writeInt32(-1); } return unsafeWriteTypedVector(*val, write_func); } template status_t Parcel::writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(T)) { if (val.get() == nullptr) { return this->writeInt32(-1); } return unsafeWriteTypedVector(*val, write_func); } template status_t Parcel::readParcelableVector(std::vector* val) const { return unsafeReadTypedVector(val, &Parcel::readParcelable); } template status_t Parcel::readParcelableVector(std::unique_ptr>>* val) const { const int32_t start = dataPosition(); int32_t size; status_t status = readInt32(&size); val->reset(); if (status != OK || size < 0) { return status; } setDataPosition(start); val->reset(new std::vector>()); status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable); if (status != OK) { val->reset(); } return status; } template status_t Parcel::readParcelable(std::unique_ptr* parcelable) const { const int32_t start = dataPosition(); int32_t present; status_t status = readInt32(&present); parcelable->reset(); if (status != OK || !present) { return status; } setDataPosition(start); parcelable->reset(new T()); status = readParcelable(parcelable->get()); if (status != OK) { parcelable->reset(); } return status; } template status_t Parcel::writeNullableParcelable(const std::unique_ptr& parcelable) { return writeRawNullableParcelable(parcelable.get()); } template status_t Parcel::writeParcelableVector(const std::vector& val) { return unsafeWriteTypedVector(val, &Parcel::writeParcelable); } template status_t Parcel::writeParcelableVector(const std::unique_ptr>>& val) { if (val.get() == nullptr) { return this->writeInt32(-1); } return unsafeWriteTypedVector(*val, &Parcel::writeParcelable); } // --------------------------------------------------------------------------- inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) { parcel.print(to); return to; } // --------------------------------------------------------------------------- // Generic acquire and release of objects. void acquire_object(const sp& proc, const flat_binder_object& obj, const void* who); void release_object(const sp& proc, const flat_binder_object& obj, const void* who); void flatten_binder(const sp& proc, const sp& binder, flat_binder_object* out); void flatten_binder(const sp& proc, const wp& binder, flat_binder_object* out); status_t unflatten_binder(const sp& proc, const flat_binder_object& flat, sp* out); status_t unflatten_binder(const sp& proc, const flat_binder_object& flat, wp* out); }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_PARCEL_H include/binder/Parcelable.h0100644 0000000 0000000 00000003207 13077405420 014702 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_PARCELABLE_H #define ANDROID_PARCELABLE_H #include #include #include namespace android { class Parcel; // Abstract interface of all parcelables. class Parcelable { public: virtual ~Parcelable() = default; // Write |this| parcelable to the given |parcel|. Keep in mind that // implementations of writeToParcel must be manually kept in sync // with readFromParcel and the Java equivalent versions of these methods. // // Returns android::OK on success and an appropriate error otherwise. virtual status_t writeToParcel(Parcel* parcel) const = 0; // Read data from the given |parcel| into |this|. After readFromParcel // completes, |this| should have equivalent state to the object that // wrote itself to the parcel. // // Returns android::OK on success and an appropriate error otherwise. virtual status_t readFromParcel(const Parcel* parcel) = 0; }; // class Parcelable } // namespace android #endif // ANDROID_PARCELABLE_H include/binder/PermissionCache.h0100644 0000000 0000000 00000004751 13077405420 015731 0ustar000000000 0000000 /* * Copyright (C) 2009 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 BINDER_PERMISSION_H #define BINDER_PERMISSION_H #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- /* * PermissionCache caches permission checks for a given uid. * * Currently the cache is not updated when there is a permission change, * for instance when an application is uninstalled. * * IMPORTANT: for the reason stated above, only system permissions are safe * to cache. This restriction may be lifted at a later time. * */ class PermissionCache : Singleton { struct Entry { String16 name; uid_t uid; bool granted; inline bool operator < (const Entry& e) const { return (uid == e.uid) ? (name < e.name) : (uid < e.uid); } }; mutable Mutex mLock; // we pool all the permission names we see, as many permissions checks // will have identical names SortedVector< String16 > mPermissionNamesPool; // this is our cache per say. it stores pooled names. SortedVector< Entry > mCache; // free the whole cache, but keep the permission name pool void purge(); status_t check(bool* granted, const String16& permission, uid_t uid) const; void cache(const String16& permission, uid_t uid, bool granted); public: PermissionCache(); static bool checkCallingPermission(const String16& permission); static bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid); static bool checkPermission(const String16& permission, pid_t pid, uid_t uid); }; // --------------------------------------------------------------------------- }; // namespace android #endif /* BINDER_PERMISSION_H */ include/binder/PersistableBundle.h0100644 0000000 0000000 00000011645 13077405420 016264 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_PERSISTABLE_BUNDLE_H #define ANDROID_PERSISTABLE_BUNDLE_H #include #include #include #include #include namespace android { namespace os { /* * C++ implementation of PersistableBundle, a mapping from String values to * various types that can be saved to persistent and later restored. */ class PersistableBundle : public Parcelable { public: PersistableBundle() = default; virtual ~PersistableBundle() = default; PersistableBundle(const PersistableBundle& bundle) = default; status_t writeToParcel(Parcel* parcel) const override; status_t readFromParcel(const Parcel* parcel) override; bool empty() const; size_t size() const; size_t erase(const String16& key); /* * Setters for PersistableBundle. Adds a a key-value pair instantiated with * |key| and |value| into the member map appropriate for the type of |value|. * If there is already an existing value for |key|, |value| will replace it. */ void putBoolean(const String16& key, bool value); void putInt(const String16& key, int32_t value); void putLong(const String16& key, int64_t value); void putDouble(const String16& key, double value); void putString(const String16& key, const String16& value); void putBooleanVector(const String16& key, const std::vector& value); void putIntVector(const String16& key, const std::vector& value); void putLongVector(const String16& key, const std::vector& value); void putDoubleVector(const String16& key, const std::vector& value); void putStringVector(const String16& key, const std::vector& value); void putPersistableBundle(const String16& key, const PersistableBundle& value); /* * Getters for PersistableBundle. If |key| exists, these methods write the * value associated with |key| into |out|, and return true. Otherwise, these * methods return false. */ bool getBoolean(const String16& key, bool* out) const; bool getInt(const String16& key, int32_t* out) const; bool getLong(const String16& key, int64_t* out) const; bool getDouble(const String16& key, double* out) const; bool getString(const String16& key, String16* out) const; bool getBooleanVector(const String16& key, std::vector* out) const; bool getIntVector(const String16& key, std::vector* out) const; bool getLongVector(const String16& key, std::vector* out) const; bool getDoubleVector(const String16& key, std::vector* out) const; bool getStringVector(const String16& key, std::vector* out) const; bool getPersistableBundle(const String16& key, PersistableBundle* out) const; friend bool operator==(const PersistableBundle& lhs, const PersistableBundle& rhs) { return (lhs.mBoolMap == rhs.mBoolMap && lhs.mIntMap == rhs.mIntMap && lhs.mLongMap == rhs.mLongMap && lhs.mDoubleMap == rhs.mDoubleMap && lhs.mStringMap == rhs.mStringMap && lhs.mBoolVectorMap == rhs.mBoolVectorMap && lhs.mIntVectorMap == rhs.mIntVectorMap && lhs.mLongVectorMap == rhs.mLongVectorMap && lhs.mDoubleVectorMap == rhs.mDoubleVectorMap && lhs.mStringVectorMap == rhs.mStringVectorMap && lhs.mPersistableBundleMap == rhs.mPersistableBundleMap); } friend bool operator!=(const PersistableBundle& lhs, const PersistableBundle& rhs) { return !(lhs == rhs); } private: status_t writeToParcelInner(Parcel* parcel) const; status_t readFromParcelInner(const Parcel* parcel, size_t length); std::map mBoolMap; std::map mIntMap; std::map mLongMap; std::map mDoubleMap; std::map mStringMap; std::map> mBoolVectorMap; std::map> mIntVectorMap; std::map> mLongVectorMap; std::map> mDoubleVectorMap; std::map> mStringVectorMap; std::map mPersistableBundleMap; }; } // namespace os } // namespace android #endif // ANDROID_PERSISTABLE_BUNDLE_H include/binder/ProcessInfoService.h0100644 0000000 0000000 00000004051 13077405420 016421 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_PROCESS_INFO_SERVICE_H #define ANDROID_PROCESS_INFO_SERVICE_H #include #include #include #include namespace android { // ---------------------------------------------------------------------- class ProcessInfoService : public Singleton { friend class Singleton; sp mProcessInfoService; Mutex mProcessInfoLock; ProcessInfoService(); status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states); void updateBinderLocked(); static const int BINDER_ATTEMPT_LIMIT = 5; public: /** * For each PID in the given "pids" input array, write the current process state * for that process into the "states" output array, or * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID * exists. * * Returns NO_ERROR if this operation was successful, or a negative error code otherwise. */ static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states) { return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids, /*out*/ states); } }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_PROCESS_INFO_SERVICE_H include/binder/ProcessState.h0100644 0000000 0000000 00000010252 13077405420 015265 0ustar000000000 0000000 /* * Copyright (C) 2005 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_PROCESS_STATE_H #define ANDROID_PROCESS_STATE_H #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { class IPCThreadState; class ProcessState : public virtual RefBase { public: static sp self(); void setContextObject(const sp& object); sp getContextObject(const sp& caller); void setContextObject(const sp& object, const String16& name); sp getContextObject(const String16& name, const sp& caller); void startThreadPool(); typedef bool (*context_check_func)(const String16& name, const sp& caller, void* userData); bool isContextManager(void) const; bool becomeContextManager( context_check_func checkFunc, void* userData); sp getStrongProxyForHandle(int32_t handle); wp getWeakProxyForHandle(int32_t handle); void expungeHandle(int32_t handle, IBinder* binder); void spawnPooledThread(bool isMain); status_t setThreadPoolMaxThreadCount(size_t maxThreads); void giveThreadPoolName(); private: friend class IPCThreadState; ProcessState(); ~ProcessState(); ProcessState(const ProcessState& o); ProcessState& operator=(const ProcessState& o); String8 makeBinderThreadName(); struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; }; handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD; void* mVMStart; // Protects thread count variable below. pthread_mutex_t mThreadCountLock; pthread_cond_t mThreadCountDecrement; // Number of binder threads current executing a command. size_t mExecutingThreadsCount; // Maximum number for binder threads allowed for this process. size_t mMaxThreads; // Time when thread pool was emptied int64_t mStarvationStartTimeMs; mutable Mutex mLock; // protects everything below. VectormHandleToObject; bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; KeyedVector > mContexts; String8 mRootDir; bool mThreadPoolStarted; volatile int32_t mThreadPoolSeq; }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_PROCESS_STATE_H include/binder/Status.h0100644 0000000 0000000 00000013310 13077405420 014127 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_BINDER_STATUS_H #define ANDROID_BINDER_STATUS_H #include #include #include namespace android { namespace binder { // An object similar in function to a status_t except that it understands // how exceptions are encoded in the prefix of a Parcel. Used like: // // Parcel data; // Parcel reply; // status_t status; // binder::Status remote_exception; // if ((status = data.writeInterfaceToken(interface_descriptor)) != OK || // (status = data.writeInt32(function_input)) != OK) { // // We failed to write into the memory of our local parcel? // } // if ((status = remote()->transact(transaction, data, &reply)) != OK) { // // Something has gone wrong in the binder driver or libbinder. // } // if ((status = remote_exception.readFromParcel(reply)) != OK) { // // The remote didn't correctly write the exception header to the // // reply. // } // if (!remote_exception.isOk()) { // // The transaction went through correctly, but the remote reported an // // exception during handling. // } // class Status final { public: // Keep the exception codes in sync with android/os/Parcel.java. enum Exception { EX_NONE = 0, EX_SECURITY = -1, EX_BAD_PARCELABLE = -2, EX_ILLEGAL_ARGUMENT = -3, EX_NULL_POINTER = -4, EX_ILLEGAL_STATE = -5, EX_NETWORK_MAIN_THREAD = -6, EX_UNSUPPORTED_OPERATION = -7, EX_SERVICE_SPECIFIC = -8, // This is special and Java specific; see Parcel.java. EX_HAS_REPLY_HEADER = -128, // This is special, and indicates to C++ binder proxies that the // transaction has failed at a low level. EX_TRANSACTION_FAILED = -129, }; // A more readable alias for the default constructor. static Status ok(); // Authors should explicitly pick whether their integer is: // - an exception code (EX_* above) // - service specific error code // - status_t // // Prefer a generic exception code when possible, then a service specific // code, and finally a status_t for low level failures or legacy support. // Exception codes and service specific errors map to nicer exceptions for // Java clients. static Status fromExceptionCode(int32_t exceptionCode); static Status fromExceptionCode(int32_t exceptionCode, const String8& message); static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode); static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode, const String8& message); static Status fromStatusT(status_t status); Status() = default; ~Status() = default; // Status objects are copyable and contain just simple data. Status(const Status& status) = default; Status(Status&& status) = default; Status& operator=(const Status& status) = default; // Bear in mind that if the client or service is a Java endpoint, this // is not the logic which will provide/interpret the data here. status_t readFromParcel(const Parcel& parcel); status_t writeToParcel(Parcel* parcel) const; // Set one of the pre-defined exception types defined above. void setException(int32_t ex, const String8& message); // Set a service specific exception with error code. void setServiceSpecificError(int32_t errorCode, const String8& message); // Setting a |status| != OK causes generated code to return |status| // from Binder transactions, rather than writing an exception into the // reply Parcel. This is the least preferable way of reporting errors. void setFromStatusT(status_t status); // Get information about an exception. int32_t exceptionCode() const { return mException; } const String8& exceptionMessage() const { return mMessage; } status_t transactionError() const { return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK; } int32_t serviceSpecificErrorCode() const { return mException == EX_SERVICE_SPECIFIC ? mErrorCode : 0; } bool isOk() const { return mException == EX_NONE; } // For logging. String8 toString8() const; private: Status(int32_t exceptionCode, int32_t errorCode); Status(int32_t exceptionCode, int32_t errorCode, const String8& message); // If |mException| == EX_TRANSACTION_FAILED, generated code will return // |mErrorCode| as the result of the transaction rather than write an // exception to the reply parcel. // // Otherwise, we always write |mException| to the parcel. // If |mException| != EX_NONE, we write |mMessage| as well. // If |mException| == EX_SERVICE_SPECIFIC we write |mErrorCode| as well. int32_t mException = EX_NONE; int32_t mErrorCode = 0; String8 mMessage; }; // class Status // For gtest output logging template T& operator<< (T& stream, const Status& s) { stream << s.toString8().string(); return stream; } } // namespace binder } // namespace android #endif // ANDROID_BINDER_STATUS_H include/binder/TextOutput.h0100644 0000000 0000000 00000012642 13077405420 015020 0ustar000000000 0000000 /* * Copyright (C) 2006 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_TEXTOUTPUT_H #define ANDROID_TEXTOUTPUT_H #include #include #include // --------------------------------------------------------------------------- namespace android { class String8; class String16; class TextOutput { public: TextOutput(); virtual ~TextOutput(); virtual status_t print(const char* txt, size_t len) = 0; virtual void moveIndent(int delta) = 0; class Bundle { public: inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); } inline ~Bundle() { mTO.popBundle(); } private: TextOutput& mTO; }; virtual void pushBundle() = 0; virtual void popBundle() = 0; }; // --------------------------------------------------------------------------- // Text output stream for printing to the log (via utils/Log.h). extern TextOutput& alog; // Text output stream for printing to stdout. extern TextOutput& aout; // Text output stream for printing to stderr. extern TextOutput& aerr; typedef TextOutput& (*TextOutputManipFunc)(TextOutput&); TextOutput& endl(TextOutput& to); TextOutput& indent(TextOutput& to); TextOutput& dedent(TextOutput& to); TextOutput& operator<<(TextOutput& to, const char* str); TextOutput& operator<<(TextOutput& to, char); // writes raw character TextOutput& operator<<(TextOutput& to, bool); TextOutput& operator<<(TextOutput& to, int); TextOutput& operator<<(TextOutput& to, long); TextOutput& operator<<(TextOutput& to, unsigned int); TextOutput& operator<<(TextOutput& to, unsigned long); TextOutput& operator<<(TextOutput& to, long long); TextOutput& operator<<(TextOutput& to, unsigned long long); TextOutput& operator<<(TextOutput& to, float); TextOutput& operator<<(TextOutput& to, double); TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func); TextOutput& operator<<(TextOutput& to, const void*); TextOutput& operator<<(TextOutput& to, const String8& val); TextOutput& operator<<(TextOutput& to, const String16& val); class TypeCode { public: inline TypeCode(uint32_t code); inline ~TypeCode(); inline uint32_t typeCode() const; private: uint32_t mCode; }; TextOutput& operator<<(TextOutput& to, const TypeCode& val); class HexDump { public: HexDump(const void *buf, size_t size, size_t bytesPerLine=16); inline ~HexDump(); inline HexDump& setBytesPerLine(size_t bytesPerLine); inline HexDump& setSingleLineCutoff(int32_t bytes); inline HexDump& setAlignment(size_t alignment); inline HexDump& setCArrayStyle(bool enabled); inline const void* buffer() const; inline size_t size() const; inline size_t bytesPerLine() const; inline int32_t singleLineCutoff() const; inline size_t alignment() const; inline bool carrayStyle() const; private: const void* mBuffer; size_t mSize; size_t mBytesPerLine; int32_t mSingleLineCutoff; size_t mAlignment; bool mCArrayStyle; }; TextOutput& operator<<(TextOutput& to, const HexDump& val); // --------------------------------------------------------------------------- // No user servicable parts below. inline TextOutput& endl(TextOutput& to) { to.print("\n", 1); return to; } inline TextOutput& indent(TextOutput& to) { to.moveIndent(1); return to; } inline TextOutput& dedent(TextOutput& to) { to.moveIndent(-1); return to; } inline TextOutput& operator<<(TextOutput& to, const char* str) { to.print(str, strlen(str)); return to; } inline TextOutput& operator<<(TextOutput& to, char c) { to.print(&c, 1); return to; } inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func) { return (*func)(to); } inline TypeCode::TypeCode(uint32_t code) : mCode(code) { } inline TypeCode::~TypeCode() { } inline uint32_t TypeCode::typeCode() const { return mCode; } inline HexDump::~HexDump() { } inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) { mBytesPerLine = bytesPerLine; return *this; } inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) { mSingleLineCutoff = bytes; return *this; } inline HexDump& HexDump::setAlignment(size_t alignment) { mAlignment = alignment; return *this; } inline HexDump& HexDump::setCArrayStyle(bool enabled) { mCArrayStyle = enabled; return *this; } inline const void* HexDump::buffer() const { return mBuffer; } inline size_t HexDump::size() const { return mSize; } inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; } inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; } inline size_t HexDump::alignment() const { return mAlignment; } inline bool HexDump::carrayStyle() const { return mCArrayStyle; } // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_TEXTOUTPUT_H include/diskusage/0040755 0000000 0000000 00000000000 13077405420 013214 5ustar000000000 0000000 include/diskusage/dirsize.h0100644 0000000 0000000 00000001522 13077405420 015033 0ustar000000000 0000000 /* * * Copyright (C) 2010 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 __LIBDISKUSAGE_DIRSIZE_H #define __LIBDISKUSAGE_DIRSIZE_H #include __BEGIN_DECLS int64_t stat_size(struct stat *s); int64_t calculate_dir_size(int dfd); __END_DECLS #endif /* __LIBDISKUSAGE_DIRSIZE_H */ include/gui/0040755 0000000 0000000 00000000000 13077405420 012021 5ustar000000000 0000000 include/gui/BitTube.h0100644 0000000 0000000 00000005555 13077405420 013537 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_SENSOR_CHANNEL_H #define ANDROID_GUI_SENSOR_CHANNEL_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class Parcel; class BitTube : public RefBase { public: // creates a BitTube with a default (4KB) send buffer BitTube(); // creates a BitTube with a a specified send and receive buffer size explicit BitTube(size_t bufsize); explicit BitTube(const Parcel& data); virtual ~BitTube(); // check state after construction status_t initCheck() const; // get receive file-descriptor int getFd() const; // get the send file-descriptor. int getSendFd() const; // send objects (sized blobs). All objects are guaranteed to be written or the call fails. template static ssize_t sendObjects(const sp& tube, T const* events, size_t count) { return sendObjects(tube, events, count, sizeof(T)); } // receive objects (sized blobs). If the receiving buffer isn't large enough, // excess messages are silently discarded. template static ssize_t recvObjects(const sp& tube, T* events, size_t count) { return recvObjects(tube, events, count, sizeof(T)); } // parcels this BitTube status_t writeToParcel(Parcel* reply) const; private: void init(size_t rcvbuf, size_t sndbuf); // send a message. The write is guaranteed to send the whole message or fail. ssize_t write(void const* vaddr, size_t size); // receive a message. the passed buffer must be at least as large as the // write call used to send the message, excess data is silently discarded. ssize_t read(void* vaddr, size_t size); int mSendFd; mutable int mReceiveFd; static ssize_t sendObjects(const sp& tube, void const* events, size_t count, size_t objSize); static ssize_t recvObjects(const sp& tube, void* events, size_t count, size_t objSize); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_SENSOR_CHANNEL_H include/gui/BufferItem.h0100644 0000000 0000000 00000010755 13077405420 014227 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERITEM_H #define ANDROID_GUI_BUFFERITEM_H #include #include #include #include #include #include #include namespace android { class Fence; class GraphicBuffer; class BufferItem : public Flattenable { friend class Flattenable; size_t getPodSize() const; size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); public: // The default value of mBuf, used to indicate this doesn't correspond to a slot. enum { INVALID_BUFFER_SLOT = -1 }; BufferItem(); ~BufferItem(); static const char* scalingModeName(uint32_t scalingMode); // mGraphicBuffer points to the buffer allocated for this slot, or is NULL // if the buffer in this slot has been acquired in the past (see // BufferSlot.mAcquireCalled). sp mGraphicBuffer; // mFence is a fence that will signal when the buffer is idle. sp mFence; // mCrop is the current crop rectangle for this buffer slot. Rect mCrop; // mTransform is the current transform flags for this buffer slot. // refer to NATIVE_WINDOW_TRANSFORM_* in uint32_t mTransform; // mScalingMode is the current scaling mode for this buffer slot. // refer to NATIVE_WINDOW_SCALING_* in uint32_t mScalingMode; // mTimestamp is the current timestamp for this buffer slot. This gets // to set by queueBuffer each time this slot is queued. This value // is guaranteed to be monotonically increasing for each newly // acquired buffer. union { int64_t mTimestamp; struct { uint32_t mTimestampLo; uint32_t mTimestampHi; }; }; // mIsAutoTimestamp indicates whether mTimestamp was generated // automatically when the buffer was queued. bool mIsAutoTimestamp; // mDataSpace is the current dataSpace value for this buffer slot. This gets // set by queueBuffer each time this slot is queued. The meaning of the // dataSpace is format-dependent. android_dataspace mDataSpace; // mFrameNumber is the number of the queued frame for this slot. union { uint64_t mFrameNumber; struct { uint32_t mFrameNumberLo; uint32_t mFrameNumberHi; }; }; // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). int mSlot; // mIsDroppable whether this buffer was queued with the // property that it can be replaced by a new buffer for the purpose of // making sure dequeueBuffer() won't block. // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer // was queued. bool mIsDroppable; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; // Indicates this buffer must be transformed by the inverse transform of the screen // it is displayed onto. This is applied after mTransform. bool mTransformToDisplayInverse; // Describes the portion of the surface that has been modified since the // previous frame Region mSurfaceDamage; // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant // in shared buffer mode. bool mAutoRefresh; // Indicates that this buffer was queued by the producer. When in shared // buffer mode acquire() can return a BufferItem that wasn't in the queue. bool mQueuedBuffer; // Indicates that this BufferItem contains a stale buffer which has already // been released by the BufferQueue. bool mIsStale; }; } // namespace android #endif include/gui/BufferItemConsumer.h0100644 0000000 0000000 00000007273 13077405420 015744 0ustar000000000 0000000 /* * Copyright (C) 2012 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_GUI_BUFFERITEMCONSUMER_H #define ANDROID_GUI_BUFFERITEMCONSUMER_H #include #include #include #include #include #define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer" namespace android { class BufferQueue; /** * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients * access to the whole BufferItem entry from BufferQueue. Multiple buffers may * be acquired at once, to be used concurrently by the client. This consumer can * operate either in synchronous or asynchronous mode. */ class BufferItemConsumer: public ConsumerBase { public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; enum { DEFAULT_MAX_BUFFERS = -1 }; enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; // Create a new buffer item consumer. The consumerUsage parameter determines // the consumer usage flags passed to the graphics allocator. The // bufferCount parameter specifies how many buffers can be locked for user // access at the same time. // controlledByApp tells whether this consumer is controlled by the // application. BufferItemConsumer(const sp& consumer, uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); virtual ~BufferItemConsumer(); // set the name of the BufferItemConsumer that will be used to identify it in // log messages. void setName(const String8& name); // Gets the next graphics buffer from the producer, filling out the // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue // of buffers is empty, and INVALID_OPERATION if the maximum number of // buffers is already acquired. // // Only a fixed number of buffers can be acquired at a time, determined by // the construction-time bufferCount parameter. If INVALID_OPERATION is // returned by acquireBuffer, then old buffers must be returned to the // queue by calling releaseBuffer before more buffers can be acquired. // // If waitForFence is true, and the acquired BufferItem has a valid fence object, // acquireBuffer will wait on the fence with no timeout before returning. status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen, bool waitForFence = true); // Returns an acquired buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be acquired at a time, old buffers // must be released by calling releaseBuffer to ensure new buffers can be // acquired by acquireBuffer. Once a BufferItem is released, the caller must // not access any members of the BufferItem, and should immediately remove // all of its references to the BufferItem itself. status_t releaseBuffer(const BufferItem &item, const sp& releaseFence = Fence::NO_FENCE); }; } // namespace android #endif // ANDROID_GUI_CPUCONSUMER_H include/gui/BufferQueue.h0100644 0000000 0000000 00000007272 13077405420 014415 0ustar000000000 0000000 /* * Copyright (C) 2012 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_GUI_BUFFERQUEUE_H #define ANDROID_GUI_BUFFERQUEUE_H #include #include #include #include #include // These are only required to keep other parts of the framework with incomplete // dependencies building successfully #include namespace android { class BufferQueue { public: // BufferQueue will keep track of at most this value of buffers. // Attempts at runtime to increase the number of buffers past this will fail. enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; // Used as a placeholder slot# when the value isn't pointing to an existing buffer. enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // Alias to -- please scope from there in future code! enum { NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, PRESENT_LATER = IGraphicBufferConsumer::PRESENT_LATER, }; // When in async mode we reserve two slots in order to guarantee that the // producer and consumer can run asynchronously. enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; // for backward source compatibility typedef ::android::ConsumerListener ConsumerListener; // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak // reference to the actual consumer object. It forwards all calls to that // consumer object so long as it exists. // // This class exists to avoid having a circular reference between the // BufferQueue object and the consumer object. The reason this can't be a weak // reference in the BufferQueue class is because we're planning to expose the // consumer side of a BufferQueue as a binder interface, which doesn't support // weak references. class ProxyConsumerListener : public BnConsumerListener { public: ProxyConsumerListener(const wp& consumerListener); virtual ~ProxyConsumerListener(); virtual void onFrameAvailable(const BufferItem& item) override; virtual void onFrameReplaced(const BufferItem& item) override; virtual void onBuffersReleased() override; virtual void onSidebandStreamChanged() override; private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. wp mConsumerListener; }; // BufferQueue manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the // needed gralloc buffers. static void createBufferQueue(sp* outProducer, sp* outConsumer, const sp& allocator = NULL); private: BufferQueue(); // Create through createBufferQueue }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_BUFFERQUEUE_H include/gui/BufferQueueConsumer.h0100644 0000000 0000000 00000016554 13077405420 016134 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERQUEUECONSUMER_H #define ANDROID_GUI_BUFFERQUEUECONSUMER_H #include #include #include #include namespace android { class BufferQueueCore; class BufferQueueConsumer : public BnGraphicBufferConsumer { public: BufferQueueConsumer(const sp& core); virtual ~BufferQueueConsumer(); // acquireBuffer attempts to acquire ownership of the next pending buffer in // the BufferQueue. If no buffer is pending then it returns // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the // information about the buffer is returned in BufferItem. If the buffer // returned had previously been acquired then the BufferItem::mGraphicBuffer // field of buffer is set to NULL and it is assumed that the consumer still // holds a reference to the buffer. // // If expectedPresent is nonzero, it indicates the time when the buffer // will be displayed on screen. If the buffer's timestamp is farther in the // future, the buffer won't be acquired, and PRESENT_LATER will be // returned. The presentation time is in nanoseconds, and the time base // is CLOCK_MONOTONIC. virtual status_t acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override; // See IGraphicBufferConsumer::detachBuffer virtual status_t detachBuffer(int slot); // See IGraphicBufferConsumer::attachBuffer virtual status_t attachBuffer(int* slot, const sp& buffer); // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer // in use. frameNumber is used to indentify the exact buffer returned. // // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free // any references to the just-released buffer that it might have, as if it // had received a onBuffersReleased() call with a mask set for the released // buffer. // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. virtual status_t releaseBuffer(int slot, uint64_t frameNumber, const sp& releaseFence, EGLDisplay display, EGLSyncKHR fence); // connect connects a consumer to the BufferQueue. Only one // consumer may be connected, and when that consumer disconnects the // BufferQueue is placed into the "abandoned" state, causing most // interactions with the BufferQueue by the producer to fail. // controlledByApp indicates whether the consumer is controlled by // the application. // // consumerListener may not be NULL. virtual status_t connect(const sp& consumerListener, bool controlledByApp); // disconnect disconnects a consumer from the BufferQueue. All // buffers will be freed and the BufferQueue is placed in the "abandoned" // state, causing most interactions with the BufferQueue by the producer to // fail. virtual status_t disconnect(); // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask // indicating which buffer slots have been released by the BufferQueue // but have not yet been released by the consumer. // // This should be called from the onBuffersReleased() callback. virtual status_t getReleasedBuffers(uint64_t* outSlotMask); // setDefaultBufferSize is used to set the size of buffers returned by // dequeueBuffer when a width and height of zero is requested. Default // is 1x1. virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); // see IGraphicBufferConsumer::setMaxBufferCount virtual status_t setMaxBufferCount(int bufferCount); // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // setConsumerName sets the name used in logging virtual void setConsumerName(const String8& name); // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // in dequeueBuffer. The initial default is HAL_PIXEL_FORMAT_RGBA_8888. virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat); // setDefaultBufferDataSpace allows the BufferQueue to create // GraphicBuffers of a defaultDataSpace if no data space is specified // in queueBuffer. // The initial default is HAL_DATASPACE_UNKNOWN virtual status_t setDefaultBufferDataSpace( android_dataspace defaultDataSpace); // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. // These are merged with the bits passed to dequeueBuffer. The values are // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. virtual status_t setConsumerUsageBits(uint32_t usage); // setTransformHint bakes in rotation to buffers so overlays can be used. // The values are enumerated in window.h, e.g. // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). virtual status_t setTransformHint(uint32_t hint); // Retrieve the sideband buffer stream, if any. virtual sp getSidebandStream() const; // See IGraphicBufferConsumer::discardFreeBuffers virtual status_t discardFreeBuffers() override; // dump our state in a String virtual void dump(String8& result, const char* prefix) const; // Functions required for backwards compatibility. // These will be modified/renamed in IGraphicBufferConsumer and will be // removed from this class at that time. See b/13306289. virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp& releaseFence) { return releaseBuffer(buf, frameNumber, releaseFence, display, fence); } virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { return connect(consumer, controlledByApp); } virtual status_t consumerDisconnect() { return disconnect(); } // End functions required for backwards compatibility private: sp mCore; // This references mCore->mSlots. Lock mCore->mMutex while accessing. BufferQueueDefs::SlotsType& mSlots; // This is a cached copy of the name stored in the BufferQueueCore. // It's updated during setConsumerName. String8 mConsumerName; }; // class BufferQueueConsumer } // namespace android #endif include/gui/BufferQueueCore.h0100644 0000000 0000000 00000032010 13077405420 015212 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERQUEUECORE_H #define ANDROID_GUI_BUFFERQUEUECORE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define ATRACE_BUFFER_INDEX(index) \ if (ATRACE_ENABLED()) { \ char ___traceBuf[1024]; \ snprintf(___traceBuf, 1024, "%s: %d", \ mCore->mConsumerName.string(), (index)); \ android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ } namespace android { class IConsumerListener; class IGraphicBufferAlloc; class IProducerListener; class BufferQueueCore : public virtual RefBase { friend class BufferQueueProducer; friend class BufferQueueConsumer; public: // Used as a placeholder slot number when the value isn't pointing to an // existing buffer. enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // We reserve two slots in order to guarantee that the producer and // consumer can run asynchronously. enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; enum { // The API number used to indicate the currently connected producer CURRENTLY_CONNECTED_API = -1, // The API number used to indicate that no producer is connected NO_CONNECTED_API = 0, }; typedef Vector Fifo; // BufferQueueCore manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the needed // gralloc buffers. BufferQueueCore(const sp& allocator = NULL); virtual ~BufferQueueCore(); private: // Dump our state in a string void dump(String8& result, const char* prefix) const; // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we're in asynchronous mode. int getMinUndequeuedBufferCountLocked() const; // getMinMaxBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. The async parameter tells whether // we're in asynchonous mode. int getMinMaxBufferCountLocked() const; // getMaxBufferCountLocked returns the maximum number of buffers that can be // allocated at once. This value depends on the following member variables: // // mMaxDequeuedBufferCount // mMaxAcquiredBufferCount // mMaxBufferCount // mAsyncMode // mDequeueBufferCannotBlock // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. int getMaxBufferCountLocked() const; // This performs the same computation but uses the given arguments instead // of the member variables for mMaxBufferCount, mAsyncMode, and // mDequeueBufferCannotBlock. int getMaxBufferCountLocked(bool asyncMode, bool dequeueBufferCannotBlock, int maxBufferCount) const; // clearBufferSlotLocked frees the GraphicBuffer and sync resources for the // given slot. void clearBufferSlotLocked(int slot); // freeAllBuffersLocked frees the GraphicBuffer and sync resources for // all slots, even if they're currently dequeued, queued, or acquired. void freeAllBuffersLocked(); // discardFreeBuffersLocked releases all currently-free buffers held by the // queue, in order to reduce the memory consumption of the queue to the // minimum possible without discarding data. void discardFreeBuffersLocked(); // If delta is positive, makes more slots available. If negative, takes // away slots. Returns false if the request can't be met. bool adjustAvailableSlotsLocked(int delta); // waitWhileAllocatingLocked blocks until mIsAllocating is false. void waitWhileAllocatingLocked() const; #if DEBUG_ONLY_CODE // validateConsistencyLocked ensures that the free lists are in sync with // the information stored in mSlots void validateConsistencyLocked() const; #endif // mAllocator is the connection to SurfaceFlinger that is used to allocate // new GraphicBuffer objects. sp mAllocator; // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueueCore objects. It must be locked whenever any // member variable is accessed. mutable Mutex mMutex; // mIsAbandoned indicates that the BufferQueue will no longer be used to // consume image buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the // consumerDisconnect method. A BufferQueue that is abandoned will return // the NO_INIT error from all IGraphicBufferProducer methods capable of // returning an error. bool mIsAbandoned; // mConsumerControlledByApp indicates whether the connected consumer is // controlled by the application. bool mConsumerControlledByApp; // mConsumerName is a string used to identify the BufferQueue in log // messages. It is set by the IGraphicBufferConsumer::setConsumerName // method. String8 mConsumerName; // mConsumerListener is used to notify the connected consumer of // asynchronous events that it may wish to react to. It is initially // set to NULL and is written by consumerConnect and consumerDisconnect. sp mConsumerListener; // mConsumerUsageBits contains flags that the consumer wants for // GraphicBuffers. uint32_t mConsumerUsageBits; // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated // by the connect and disconnect methods. int mConnectedApi; // mConnectedProducerToken is used to set a binder death notification on // the producer. sp mConnectedProducerListener; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer // and consumer without sending a GraphicBuffer over Binder. The entire // array is initialized to NULL at construction time, and buffers are // allocated for a slot when requestBuffer is called with that slot's index. BufferQueueDefs::SlotsType mSlots; // mQueue is a FIFO of queued buffers used in synchronous mode. Fifo mQueue; // mFreeSlots contains all of the slots which are FREE and do not currently // have a buffer attached. std::set mFreeSlots; // mFreeBuffers contains all of the slots which are FREE and currently have // a buffer attached. std::list mFreeBuffers; // mUnusedSlots contains all slots that are currently unused. They should be // free and not have a buffer attached. std::list mUnusedSlots; // mActiveBuffers contains all slots which have a non-FREE buffer attached. std::set mActiveBuffers; // mDequeueCondition is a condition variable used for dequeueBuffer in // synchronous mode. mutable Condition mDequeueCondition; // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and // consumer are controlled by the application. bool mDequeueBufferCannotBlock; // mDefaultBufferFormat can be set so it will override the buffer format // when it isn't specified in dequeueBuffer. PixelFormat mDefaultBufferFormat; // mDefaultWidth holds the default width of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultWidth; // mDefaultHeight holds the default height of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultHeight; // mDefaultBufferDataSpace holds the default dataSpace of queued buffers. // It is used in queueBuffer if a dataspace of 0 (HAL_DATASPACE_UNKNOWN) // is specified. android_dataspace mDefaultBufferDataSpace; // mMaxBufferCount is the limit on the number of buffers that will be // allocated at one time. This limit can be set by the consumer. int mMaxBufferCount; // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer // via setMaxAcquiredBufferCount, but this may only be done while no // producer is connected to the BufferQueue. This value is used to derive // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. int mMaxAcquiredBufferCount; // mMaxDequeuedBufferCount is the number of buffers that the producer may // dequeue at one time. It defaults to 1, and can be changed by the producer // via setMaxDequeuedBufferCount. int mMaxDequeuedBufferCount; // mBufferHasBeenQueued is true once a buffer has been queued. It is reset // when something causes all buffers to be freed (e.g., changing the buffer // count). bool mBufferHasBeenQueued; // mFrameCounter is the free running counter, incremented on every // successful queueBuffer call and buffer allocation. uint64_t mFrameCounter; // mTransformHint is used to optimize for screen rotations. uint32_t mTransformHint; // mSidebandStream is a handle to the sideband buffer stream, if any sp mSidebandStream; // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which // releases mMutex while doing the allocation proper). Producers should not modify any of the // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to // false. bool mIsAllocating; // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. mutable Condition mIsAllocatingCondition; // mAllowAllocation determines whether dequeueBuffer is allowed to allocate // new buffers bool mAllowAllocation; // mBufferAge tracks the age of the contents of the most recently dequeued // buffer as the number of frames that have elapsed since it was last queued uint64_t mBufferAge; // mGenerationNumber stores the current generation number of the attached // producer. Any attempt to attach a buffer with a different generation // number will fail. uint32_t mGenerationNumber; // mAsyncMode indicates whether or not async mode is enabled. // In async mode an extra buffer will be allocated to allow the producer to // enqueue buffers without blocking. bool mAsyncMode; // mSharedBufferMode indicates whether or not shared buffer mode is enabled. bool mSharedBufferMode; // When shared buffer mode is enabled, this indicates whether the consumer // should acquire buffers even if BufferQueue doesn't indicate that they are // available. bool mAutoRefresh; // When shared buffer mode is enabled, this tracks which slot contains the // shared buffer. int mSharedBufferSlot; // Cached data about the shared buffer in shared buffer mode struct SharedBufferCache { SharedBufferCache(Rect _crop, uint32_t _transform, int _scalingMode, android_dataspace _dataspace) : crop(_crop), transform(_transform), scalingMode(_scalingMode), dataspace(_dataspace) { }; Rect crop; uint32_t transform; uint32_t scalingMode; android_dataspace dataspace; } mSharedBufferCache; // The slot of the last queued buffer int mLastQueuedSlot; const uint64_t mUniqueId; }; // class BufferQueueCore } // namespace android #endif include/gui/BufferQueueDefs.h0100644 0000000 0000000 00000002170 13077405420 015207 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERQUEUECOREDEFS_H #define ANDROID_GUI_BUFFERQUEUECOREDEFS_H #include namespace android { class BufferQueueCore; namespace BufferQueueDefs { // BufferQueue will keep track of at most this value of buffers. // Attempts at runtime to increase the number of buffers past this // will fail. enum { NUM_BUFFER_SLOTS = 64 }; typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; } // namespace BufferQueueDefs } // namespace android #endif include/gui/BufferQueueProducer.h0100644 0000000 0000000 00000025465 13077405420 016125 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERQUEUEPRODUCER_H #define ANDROID_GUI_BUFFERQUEUEPRODUCER_H #include #include namespace android { class BufferSlot; class BufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient { public: friend class BufferQueue; // Needed to access binderDied BufferQueueProducer(const sp& core); virtual ~BufferQueueProducer(); // requestBuffer returns the GraphicBuffer for slot N. // // In normal operation, this is called the first time slot N is returned // by dequeueBuffer. It must be called again if dequeueBuffer returns // flags indicating that previously-returned buffers are no longer valid. virtual status_t requestBuffer(int slot, sp* buf); // see IGraphicsBufferProducer::setMaxDequeuedBufferCount virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); // see IGraphicsBufferProducer::setAsyncMode virtual status_t setAsyncMode(bool async); // dequeueBuffer gets the next buffer slot index for the producer to use. // If a buffer slot is available then that slot index is written to the // location pointed to by the buf argument and a status of OK is returned. // If no slot is available then a status of -EBUSY is returned and buf is // unmodified. // // The outFence parameter will be updated to hold the fence associated with // the buffer. The contents of the buffer must not be overwritten until the // fence signals. If the fence is Fence::NO_FENCE, the buffer may be // written immediately. // // The width and height parameters must be no greater than the minimum of // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). // An error due to invalid dimensions might not be reported until // updateTexImage() is called. If width and height are both zero, the // default values specified by setDefaultBufferSize() are used instead. // // If the format is 0, the default format will be used. // // The usage argument specifies gralloc buffer usage flags. The values // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These // will be merged with the usage flags specified by setConsumerUsageBits. // // The return value may be a negative error value or a non-negative // collection of flags. If the flags are set, the return values are // valid, but additional actions must be performed. // // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the // producer must discard cached GraphicBuffer references for the slot // returned in buf. // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer // must discard cached GraphicBuffer references for all slots. // // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. virtual status_t dequeueBuffer(int *outSlot, sp* outFence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); // See IGraphicBufferProducer::detachBuffer virtual status_t detachBuffer(int slot); // See IGraphicBufferProducer::detachNextBuffer virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence); // See IGraphicBufferProducer::attachBuffer virtual status_t attachBuffer(int* outSlot, const sp& buffer); // queueBuffer returns a filled buffer to the BufferQueue. // // Additional data is provided in the QueueBufferInput struct. Notably, // a timestamp must be provided for the buffer. The timestamp is in // nanoseconds, and must be monotonically increasing. Its other semantics // (zero point, etc) are producer-specific and should be documented by the // producer. // // The caller may provide a fence that signals when all rendering // operations have completed. Alternatively, NO_FENCE may be used, // indicating that the buffer is ready immediately. // // Some values are returned in the output struct: the current settings // for default width and height, the current transform hint, and the // number of queued buffers. virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output); // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't // queue it for use by the consumer. // // The buffer will not be overwritten until the fence signals. The fence // will usually be the one obtained from dequeueBuffer. virtual status_t cancelBuffer(int slot, const sp& fence); // Query native window attributes. The "what" values are enumerated in // window.h (e.g. NATIVE_WINDOW_FORMAT). virtual int query(int what, int* outValue); // connect attempts to connect a producer API to the BufferQueue. This // must be called before any other IGraphicBufferProducer methods are // called except for getAllocator. A consumer must already be connected. // // This method will fail if connect was previously called on the // BufferQueue and no corresponding disconnect call was made (i.e. if // it's still connected to a producer). // // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output); // disconnect attempts to disconnect a producer API from the BufferQueue. // Calling this method will cause any subsequent calls to other // IGraphicBufferProducer methods to fail except for getAllocator and connect. // Successfully calling connect after this will allow the other methods to // succeed again. // // This method will fail if the the BufferQueue is not currently // connected to the specified producer API. virtual status_t disconnect(int api); // Attaches a sideband buffer stream to the IGraphicBufferProducer. // // A sideband stream is a device-specific mechanism for passing buffers // from the producer to the consumer without using dequeueBuffer/ // queueBuffer. If a sideband stream is present, the consumer can choose // whether to acquire buffers from the sideband stream or from the queued // buffers. // // Passing NULL or a different stream handle will detach the previous // handle if any. virtual status_t setSidebandStream(const sp& stream); // See IGraphicBufferProducer::allocateBuffers virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); // See IGraphicBufferProducer::allowAllocation virtual status_t allowAllocation(bool allow); // See IGraphicBufferProducer::setGenerationNumber virtual status_t setGenerationNumber(uint32_t generationNumber); // See IGraphicBufferProducer::getConsumerName virtual String8 getConsumerName() const override; // See IGraphicBufferProducer::getNextFrameNumber virtual uint64_t getNextFrameNumber() const override; // See IGraphicBufferProducer::setSharedBufferMode virtual status_t setSharedBufferMode(bool sharedBufferMode) override; // See IGraphicBufferProducer::setAutoRefresh virtual status_t setAutoRefresh(bool autoRefresh) override; // See IGraphicBufferProducer::setDequeueTimeout virtual status_t setDequeueTimeout(nsecs_t timeout) override; // See IGraphicBufferProducer::getLastQueuedBuffer virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override; // See IGraphicBufferProducer::getUniqueId virtual status_t getUniqueId(uint64_t* outId) const override; private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); // Returns the slot of the next free buffer if one is available or // BufferQueueCore::INVALID_BUFFER_SLOT otherwise int getFreeBufferLocked() const; // Returns the next free slot if one is available or // BufferQueueCore::INVALID_BUFFER_SLOT otherwise int getFreeSlotLocked() const; // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may // block if there are no available slots and we are not in non-blocking // mode (producer and consumer controlled by the application). If it blocks, // it will release mCore->mMutex while blocked so that other operations on // the BufferQueue may succeed. enum class FreeSlotCaller { Dequeue, Attach, }; status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const; sp mCore; // This references mCore->mSlots. Lock mCore->mMutex while accessing. BufferQueueDefs::SlotsType& mSlots; // This is a cached copy of the name stored in the BufferQueueCore. // It's updated during connect and dequeueBuffer (which should catch // most updates). String8 mConsumerName; uint32_t mStickyTransform; // This saves the fence from the last queueBuffer, such that the // next queueBuffer call can throttle buffer production. The prior // queueBuffer's fence is not nessessarily available elsewhere, // since the previous buffer might have already been acquired. sp mLastQueueBufferFence; Rect mLastQueuedCrop; uint32_t mLastQueuedTransform; // Take-a-ticket system for ensuring that onFrame* callbacks are called in // the order that frames are queued. While the BufferQueue lock // (mCore->mMutex) is held, a ticket is retained by the producer. After // dropping the BufferQueue lock, the producer must wait on the condition // variable until the current callback ticket matches its retained ticket. Mutex mCallbackMutex; int mNextCallbackTicket; // Protected by mCore->mMutex int mCurrentCallbackTicket; // Protected by mCallbackMutex Condition mCallbackCondition; // Sets how long dequeueBuffer or attachBuffer will block if a buffer or // slot is not yet available. nsecs_t mDequeueTimeout; }; // class BufferQueueProducer } // namespace android #endif include/gui/BufferSlot.h0100644 0000000 0000000 00000016753 13077405420 014256 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_BUFFERSLOT_H #define ANDROID_GUI_BUFFERSLOT_H #include #include #include #include #include namespace android { class Fence; // BufferState tracks the states in which a buffer slot can be. struct BufferState { // All slots are initially FREE (not dequeued, queued, acquired, or shared). BufferState() : mDequeueCount(0), mQueueCount(0), mAcquireCount(0), mShared(false) { } uint32_t mDequeueCount; uint32_t mQueueCount; uint32_t mAcquireCount; bool mShared; // A buffer can be in one of five states, represented as below: // // | mShared | mDequeueCount | mQueueCount | mAcquireCount | // --------|---------|---------------|-------------|---------------| // FREE | false | 0 | 0 | 0 | // DEQUEUED| false | 1 | 0 | 0 | // QUEUED | false | 0 | 1 | 0 | // ACQUIRED| false | 0 | 0 | 1 | // SHARED | true | any | any | any | // // FREE indicates that the buffer is available to be dequeued by the // producer. The slot is "owned" by BufferQueue. It transitions to DEQUEUED // when dequeueBuffer is called. // // DEQUEUED indicates that the buffer has been dequeued by the producer, but // has not yet been queued or canceled. The producer may modify the // buffer's contents as soon as the associated release fence is signaled. // The slot is "owned" by the producer. It can transition to QUEUED (via // queueBuffer or attachBuffer) or back to FREE (via cancelBuffer or // detachBuffer). // // QUEUED indicates that the buffer has been filled by the producer and // queued for use by the consumer. The buffer contents may continue to be // modified for a finite time, so the contents must not be accessed until // the associated fence is signaled. The slot is "owned" by BufferQueue. It // can transition to ACQUIRED (via acquireBuffer) or to FREE (if another // buffer is queued in asynchronous mode). // // ACQUIRED indicates that the buffer has been acquired by the consumer. As // with QUEUED, the contents must not be accessed by the consumer until the // acquire fence is signaled. The slot is "owned" by the consumer. It // transitions to FREE when releaseBuffer (or detachBuffer) is called. A // detached buffer can also enter the ACQUIRED state via attachBuffer. // // SHARED indicates that this buffer is being used in shared buffer // mode. It can be in any combination of the other states at the same time, // except for FREE (since that excludes being in any other state). It can // also be dequeued, queued, or acquired multiple times. inline bool isFree() const { return !isAcquired() && !isDequeued() && !isQueued(); } inline bool isDequeued() const { return mDequeueCount > 0; } inline bool isQueued() const { return mQueueCount > 0; } inline bool isAcquired() const { return mAcquireCount > 0; } inline bool isShared() const { return mShared; } inline void reset() { *this = BufferState(); } const char* string() const; inline void dequeue() { mDequeueCount++; } inline void detachProducer() { if (mDequeueCount > 0) { mDequeueCount--; } } inline void attachProducer() { mDequeueCount++; } inline void queue() { if (mDequeueCount > 0) { mDequeueCount--; } mQueueCount++; } inline void cancel() { if (mDequeueCount > 0) { mDequeueCount--; } } inline void freeQueued() { if (mQueueCount > 0) { mQueueCount--; } } inline void acquire() { if (mQueueCount > 0) { mQueueCount--; } mAcquireCount++; } inline void acquireNotInQueue() { mAcquireCount++; } inline void release() { if (mAcquireCount > 0) { mAcquireCount--; } } inline void detachConsumer() { if (mAcquireCount > 0) { mAcquireCount--; } } inline void attachConsumer() { mAcquireCount++; } }; struct BufferSlot { BufferSlot() : mGraphicBuffer(nullptr), mEglDisplay(EGL_NO_DISPLAY), mBufferState(), mRequestBufferCalled(false), mFrameNumber(0), mEglFence(EGL_NO_SYNC_KHR), mFence(Fence::NO_FENCE), mAcquireCalled(false), mNeedsReallocation(false) { } // mGraphicBuffer points to the buffer allocated for this slot or is NULL // if no buffer has been allocated. sp mGraphicBuffer; // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects. EGLDisplay mEglDisplay; // mBufferState is the current state of this buffer slot. BufferState mBufferState; // mRequestBufferCalled is used for validating that the producer did // call requestBuffer() when told to do so. Technically this is not // needed but useful for debugging and catching producer bugs. bool mRequestBufferCalled; // mFrameNumber is the number of the queued frame for this slot. This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). uint64_t mFrameNumber; // mEglFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a // new sync object in releaseBuffer. (This is deprecated in favor of // mFence, below.) EGLSyncKHR mEglFence; // mFence is a fence which will signal when work initiated by the // previous owner of the buffer is finished. When the buffer is FREE, // the fence indicates when the consumer has finished reading // from the buffer, or when the producer has finished writing if it // called cancelBuffer after queueing some writes. When the buffer is // QUEUED, it indicates when the producer has finished filling the // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been // passed to the consumer or producer along with ownership of the // buffer, and mFence is set to NO_FENCE. sp mFence; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; // Indicates whether the buffer was re-allocated without notifying the // producer. If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when // dequeued to prevent the producer from using a stale cached buffer. bool mNeedsReallocation; }; } // namespace android #endif include/gui/ConsumerBase.h0100644 0000000 0000000 00000026572 13077405420 014571 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_CONSUMERBASE_H #define ANDROID_GUI_CONSUMERBASE_H #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class String8; // ConsumerBase is a base class for BufferQueue consumer end-points. It // handles common tasks like management of the connection to the BufferQueue // and the buffer pool. class ConsumerBase : public virtual RefBase, protected ConsumerListener { public: struct FrameAvailableListener : public virtual RefBase { // See IConsumerListener::onFrame{Available,Replaced} virtual void onFrameAvailable(const BufferItem& item) = 0; virtual void onFrameReplaced(const BufferItem& /* item */) {} }; virtual ~ConsumerBase(); // abandon frees all the buffers and puts the ConsumerBase into the // 'abandoned' state. Once put in this state the ConsumerBase can never // leave it. When in the 'abandoned' state, all methods of the // IGraphicBufferProducer interface will fail with the NO_INIT error. // // Note that while calling this method causes all the buffers to be freed // from the perspective of the the ConsumerBase, if there are additional // references on the buffers (e.g. if a buffer is referenced by a client // or by OpenGL ES as a texture) then those buffer will remain allocated. void abandon(); // Returns true if the ConsumerBase is in the 'abandoned' state bool isAbandoned(); // set the name of the ConsumerBase that will be used to identify it in // log messages. void setName(const String8& name); // dump writes the current state to a string. Child classes should add // their state to the dump by overriding the dumpLocked method, which is // called by these methods after locking the mutex. void dump(String8& result) const; void dump(String8& result, const char* prefix) const; // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. void setFrameAvailableListener(const wp& listener); // See IGraphicBufferConsumer::detachBuffer status_t detachBuffer(int slot); // See IGraphicBufferConsumer::setDefaultBufferSize status_t setDefaultBufferSize(uint32_t width, uint32_t height); // See IGraphicBufferConsumer::setDefaultBufferFormat status_t setDefaultBufferFormat(PixelFormat defaultFormat); // See IGraphicBufferConsumer::setDefaultBufferDataSpace status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); // See IGraphicBufferConsumer::discardFreeBuffers status_t discardFreeBuffers(); private: ConsumerBase(const ConsumerBase&); void operator=(const ConsumerBase&); protected: // ConsumerBase constructs a new ConsumerBase object to consume image // buffers from the given IGraphicBufferConsumer. // The controlledByApp flag indicates that this consumer is under the application's // control. ConsumerBase(const sp& consumer, bool controlledByApp = false); // onLastStrongRef gets called by RefBase just before the dtor of the most // derived class. It is used to clean up the buffers so that ConsumerBase // can coordinate the clean-up by calling into virtual methods implemented // by the derived classes. This would not be possible from the // ConsuemrBase dtor because by the time that gets called the derived // classes have already been destructed. // // This methods should not need to be overridden by derived classes, but // if they are overridden the ConsumerBase implementation must be called // from the derived class. virtual void onLastStrongRef(const void* id); // Implementation of the IConsumerListener interface. These // calls are used to notify the ConsumerBase of asynchronous events in the // BufferQueue. The onFrameAvailable, onFrameReplaced, and // onBuffersReleased methods should not need to be overridden by derived // classes, but if they are overridden the ConsumerBase implementation must // be called from the derived class. The ConsumerBase version of // onSidebandStreamChanged does nothing and can be overriden by derived // classes if they want the notification. virtual void onFrameAvailable(const BufferItem& item) override; virtual void onFrameReplaced(const BufferItem& item) override; virtual void onBuffersReleased() override; virtual void onSidebandStreamChanged() override; // freeBufferLocked frees up the given buffer slot. If the slot has been // initialized this will release the reference to the GraphicBuffer in that // slot. Otherwise it has no effect. // // Derived classes should override this method to clean up any state they // keep per slot. If it is overridden, the derived class's implementation // must call ConsumerBase::freeBufferLocked. // // This method must be called with mMutex locked. virtual void freeBufferLocked(int slotIndex); // abandonLocked puts the BufferQueue into the abandoned state, causing // all future operations on it to fail. This method rather than the public // abandon method should be overridden by child classes to add abandon- // time behavior. // // Derived classes should override this method to clean up any object // state they keep (as opposed to per-slot state). If it is overridden, // the derived class's implementation must call ConsumerBase::abandonLocked. // // This method must be called with mMutex locked. virtual void abandonLocked(); // dumpLocked dumps the current state of the ConsumerBase object to the // result string. Each line is prefixed with the string pointed to by the // prefix argument. The buffer argument points to a buffer that may be // used for intermediate formatting data, and the size of that buffer is // indicated by the size argument. // // Derived classes should override this method to dump their internal // state. If this method is overridden the derived class's implementation // should call ConsumerBase::dumpLocked. // // This method must be called with mMutex locked. virtual void dumpLocked(String8& result, const char* prefix) const; // acquireBufferLocked fetches the next buffer from the BufferQueue and // updates the buffer slot for the buffer returned. // // Derived classes should override this method to perform any // initialization that must take place the first time a buffer is assigned // to a slot. If it is overridden the derived class's implementation must // call ConsumerBase::acquireBufferLocked. virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber = 0); // releaseBufferLocked relinquishes control over a buffer, returning that // control to the BufferQueue. // // Derived classes should override this method to perform any cleanup that // must take place when a buffer is released back to the BufferQueue. If // it is overridden the derived class's implementation must call // ConsumerBase::releaseBufferLocked.e virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp graphicBuffer); // addReleaseFence* adds the sync points associated with a fence to the set // of sync points that must be reached before the buffer in the given slot // may be used after the slot has been released. This should be called by // derived classes each time some asynchronous work is kicked off that // references the buffer. status_t addReleaseFence(int slot, const sp graphicBuffer, const sp& fence); status_t addReleaseFenceLocked(int slot, const sp graphicBuffer, const sp& fence); // Slot contains the information and object references that // ConsumerBase maintains about a BufferQueue buffer slot. struct Slot { // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if // no Gralloc buffer is in the slot. sp mGraphicBuffer; // mFence is a fence which will signal when the buffer associated with // this buffer slot is no longer being used by the consumer and can be // overwritten. The buffer can be dequeued before the fence signals; // the producer is responsible for delaying writes until it signals. sp mFence; // the frame number of the last acquired frame for this slot uint64_t mFrameNumber; }; // mSlots stores the buffers that have been allocated by the BufferQueue // for each buffer slot. It is initialized to null pointers, and gets // filled in with the result of BufferQueue::acquire when the // client dequeues a buffer from a // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS]; // mAbandoned indicates that the BufferQueue will no longer be used to // consume images buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the abandon // method. A BufferQueue that has been abandoned will return the NO_INIT // error from all IConsumerBase methods capable of returning an error. bool mAbandoned; // mName is a string used to identify the ConsumerBase in log messages. // It can be set by the setName method. String8 mName; // mFrameAvailableListener is the listener object that will be called when a // new frame becomes available. If it is not NULL it will be called from // queueBuffer. wp mFrameAvailableListener; // The ConsumerBase has-a BufferQueue and is responsible for creating this object // if none is supplied sp mConsumer; // mMutex is the mutex used to prevent concurrent access to the member // variables of ConsumerBase objects. It must be locked whenever the // member variables are accessed or when any of the *Locked methods are // called. // // This mutex is intended to be locked by derived classes. mutable Mutex mMutex; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_CONSUMERBASE_H include/gui/CpuConsumer.h0100644 0000000 0000000 00000012147 13077405420 014437 0ustar000000000 0000000 /* * Copyright (C) 2012 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_GUI_CPUCONSUMER_H #define ANDROID_GUI_CPUCONSUMER_H #include #include #include #include #include namespace android { class BufferQueue; /** * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU * access to the underlying gralloc buffers provided by BufferQueue. Multiple * buffers may be acquired by it at once, to be used concurrently by the * CpuConsumer owner. Sets gralloc usage flags to be software-read-only. * This queue is synchronous by default. */ class CpuConsumer : public ConsumerBase { public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; struct LockedBuffer { uint8_t *data; uint32_t width; uint32_t height; PixelFormat format; uint32_t stride; Rect crop; uint32_t transform; uint32_t scalingMode; int64_t timestamp; android_dataspace dataSpace; uint64_t frameNumber; // this is the same as format, except for formats that are compatible with // a flexible format (e.g. HAL_PIXEL_FORMAT_YCbCr_420_888). In the latter // case this contains that flexible format PixelFormat flexFormat; // Values below are only valid when using HAL_PIXEL_FORMAT_YCbCr_420_888 // or compatible format, in which case LockedBuffer::data // contains the Y channel, and stride is the Y channel stride. For other // formats, these will all be 0. uint8_t *dataCb; uint8_t *dataCr; uint32_t chromaStride; uint32_t chromaStep; LockedBuffer() : data(NULL), width(0), height(0), format(PIXEL_FORMAT_NONE), stride(0), crop(Rect::EMPTY_RECT), transform(0), scalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), timestamp(0), dataSpace(HAL_DATASPACE_UNKNOWN), frameNumber(0), flexFormat(PIXEL_FORMAT_NONE), dataCb(NULL), dataCr(NULL), chromaStride(0), chromaStep(0) {} }; // Create a new CPU consumer. The maxLockedBuffers parameter specifies // how many buffers can be locked for user access at the same time. CpuConsumer(const sp& bq, size_t maxLockedBuffers, bool controlledByApp = false); virtual ~CpuConsumer(); // set the name of the CpuConsumer that will be used to identify it in // log messages. void setName(const String8& name); // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and // NOT_ENOUGH_DATA if the maximum number of buffers is already locked. // // Only a fixed number of buffers can be locked at a time, determined by the // construction-time maxLockedBuffers parameter. If INVALID_OPERATION is // returned by lockNextBuffer, then old buffers must be returned to the queue // by calling unlockBuffer before more buffers can be acquired. status_t lockNextBuffer(LockedBuffer *nativeBuffer); // Returns a locked buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be locked at a time, old buffers must // be released by calling unlockBuffer to ensure new buffers can be acquired by // lockNextBuffer. status_t unlockBuffer(const LockedBuffer &nativeBuffer); private: // Maximum number of buffers that can be locked at a time size_t mMaxLockedBuffers; status_t releaseAcquiredBufferLocked(size_t lockedIdx); virtual void freeBufferLocked(int slotIndex); // Tracking for buffers acquired by the user struct AcquiredBuffer { // Need to track the original mSlot index and the buffer itself because // the mSlot entry may be freed/reused before the acquired buffer is // released. int mSlot; sp mGraphicBuffer; void *mBufferPointer; AcquiredBuffer() : mSlot(BufferQueue::INVALID_BUFFER_SLOT), mBufferPointer(NULL) { } }; Vector mAcquiredBuffers; // Count of currently locked buffers size_t mCurrentLockedBuffers; }; } // namespace android #endif // ANDROID_GUI_CPUCONSUMER_H include/gui/DisplayEventReceiver.h0100644 0000000 0000000 00000007613 13077405420 016272 0ustar000000000 0000000 /* * 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_GUI_DISPLAY_EVENT_H #define ANDROID_GUI_DISPLAY_EVENT_H #include #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class BitTube; class IDisplayEventConnection; // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: enum { DISPLAY_EVENT_VSYNC = 'vsyn', DISPLAY_EVENT_HOTPLUG = 'plug' }; struct Event { struct Header { uint32_t type; uint32_t id; nsecs_t timestamp __attribute__((aligned(8))); }; struct VSync { uint32_t count; }; struct Hotplug { bool connected; }; Header header; union { VSync vsync; Hotplug hotplug; }; }; public: /* * DisplayEventReceiver creates and registers an event connection with * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate * or requestNextVsync to receive them. * Other events start being delivered immediately. */ DisplayEventReceiver(); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events * stop being delivered immediately. Note that the queue could have * some events pending. These will be delivered. */ ~DisplayEventReceiver(); /* * initCheck returns the state of DisplayEventReceiver after construction. */ status_t initCheck() const; /* * getFd returns the file descriptor to use to receive events. * OWNERSHIP IS RETAINED by DisplayEventReceiver. DO NOT CLOSE this * file-descriptor. */ int getFd() const; /* * getEvents reads events from the queue and returns how many events were * read. Returns 0 if there are no more events or a negative error code. * If NOT_ENOUGH_DATA is returned, the object has become invalid forever, it * should be destroyed and getEvents() shouldn't be called again. */ ssize_t getEvents(Event* events, size_t count); static ssize_t getEvents(const sp& dataChannel, Event* events, size_t count); /* * sendEvents write events to the queue and returns how many events were * written. */ static ssize_t sendEvents(const sp& dataChannel, Event const* events, size_t count); /* * setVsyncRate() sets the Event::VSync delivery rate. A value of * 1 returns every Event::VSync. A value of 2 returns every other event, * etc... a value of 0 returns no event unless requestNextVsync() has * been called. */ status_t setVsyncRate(uint32_t count); /* * requestNextVsync() schedules the next Event::VSync. It has no effect * if the vsync rate is > 0. */ status_t requestNextVsync(); private: sp mEventConnection; sp mDataChannel; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_DISPLAY_EVENT_H include/gui/GLConsumer.h0100644 0000000 0000000 00000055245 13077405420 014220 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_CONSUMER_H #define ANDROID_GUI_CONSUMER_H #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class String8; /* * GLConsumer consumes buffers of graphics data from a BufferQueue, * and makes them available to OpenGL as a texture. * * A typical usage pattern is to set up the GLConsumer with the * desired options, and call updateTexImage() when a new frame is desired. * If a new frame is available, the texture will be updated. If not, * the previous contents are retained. * * By default, the texture is attached to the GL_TEXTURE_EXTERNAL_OES * texture target, in the EGL context of the first thread that calls * updateTexImage(). * * This class was previously called SurfaceTexture. */ class GLConsumer : public ConsumerBase { public: enum { TEXTURE_EXTERNAL = 0x8D65 }; // GL_TEXTURE_EXTERNAL_OES typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; // GLConsumer constructs a new GLConsumer object. If the constructor with // the tex parameter is used, tex indicates the name of the OpenGL ES // texture to which images are to be streamed. texTarget specifies the // OpenGL ES texture target to which the texture will be bound in // updateTexImage. useFenceSync specifies whether fences should be used to // synchronize access to buffers if that behavior is enabled at // compile-time. // // A GLConsumer may be detached from one OpenGL ES context and then // attached to a different context using the detachFromContext and // attachToContext methods, respectively. The intention of these methods is // purely to allow a GLConsumer to be transferred from one consumer // context to another. If such a transfer is not needed there is no // requirement that either of these methods be called. // // If the constructor with the tex parameter is used, the GLConsumer is // created in a state where it is considered attached to an OpenGL ES // context for the purposes of the attachToContext and detachFromContext // methods. However, despite being considered "attached" to a context, the // specific OpenGL ES context doesn't get latched until the first call to // updateTexImage. After that point, all calls to updateTexImage must be // made with the same OpenGL ES context current. // // If the constructor without the tex parameter is used, the GLConsumer is // created in a detached state, and attachToContext must be called before // calls to updateTexImage. GLConsumer(const sp& bq, uint32_t tex, uint32_t texureTarget, bool useFenceSync, bool isControlledByApp); GLConsumer(const sp& bq, uint32_t texureTarget, bool useFenceSync, bool isControlledByApp); // updateTexImage acquires the most recently queued buffer, and sets the // image contents of the target texture to it. // // This call may only be made while the OpenGL ES context to which the // target texture belongs is bound to the calling thread. // // This calls doGLFenceWait to ensure proper synchronization. status_t updateTexImage(); // releaseTexImage releases the texture acquired in updateTexImage(). // This is intended to be used in single buffer mode. // // This call may only be made while the OpenGL ES context to which the // target texture belongs is bound to the calling thread. status_t releaseTexImage(); // setReleaseFence stores a fence that will signal when the current buffer // is no longer being read. This fence will be returned to the producer // when the current buffer is released by updateTexImage(). Multiple // fences can be set for a given buffer; they will be merged into a single // union fence. virtual void setReleaseFence(const sp& fence); // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix // associated with the texture image set by the most recent call to // updateTexImage. // // This transform matrix maps 2D homogeneous texture coordinates of the form // (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture // coordinate that should be used to sample that location from the texture. // Sampling the texture outside of the range of this transform is undefined. // // This transform is necessary to compensate for transforms that the stream // content producer may implicitly apply to the content. By forcing users of // a GLConsumer to apply this transform we avoid performing an extra // copy of the data that would be needed to hide the transform from the // user. // // The matrix is stored in column-major order so that it may be passed // directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv // functions. void getTransformMatrix(float mtx[16]); // Computes the transform matrix documented by getTransformMatrix // from the BufferItem sub parts. static void computeTransformMatrix(float outTransform[16], const sp& buf, const Rect& cropRect, uint32_t transform, bool filtering); // getTimestamp retrieves the timestamp associated with the texture image // set by the most recent call to updateTexImage. // // The timestamp is in nanoseconds, and is monotonically increasing. Its // other semantics (zero point, etc) are source-dependent and should be // documented by the source. int64_t getTimestamp(); // getFrameNumber retrieves the frame number associated with the texture // image set by the most recent call to updateTexImage. // // The frame number is an incrementing counter set to 0 at the creation of // the BufferQueue associated with this consumer. uint64_t getFrameNumber(); // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. // A call to setDefaultBufferSize() may trigger requestBuffers() to // be called from the client. // The width and height parameters must be no greater than the minimum of // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). // An error due to invalid dimensions might not be reported until // updateTexImage() is called. status_t setDefaultBufferSize(uint32_t width, uint32_t height); // setFilteringEnabled sets whether the transform matrix should be computed // for use with bilinear filtering. void setFilteringEnabled(bool enabled); // getCurrentBuffer returns the buffer associated with the current image. sp getCurrentBuffer() const; // getCurrentTextureTarget returns the texture target of the current // texture as returned by updateTexImage(). uint32_t getCurrentTextureTarget() const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; // getCurrentTransform returns the transform of the current buffer. uint32_t getCurrentTransform() const; // getCurrentScalingMode returns the scaling mode of the current buffer. uint32_t getCurrentScalingMode() const; // getCurrentFence returns the fence indicating when the current buffer is // ready to be read from. sp getCurrentFence() const; // doGLFenceWait inserts a wait command into the OpenGL ES command stream // to ensure that it is safe for future OpenGL ES commands to access the // current texture buffer. status_t doGLFenceWait() const; // set the name of the GLConsumer that will be used to identify it in // log messages. void setName(const String8& name); // These functions call the corresponding BufferQueue implementation // so the refactoring can proceed smoothly status_t setDefaultBufferFormat(PixelFormat defaultFormat); status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); status_t setConsumerUsageBits(uint32_t usage); status_t setTransformHint(uint32_t hint); status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context // that was current for previous calls to updateTexImage. // // Detaching a GLConsumer from an OpenGL ES context will result in the // deletion of the OpenGL ES texture object into which the images were being // streamed. After a GLConsumer has been detached from the OpenGL ES // context calls to updateTexImage will fail returning INVALID_OPERATION // until the GLConsumer is attached to a new OpenGL ES context using the // attachToContext method. status_t detachFromContext(); // attachToContext attaches a GLConsumer that is currently in the // 'detached' state to the current OpenGL ES context. A GLConsumer is // in the 'detached' state iff detachFromContext has successfully been // called and no calls to attachToContext have succeeded since the last // detachFromContext call. Calls to attachToContext made on a // GLConsumer that is not in the 'detached' state will result in an // INVALID_OPERATION error. // // The tex argument specifies the OpenGL ES texture object name in the // new context into which the image contents will be streamed. A successful // call to attachToContext will result in this texture object being bound to // the texture target and populated with the image contents that were // current at the time of the last call to detachFromContext. status_t attachToContext(uint32_t tex); protected: // abandonLocked overrides the ConsumerBase method to clear // mCurrentTextureImage in addition to the ConsumerBase behavior. virtual void abandonLocked(); // dumpLocked overrides the ConsumerBase method to dump GLConsumer- // specific info in addition to the ConsumerBase behavior. virtual void dumpLocked(String8& result, const char* prefix) const; // acquireBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase behavior. virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) override; // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence); status_t releaseBufferLocked(int slot, const sp graphicBuffer, EGLSyncKHR eglFence) { return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } static bool isExternalFormat(PixelFormat format); struct PendingRelease { PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer(), display(nullptr), fence(nullptr) {} bool isPending; int currentTexture; sp graphicBuffer; EGLDisplay display; EGLSyncKHR fence; }; // This releases the buffer in the slot referenced by mCurrentTexture, // then updates state to refer to the BufferItem, which must be a // newly-acquired buffer. If pendingRelease is not null, the parameters // which would have been passed to releaseBufferLocked upon the successful // completion of the method will instead be returned to the caller, so that // it may call releaseBufferLocked itself later. status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease = nullptr); // Binds mTexName and the current buffer to mTexTarget. Uses // mCurrentTexture if it's set, mCurrentTextureImage if not. If the // bind succeeds, this calls doGLFenceWait. status_t bindTextureImageLocked(); // Gets the current EGLDisplay and EGLContext values, and compares them // to mEglDisplay and mEglContext. If the fields have been previously // set, the values must match; if not, the fields are set to the current // values. // The contextCheck argument is used to ensure that a GL context is // properly set; when set to false, the check is not performed. status_t checkAndUpdateEglStateLocked(bool contextCheck = false); private: // EglImage is a utility class for tracking and creating EGLImageKHRs. There // is primarily just one image per slot, but there is also special cases: // - For releaseTexImage, we use a debug image (mReleasedTexImage) // - After freeBuffer, we must still keep the current image/buffer // Reference counting EGLImages lets us handle all these cases easily while // also only creating new EGLImages from buffers when required. class EglImage : public LightRefBase { public: EglImage(sp graphicBuffer); // createIfNeeded creates an EGLImage if required (we haven't created // one yet, or the EGLDisplay or crop-rect has changed). status_t createIfNeeded(EGLDisplay display, const Rect& cropRect, bool forceCreate = false); // This calls glEGLImageTargetTexture2DOES to bind the image to the // texture in the specified texture target. void bindToTextureTarget(uint32_t texTarget); const sp& graphicBuffer() { return mGraphicBuffer; } const native_handle* graphicBufferHandle() { return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle; } private: // Only allow instantiation using ref counting. friend class LightRefBase; virtual ~EglImage(); // createImage creates a new EGLImage from a GraphicBuffer. EGLImageKHR createImage(EGLDisplay dpy, const sp& graphicBuffer, const Rect& crop); // Disallow copying EglImage(const EglImage& rhs); void operator = (const EglImage& rhs); // mGraphicBuffer is the buffer that was used to create this image. sp mGraphicBuffer; // mEglImage is the EGLImage created from mGraphicBuffer. EGLImageKHR mEglImage; // mEGLDisplay is the EGLDisplay that was used to create mEglImage. EGLDisplay mEglDisplay; // mCropRect is the crop rectangle passed to EGL when mEglImage // was created. Rect mCropRect; }; // freeBufferLocked frees up the given buffer slot. If the slot has been // initialized this will release the reference to the GraphicBuffer in that // slot and destroy the EGLImage in that slot. Otherwise it has no effect. // // This method must be called with mMutex locked. virtual void freeBufferLocked(int slotIndex); // computeCurrentTransformMatrixLocked computes the transform matrix for the // current texture. It uses mCurrentTransform and the current GraphicBuffer // to compute this matrix and stores it in mCurrentTransformMatrix. // mCurrentTextureImage must not be NULL. void computeCurrentTransformMatrixLocked(); // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command // stream to ensure that it is safe for future OpenGL ES commands to // access the current texture buffer. status_t doGLFenceWaitLocked() const; // syncForReleaseLocked performs the synchronization needed to release the // current slot from an OpenGL ES context. If needed it will set the // current slot's fence to guard against a producer accessing the buffer // before the outstanding accesses have completed. status_t syncForReleaseLocked(EGLDisplay dpy); // returns a graphic buffer used when the texture image has been released static sp getDebugTexImageBuffer(); // The default consumer usage flags that GLConsumer always sets on its // BufferQueue instance; these will be OR:d with any additional flags passed // from the GLConsumer user. In particular, GLConsumer will always // consume buffers as hardware textures. static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; // mCurrentTextureImage is the EglImage/buffer of the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. sp mCurrentTextureImage; // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. Rect mCurrentCrop; // mCurrentTransform is the transform identifier for the current texture. It // gets set each time updateTexImage is called. uint32_t mCurrentTransform; // mCurrentScalingMode is the scaling mode for the current texture. It gets // set each time updateTexImage is called. uint32_t mCurrentScalingMode; // mCurrentFence is the fence received from BufferQueue in updateTexImage. sp mCurrentFence; // mCurrentTransformMatrix is the transform matrix for the current texture. // It gets computed by computeTransformMatrix each time updateTexImage is // called. float mCurrentTransformMatrix[16]; // mCurrentTimestamp is the timestamp for the current texture. It // gets set each time updateTexImage is called. int64_t mCurrentTimestamp; // mCurrentFrameNumber is the frame counter for the current texture. // It gets set each time updateTexImage is called. uint64_t mCurrentFrameNumber; uint32_t mDefaultWidth, mDefaultHeight; // mFilteringEnabled indicates whether the transform matrix is computed for // use with bilinear filtering. It defaults to true and is changed by // setFilteringEnabled(). bool mFilteringEnabled; // mTexName is the name of the OpenGL texture to which streamed images will // be bound when updateTexImage is called. It is set at construction time // and can be changed with a call to attachToContext. uint32_t mTexName; // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync // extension should be used to prevent buffers from being dequeued before // it's safe for them to be written. It gets set at construction time and // never changes. const bool mUseFenceSync; // mTexTarget is the GL texture target with which the GL texture object is // associated. It is set in the constructor and never changed. It is // almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android // Browser. In that case it is set to GL_TEXTURE_2D to allow // glCopyTexSubImage to read from the texture. This is a hack to work // around a GL driver limitation on the number of FBO attachments, which the // browser's tile cache exceeds. const uint32_t mTexTarget; // EGLSlot contains the information and object references that // GLConsumer maintains about a BufferQueue buffer slot. struct EglSlot { EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} // mEglImage is the EGLImage created from mGraphicBuffer. sp mEglImage; // mFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based // on a compile-time option) set to a new sync object in updateTexImage. EGLSyncKHR mEglFence; }; // mEglDisplay is the EGLDisplay with which this GLConsumer is currently // associated. It is intialized to EGL_NO_DISPLAY and gets set to the // current display when updateTexImage is called for the first time and when // attachToContext is called. EGLDisplay mEglDisplay; // mEglContext is the OpenGL ES context with which this GLConsumer is // currently associated. It is initialized to EGL_NO_CONTEXT and gets set // to the current GL context when updateTexImage is called for the first // time and when attachToContext is called. EGLContext mEglContext; // mEGLSlots stores the buffers that have been allocated by the BufferQueue // for each buffer slot. It is initialized to null pointers, and gets // filled in with the result of BufferQueue::acquire when the // client dequeues a buffer from a // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. EglSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS]; // mCurrentTexture is the buffer slot index of the buffer that is currently // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, // indicating that no buffer slot is currently bound to the texture. Note, // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean // that no buffer is bound to the texture. A call to setBufferCount will // reset mCurrentTexture to INVALID_BUFFER_SLOT. int mCurrentTexture; // mAttached indicates whether the ConsumerBase is currently attached to // an OpenGL ES context. For legacy reasons, this is initialized to true, // indicating that the ConsumerBase is considered to be attached to // whatever context is current at the time of the first updateTexImage call. // It is set to false by detachFromContext, and then set to true again by // attachToContext. bool mAttached; // protects static initialization static Mutex sStaticInitLock; // mReleasedTexImageBuffer is a dummy buffer used when in single buffer // mode and releaseTexImage() has been called static sp sReleasedTexImageBuffer; sp mReleasedTexImage; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_CONSUMER_H include/gui/GraphicBufferAlloc.h0100644 0000000 0000000 00000002574 13077405420 015661 0ustar000000000 0000000 /* * Copyright (C) 2012 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_SF_GRAPHIC_BUFFER_ALLOC_H #define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class GraphicBuffer; class GraphicBufferAlloc : public BnGraphicBufferAlloc { public: GraphicBufferAlloc(); virtual ~GraphicBufferAlloc(); virtual sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, status_t* error); }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H include/gui/GuiConfig.h0100644 0000000 0000000 00000001574 13077405420 014050 0ustar000000000 0000000 /* * Copyright (C) 2012 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_GUI_CONFIG_H #define ANDROID_GUI_CONFIG_H #include namespace android { // Append the libgui configuration details to configStr. void appendGuiConfigString(String8& configStr); }; // namespace android #endif /*ANDROID_GUI_CONFIG_H*/ include/gui/IConsumerListener.h0100644 0000000 0000000 00000010157 13077405420 015605 0ustar000000000 0000000 /* * Copyright (C) 2013 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_GUI_ICONSUMERLISTENER_H #define ANDROID_GUI_ICONSUMERLISTENER_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class BufferItem; // ConsumerListener is the interface through which the BufferQueue notifies // the consumer of events that the consumer may wish to react to. Because // the consumer will generally have a mutex that is locked during calls from // the consumer to the BufferQueue, these calls from the BufferQueue to the // consumer *MUST* be called only when the BufferQueue mutex is NOT locked. class ConsumerListener : public virtual RefBase { public: ConsumerListener() { } virtual ~ConsumerListener() { } // onFrameAvailable is called from queueBuffer each time an additional // frame becomes available for consumption. This means that frames that // are queued while in asynchronous mode only trigger the callback if no // previous frames are pending. Frames queued while in synchronous mode // always trigger the callback. The item passed to the callback will contain // all of the information about the queued frame except for its // GraphicBuffer pointer, which will always be null. // // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */ // onFrameReplaced is called from queueBuffer if the frame being queued is // replacing an existing slot in the queue. Any call to queueBuffer that // doesn't call onFrameAvailable will call this callback instead. The item // passed to the callback will contain all of the information about the // queued frame except for its GraphicBuffer pointer, which will always be // null. // // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */ // onBuffersReleased is called to notify the buffer consumer that the // BufferQueue has released its references to one or more GraphicBuffers // contained in its slots. The buffer consumer should then call // BufferQueue::getReleasedBuffers to retrieve the list of buffers // // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onBuffersReleased() = 0; /* Asynchronous */ // onSidebandStreamChanged is called to notify the buffer consumer that the // BufferQueue's sideband buffer stream has changed. This is called when a // stream is first attached and when it is either detached or replaced by a // different stream. virtual void onSidebandStreamChanged() = 0; /* Asynchronous */ }; class IConsumerListener : public ConsumerListener, public IInterface { public: DECLARE_META_INTERFACE(ConsumerListener); }; // ---------------------------------------------------------------------------- class BnConsumerListener : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_ICONSUMERLISTENER_H include/gui/IDisplayEventConnection.h0100644 0000000 0000000 00000004324 13077405420 016732 0ustar000000000 0000000 /* * 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_GUI_IDISPLAY_EVENT_CONNECTION_H #define ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class BitTube; class IDisplayEventConnection : public IInterface { public: DECLARE_META_INTERFACE(DisplayEventConnection); /* * getDataChannel() returns a BitTube where to receive the events from */ virtual sp getDataChannel() const = 0; /* * setVsyncRate() sets the vsync event delivery rate. A value of * 1 returns every vsync events. A value of 2 returns every other events, * etc... a value of 0 returns no event unless requestNextVsync() has * been called. */ virtual void setVsyncRate(uint32_t count) = 0; /* * requestNextVsync() schedules the next vsync event. It has no effect * if the vsync rate is > 0. */ virtual void requestNextVsync() = 0; // asynchronous }; // ---------------------------------------------------------------------------- class BnDisplayEventConnection : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H include/gui/IGraphicBufferAlloc.h0100644 0000000 0000000 00000003405 13077405420 015764 0ustar000000000 0000000 /* * 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_GUI_IGRAPHIC_BUFFER_ALLOC_H #define ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class GraphicBuffer; class IGraphicBufferAlloc : public IInterface { public: DECLARE_META_INTERFACE(GraphicBufferAlloc); /* Create a new GraphicBuffer for the client to use. */ virtual sp createGraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, status_t* error) = 0; }; // ---------------------------------------------------------------------------- class BnGraphicBufferAlloc : public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H include/gui/IGraphicBufferConsumer.h0100644 0000000 0000000 00000033074 13077405420 016532 0ustar000000000 0000000 /* * Copyright (C) 2013 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_GUI_IGRAPHICBUFFERCONSUMER_H #define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H #include #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class BufferItem; class Fence; class GraphicBuffer; class IConsumerListener; class NativeHandle; class IGraphicBufferConsumer : public IInterface { public: enum { // Returned by releaseBuffer, after which the consumer must // free any references to the just-released buffer that it might have. STALE_BUFFER_SLOT = 1, // Returned by dequeueBuffer if there are no pending buffers available. NO_BUFFER_AVAILABLE, // Returned by dequeueBuffer if it's too early for the buffer to be acquired. PRESENT_LATER, }; // acquireBuffer attempts to acquire ownership of the next pending buffer in // the BufferQueue. If no buffer is pending then it returns // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the // information about the buffer is returned in BufferItem. // // If the buffer returned had previously been // acquired then the BufferItem::mGraphicBuffer field of buffer is set to // NULL and it is assumed that the consumer still holds a reference to the // buffer. // // If presentWhen is non-zero, it indicates the time when the buffer will // be displayed on screen. If the buffer's timestamp is farther in the // future, the buffer won't be acquired, and PRESENT_LATER will be // returned. The presentation time is in nanoseconds, and the time base // is CLOCK_MONOTONIC. // // If maxFrameNumber is non-zero, it indicates that acquireBuffer should // only return a buffer with a frame number less than or equal to // maxFrameNumber. If no such frame is available (such as when a buffer has // been replaced but the consumer has not received the onFrameReplaced // callback), then PRESENT_LATER will be returned. // // Return of NO_ERROR means the operation completed as normal. // // Return of a positive value means the operation could not be completed // at this time, but the user should try again later: // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer) // * PRESENT_LATER - the buffer's timestamp is farther in the future // // Return of a negative value means an error has occurred: // * INVALID_OPERATION - too many buffers have been acquired virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be // freed, and there will be no way to obtain the buffer from this interface. // The freed slot will remain unallocated until either it is selected to // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached // to the slot. The buffer must have already been acquired. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - the given slot number is invalid, either because it is // out of the range [0, NUM_BUFFER_SLOTS) or because the slot // it refers to is not currently acquired. virtual status_t detachBuffer(int slot) = 0; // attachBuffer attempts to transfer ownership of a buffer to the buffer // queue. If this call succeeds, it will be as if this buffer was acquired // from the returned slot number. As such, this call will fail if attaching // this buffer would cause too many buffers to be simultaneously acquired. // // If the buffer is successfully attached, its frameNumber is initialized // to 0. This must be passed into the releaseBuffer call or else the buffer // will be deallocated as stale. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of // the buffer did not match the buffer queue. // * INVALID_OPERATION - cannot attach the buffer because it would cause too // many buffers to be acquired. // * NO_MEMORY - no free slots available virtual status_t attachBuffer(int *outSlot, const sp& buffer) = 0; // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer // in use. frameNumber is used to indentify the exact buffer returned. // // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free // any references to the just-released buffer that it might have, as if it // had received a onBuffersReleased() call with a mask set for the released // buffer. // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. // // Return of NO_ERROR means the operation completed as normal. // // Return of a positive value means the operation could not be completed // at this time, but the user should try again later: // * STALE_BUFFER_SLOT - see above (second paragraph) // // Return of a negative value means an error has occurred: // * BAD_VALUE - one of the following could've happened: // * the buffer slot was invalid // * the fence was NULL // * the buffer slot specified is not in the acquired state virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp& releaseFence) = 0; // consumerConnect connects a consumer to the BufferQueue. Only one // consumer may be connected, and when that consumer disconnects the // BufferQueue is placed into the "abandoned" state, causing most // interactions with the BufferQueue by the producer to fail. // controlledByApp indicates whether the consumer is controlled by // the application. // // consumer may not be NULL. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned // * BAD_VALUE - a NULL consumer was provided virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) = 0; // consumerDisconnect disconnects a consumer from the BufferQueue. All // buffers will be freed and the BufferQueue is placed in the "abandoned" // state, causing most interactions with the BufferQueue by the producer to // fail. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - no consumer is currently connected virtual status_t consumerDisconnect() = 0; // getReleasedBuffers sets the value pointed to by slotMask to a bit set. // Each bit index with a 1 corresponds to a released buffer slot with that // index value. In particular, a released buffer is one that has // been released by the BufferQueue but have not yet been released by the consumer. // // This should be called from the onBuffersReleased() callback. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; // setDefaultBufferSize is used to set the size of buffers returned by // dequeueBuffer when a width and height of zero is requested. Default // is 1x1. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - either w or h was zero virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; // setMaxBufferCount sets the maximum value for the number of buffers used // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode // or setMaxDequeuedBufferCount (by the producer), would cause this value to // be exceeded then that call will fail. This call will fail if a producer // is connected to the BufferQueue. // // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count // cannot be less than maxAcquiredBufferCount. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - one of the below conditions occurred: // * bufferCount was out of range (see above). // * failure to adjust the number of available slots. // * INVALID_OPERATION - attempting to call this after a producer connected. virtual status_t setMaxBufferCount(int bufferCount) = 0; // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). If this method // succeeds, any new buffer slots will be both unallocated and owned by the // BufferQueue object (i.e. they are not owned by the producer or consumer). // Calling this may also cause some buffer slots to be emptied. // // This function should not be called with a value of maxAcquiredBuffers // that is less than the number of currently acquired buffer slots. Doing so // will result in a BAD_VALUE error. // // maxAcquiredBuffers must be (inclusive) between 1 and // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value // to be exceeded. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned // * BAD_VALUE - one of the below conditions occurred: // * maxAcquiredBuffers was out of range (see above). // * failure to adjust the number of available slots. // * client would have more than the requested number of // acquired buffers after this call // * INVALID_OPERATION - attempting to call this after a producer connected. virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; // setConsumerName sets the name used in logging virtual void setConsumerName(const String8& name) = 0; // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // in dequeueBuffer. // The initial default is PIXEL_FORMAT_RGBA_8888. // // Return of a value other than NO_ERROR means an unknown error has occurred. virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0; // setDefaultBufferDataSpace is a request to the producer to provide buffers // of the indicated dataSpace. The producer may ignore this request. // The initial default is HAL_DATASPACE_UNKNOWN. // // Return of a value other than NO_ERROR means an unknown error has occurred. virtual status_t setDefaultBufferDataSpace( android_dataspace defaultDataSpace) = 0; // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. // These are merged with the bits passed to dequeueBuffer. The values are // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. // // Return of a value other than NO_ERROR means an unknown error has occurred. virtual status_t setConsumerUsageBits(uint32_t usage) = 0; // setTransformHint bakes in rotation to buffers so overlays can be used. // The values are enumerated in window.h, e.g. // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). // // Return of a value other than NO_ERROR means an unknown error has occurred. virtual status_t setTransformHint(uint32_t hint) = 0; // Retrieve the sideband buffer stream, if any. virtual sp getSidebandStream() const = 0; // discardFreeBuffers releases all currently-free buffers held by the queue, // in order to reduce the memory consumption of the queue to the minimum // possible without discarding data. virtual status_t discardFreeBuffers() = 0; // dump state into a string virtual void dump(String8& result, const char* prefix) const = 0; public: DECLARE_META_INTERFACE(GraphicBufferConsumer); }; // ---------------------------------------------------------------------------- class BnGraphicBufferConsumer : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H include/gui/IGraphicBufferProducer.h0100644 0000000 0000000 00000071277 13077405420 016531 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_IGRAPHICBUFFERPRODUCER_H #define ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class IProducerListener; class NativeHandle; class Surface; /* * This class defines the Binder IPC interface for the producer side of * a queue of graphics buffers. It's used to send graphics data from one * component to another. For example, a class that decodes video for * playback might use this to provide frames. This is typically done * indirectly, through Surface. * * The underlying mechanism is a BufferQueue, which implements * BnGraphicBufferProducer. In normal operation, the producer calls * dequeueBuffer() to get an empty buffer, fills it with data, then * calls queueBuffer() to make it available to the consumer. * * This class was previously called ISurfaceTexture. */ class IGraphicBufferProducer : public IInterface { public: DECLARE_META_INTERFACE(GraphicBufferProducer); enum { // A flag returned by dequeueBuffer when the client needs to call // requestBuffer immediately thereafter. BUFFER_NEEDS_REALLOCATION = 0x1, // A flag returned by dequeueBuffer when all mirrored slots should be // released by the client. This flag should always be processed first. RELEASE_ALL_BUFFERS = 0x2, }; // requestBuffer requests a new buffer for the given index. The server (i.e. // the IGraphicBufferProducer implementation) assigns the newly created // buffer to the given slot index, and the client is expected to mirror the // slot->buffer mapping so that it's not necessary to transfer a // GraphicBuffer for every dequeue operation. // // The slot must be in the range of [0, NUM_BUFFER_SLOTS). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - one of the two conditions occurred: // * slot was out of range (see above) // * buffer specified by the slot is not dequeued virtual status_t requestBuffer(int slot, sp* buf) = 0; // setMaxDequeuedBufferCount sets the maximum number of buffers that can be // dequeued by the producer at one time. If this method succeeds, any new // buffer slots will be both unallocated and owned by the BufferQueue object // (i.e. they are not owned by the producer or consumer). Calling this may // also cause some buffer slots to be emptied. If the caller is caching the // contents of the buffer slots, it should empty that cache after calling // this method. // // This function should not be called with a value of maxDequeuedBuffers // that is less than the number of currently dequeued buffer slots. Doing so // will result in a BAD_VALUE error. // // The buffer count should be at least 1 (inclusive), but at most // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The // minimum undequeued buffer count can be obtained by calling // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. // * BAD_VALUE - one of the below conditions occurred: // * bufferCount was out of range (see above). // * client would have more than the requested number of dequeued // buffers after this call. // * this call would cause the maxBufferCount value to be exceeded. // * failure to adjust the number of available slots. virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0; // Set the async flag if the producer intends to asynchronously queue // buffers without blocking. Typically this is used for triple-buffering // and/or when the swap interval is set to zero. // // Enabling async mode will internally allocate an additional buffer to // allow for the asynchronous behavior. If it is not enabled queue/dequeue // calls may block. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. // * BAD_VALUE - one of the following has occurred: // * this call would cause the maxBufferCount value to be // exceeded // * failure to adjust the number of available slots. virtual status_t setAsyncMode(bool async) = 0; // dequeueBuffer requests a new buffer slot for the client to use. Ownership // of the slot is transfered to the client, meaning that the server will not // use the contents of the buffer associated with that slot. // // The slot index returned may or may not contain a buffer (client-side). // If the slot is empty the client should call requestBuffer to assign a new // buffer to that slot. // // Once the client is done filling this buffer, it is expected to transfer // buffer ownership back to the server with either cancelBuffer on // the dequeued slot or to fill in the contents of its associated buffer // contents and call queueBuffer. // // If dequeueBuffer returns the BUFFER_NEEDS_REALLOCATION flag, the client is // expected to call requestBuffer immediately. // // If dequeueBuffer returns the RELEASE_ALL_BUFFERS flag, the client is // expected to release all of the mirrored slot->buffer mappings. // // The fence parameter will be updated to hold the fence associated with // the buffer. The contents of the buffer must not be overwritten until the // fence signals. If the fence is Fence::NO_FENCE, the buffer may be written // immediately. // // The width and height parameters must be no greater than the minimum of // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). // An error due to invalid dimensions might not be reported until // updateTexImage() is called. If width and height are both zero, the // default values specified by setDefaultBufferSize() are used instead. // // If the format is 0, the default format will be used. // // The usage argument specifies gralloc buffer usage flags. The values // are enumerated in , e.g. GRALLOC_USAGE_HW_RENDER. These // will be merged with the usage flags specified by // IGraphicBufferConsumer::setConsumerUsageBits. // // This call will block until a buffer is available to be dequeued. If // both the producer and consumer are controlled by the app, then this call // can never block and will return WOULD_BLOCK if no buffer is available. // // A non-negative value with flags set (see above) will be returned upon // success. // // Return of a negative means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - both in async mode and buffer count was less than the // max numbers of buffers that can be allocated at once. // * INVALID_OPERATION - cannot attach the buffer because it would cause // too many buffers to be dequeued, either because // the producer already has a single buffer dequeued // and did not set a buffer count, or because a // buffer count was set and this call would cause // it to be exceeded. // * WOULD_BLOCK - no buffer is currently available, and blocking is disabled // since both the producer/consumer are controlled by app // * NO_MEMORY - out of memory, cannot allocate the graphics buffer. // * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while // waiting for a buffer to become available. // // All other negative values are an unknown error returned downstream // from the graphics allocator (typically errno). virtual status_t dequeueBuffer(int* slot, sp* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be // freed, and there will be no way to obtain the buffer from this interface. // The freed slot will remain unallocated until either it is selected to // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached // to the slot. The buffer must have already been dequeued, and the caller // must already possesses the sp (i.e., must have called // requestBuffer). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - the given slot number is invalid, either because it is // out of the range [0, NUM_BUFFER_SLOTS), or because the slot // it refers to is not currently dequeued and requested. virtual status_t detachBuffer(int slot) = 0; // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, // and detachBuffer in sequence, except for two things: // // 1) It is unnecessary to know the dimensions, format, or usage of the // next buffer. // 2) It will not block, since if it cannot find an appropriate buffer to // return, it will return an error instead. // // Only slots that are free but still contain a GraphicBuffer will be // considered, and the oldest of those will be returned. outBuffer is // equivalent to outBuffer from the requestBuffer call, and outFence is // equivalent to fence from the dequeueBuffer call. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - either outBuffer or outFence were NULL. // * NO_MEMORY - no slots were found that were both free and contained a // GraphicBuffer. virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence) = 0; // attachBuffer attempts to transfer ownership of a buffer to the buffer // queue. If this call succeeds, it will be as if this buffer was dequeued // from the returned slot number. As such, this call will fail if attaching // this buffer would cause too many buffers to be simultaneously dequeued. // // If attachBuffer returns the RELEASE_ALL_BUFFERS flag, the caller is // expected to release all of the mirrored slot->buffer mappings. // // A non-negative value with flags set (see above) will be returned upon // success. // // Return of a negative value means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - outSlot or buffer were NULL, invalid combination of // async mode and buffer count override, or the generation // number of the buffer did not match the buffer queue. // * INVALID_OPERATION - cannot attach the buffer because it would cause // too many buffers to be dequeued, either because // the producer already has a single buffer dequeued // and did not set a buffer count, or because a // buffer count was set and this call would cause // it to be exceeded. // * WOULD_BLOCK - no buffer slot is currently available, and blocking is // disabled since both the producer/consumer are // controlled by the app. // * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while // waiting for a slot to become available. virtual status_t attachBuffer(int* outSlot, const sp& buffer) = 0; // queueBuffer indicates that the client has finished filling in the // contents of the buffer associated with slot and transfers ownership of // that slot back to the server. // // It is not valid to call queueBuffer on a slot that is not owned // by the client or one for which a buffer associated via requestBuffer // (an attempt to do so will fail with a return value of BAD_VALUE). // // In addition, the input must be described by the client (as documented // below). Any other properties (zero point, etc) // are client-dependent, and should be documented by the client. // // The slot must be in the range of [0, NUM_BUFFER_SLOTS). // // Upon success, the output will be filled with meaningful values // (refer to the documentation below). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - one of the below conditions occurred: // * fence was NULL // * scaling mode was unknown // * both in async mode and buffer count was less than the // max numbers of buffers that can be allocated at once // * slot index was out of range (see above). // * the slot was not in the dequeued state // * the slot was enqueued without requesting a buffer // * crop rect is out of bounds of the buffer dimensions struct QueueBufferInput : public Flattenable { friend class Flattenable; inline QueueBufferInput(const Parcel& parcel); // timestamp - a monotonically increasing value in nanoseconds // isAutoTimestamp - if the timestamp was synthesized at queue time // dataSpace - description of the contents, interpretation depends on format // crop - a crop rectangle that's used as a hint to the consumer // scalingMode - a set of flags from NATIVE_WINDOW_SCALING_* in // transform - a set of flags from NATIVE_WINDOW_TRANSFORM_* in // fence - a fence that the consumer must wait on before reading the buffer, // set this to Fence::NO_FENCE if the buffer is ready immediately // sticky - the sticky transform set in Surface (only used by the LEGACY // camera mode). inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp, android_dataspace dataSpace, const Rect& crop, int scalingMode, uint32_t transform, const sp& fence, uint32_t sticky = 0) : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), dataSpace(dataSpace), crop(crop), scalingMode(scalingMode), transform(transform), stickyTransform(sticky), fence(fence), surfaceDamage() { } inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, android_dataspace* outDataSpace, Rect* outCrop, int* outScalingMode, uint32_t* outTransform, sp* outFence, uint32_t* outStickyTransform = NULL) const { *outTimestamp = timestamp; *outIsAutoTimestamp = bool(isAutoTimestamp); *outDataSpace = dataSpace; *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; *outFence = fence; if (outStickyTransform != NULL) { *outStickyTransform = stickyTransform; } } // Flattenable protocol size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); const Region& getSurfaceDamage() const { return surfaceDamage; } void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; } private: int64_t timestamp; int isAutoTimestamp; android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; uint32_t stickyTransform; sp fence; Region surfaceDamage; }; // QueueBufferOutput must be a POD structure struct __attribute__ ((__packed__)) QueueBufferOutput { inline QueueBufferOutput() { } // outWidth - filled with default width applied to the buffer // outHeight - filled with default height applied to the buffer // outTransformHint - filled with default transform applied to the buffer // outNumPendingBuffers - num buffers queued that haven't yet been acquired // (counting the currently queued buffer) inline void deflate(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransformHint, uint32_t* outNumPendingBuffers) const { *outWidth = width; *outHeight = height; *outTransformHint = transformHint; *outNumPendingBuffers = numPendingBuffers; } inline void inflate(uint32_t inWidth, uint32_t inHeight, uint32_t inTransformHint, uint32_t inNumPendingBuffers) { width = inWidth; height = inHeight; transformHint = inTransformHint; numPendingBuffers = inNumPendingBuffers; } private: uint32_t width; uint32_t height; uint32_t transformHint; uint32_t numPendingBuffers; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) = 0; // cancelBuffer indicates that the client does not wish to fill in the // buffer associated with slot and transfers ownership of the slot back to // the server. // // The buffer is not queued for use by the consumer. // // The slot must be in the range of [0, NUM_BUFFER_SLOTS). // // The buffer will not be overwritten until the fence signals. The fence // will usually be the one obtained from dequeueBuffer. // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned or the producer is not // connected. // * BAD_VALUE - one of the below conditions occurred: // * fence was NULL // * slot index was out of range (see above). // * the slot was not in the dequeued state virtual status_t cancelBuffer(int slot, const sp& fence) = 0; // query retrieves some information for this surface // 'what' tokens allowed are that of NATIVE_WINDOW_* in // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. // * BAD_VALUE - what was out of range virtual int query(int what, int* value) = 0; // connect attempts to connect a client API to the IGraphicBufferProducer. // This must be called before any other IGraphicBufferProducer methods are // called except for getAllocator. A consumer must be already connected. // // This method will fail if the connect was previously called on the // IGraphicBufferProducer and no corresponding disconnect call was made. // // The listener is an optional binder callback object that can be used if // the producer wants to be notified when the consumer releases a buffer // back to the BufferQueue. It is also used to detect the death of the // producer. If only the latter functionality is desired, there is a // DummyProducerListener class in IProducerListener.h that can be used. // // The api should be one of the NATIVE_WINDOW_API_* values in // // The producerControlledByApp should be set to true if the producer is hosted // by an untrusted process (typically app_process-forked processes). If both // the producer and the consumer are app-controlled then all buffer queues // will operate in async mode regardless of the async flag. // // Upon success, the output will be filled with meaningful data // (refer to QueueBufferOutput documentation above). // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - one of the following occurred: // * the buffer queue was abandoned // * no consumer has yet connected // * BAD_VALUE - one of the following has occurred: // * the producer is already connected // * api was out of range (see above). // * output was NULL. // * Failure to adjust the number of available slots. This can // happen because of trying to allocate/deallocate the async // buffer in response to the value of producerControlledByApp. // * DEAD_OBJECT - the token is hosted by an already-dead process // // Additional negative errors may be returned by the internals, they // should be treated as opaque fatal unrecoverable errors. virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; // disconnect attempts to disconnect a client API from the // IGraphicBufferProducer. Calling this method will cause any subsequent // calls to other IGraphicBufferProducer methods to fail except for // getAllocator and connect. Successfully calling connect after this will // allow the other methods to succeed again. // // This method will fail if the the IGraphicBufferProducer is not currently // connected to the specified client API. // // The api should be one of the NATIVE_WINDOW_API_* values in // // Disconnecting from an abandoned IGraphicBufferProducer is legal and // is considered a no-op. // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - one of the following has occurred: // * the api specified does not match the one that was connected // * api was out of range (see above). // * DEAD_OBJECT - the token is hosted by an already-dead process virtual status_t disconnect(int api) = 0; // Attaches a sideband buffer stream to the IGraphicBufferProducer. // // A sideband stream is a device-specific mechanism for passing buffers // from the producer to the consumer without using dequeueBuffer/ // queueBuffer. If a sideband stream is present, the consumer can choose // whether to acquire buffers from the sideband stream or from the queued // buffers. // // Passing NULL or a different stream handle will detach the previous // handle if any. virtual status_t setSidebandStream(const sp& stream) = 0; // Allocates buffers based on the given dimensions/format. // // This function will allocate up to the maximum number of buffers // permitted by the current BufferQueue configuration. It will use the // given format, dimensions, and usage bits, which are interpreted in the // same way as for dequeueBuffer, and the async flag must be set the same // way as for dequeueBuffer to ensure that the correct number of buffers are // allocated. This is most useful to avoid an allocation delay during // dequeueBuffer. If there are already the maximum number of buffers // allocated, this function has no effect. virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) = 0; // Sets whether dequeueBuffer is allowed to allocate new buffers. // // Normally dequeueBuffer does not discriminate between free slots which // already have an allocated buffer and those which do not, and will // allocate a new buffer if the slot doesn't have a buffer or if the slot's // buffer doesn't match the requested size, format, or usage. This method // allows the producer to restrict the eligible slots to those which already // have an allocated buffer of the correct size, format, and usage. If no // eligible slot is available, dequeueBuffer will block or return an error // as usual. virtual status_t allowAllocation(bool allow) = 0; // Sets the current generation number of the BufferQueue. // // This generation number will be inserted into any buffers allocated by the // BufferQueue, and any attempts to attach a buffer with a different // generation number will fail. Buffers already in the queue are not // affected and will retain their current generation number. The generation // number defaults to 0. virtual status_t setGenerationNumber(uint32_t generationNumber) = 0; // Returns the name of the connected consumer. virtual String8 getConsumerName() const = 0; // Returns the number of the next frame which will be dequeued. virtual uint64_t getNextFrameNumber() const = 0; // Used to enable/disable shared buffer mode. // // When shared buffer mode is enabled the first buffer that is queued or // dequeued will be cached and returned to all subsequent calls to // dequeueBuffer and acquireBuffer. This allows the producer and consumer to // simultaneously access the same buffer. virtual status_t setSharedBufferMode(bool sharedBufferMode) = 0; // Used to enable/disable auto-refresh. // // Auto refresh has no effect outside of shared buffer mode. In shared // buffer mode, when enabled, it indicates to the consumer that it should // attempt to acquire buffers even if it is not aware of any being // available. virtual status_t setAutoRefresh(bool autoRefresh) = 0; // Sets how long dequeueBuffer will wait for a buffer to become available // before returning an error (TIMED_OUT). // // This timeout also affects the attachBuffer call, which will block if // there is not a free slot available into which the attached buffer can be // placed. // // By default, the BufferQueue will wait forever, which is indicated by a // timeout of -1. If set (to a value other than -1), this will disable // non-blocking mode and its corresponding spare buffer (which is used to // ensure a buffer is always available). // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - Failure to adjust the number of available slots. This can // happen because of trying to allocate/deallocate the async // buffer. virtual status_t setDequeueTimeout(nsecs_t timeout) = 0; // Returns the last queued buffer along with a fence which must signal // before the contents of the buffer are read. If there are no buffers in // the queue, outBuffer will be populated with nullptr and outFence will be // populated with Fence::NO_FENCE // // outTransformMatrix is not modified if outBuffer is null. // // Returns NO_ERROR or the status of the Binder transaction virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) = 0; // Returns a unique id for this BufferQueue virtual status_t getUniqueId(uint64_t* outId) const = 0; }; // ---------------------------------------------------------------------------- class BnGraphicBufferProducer : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H include/gui/IProducerListener.h0100644 0000000 0000000 00000004027 13077405420 015574 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H #include #include namespace android { // ProducerListener is the interface through which the BufferQueue notifies the // producer of events that the producer may wish to react to. Because the // producer will generally have a mutex that is locked during calls from the // producer to the BufferQueue, these calls from the BufferQueue to the // producer *MUST* be called only when the BufferQueue mutex is NOT locked. class ProducerListener : public virtual RefBase { public: ProducerListener() {} virtual ~ProducerListener() {} // onBufferReleased is called from IGraphicBufferConsumer::releaseBuffer to // notify the producer that a new buffer is free and ready to be dequeued. // // This is called without any lock held and can be called concurrently by // multiple threads. virtual void onBufferReleased() = 0; // Asynchronous }; class IProducerListener : public ProducerListener, public IInterface { public: DECLARE_META_INTERFACE(ProducerListener) }; class BnProducerListener : public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; class DummyProducerListener : public BnProducerListener { public: virtual void onBufferReleased() {} }; } // namespace android #endif include/gui/ISensorEventConnection.h0100644 0000000 0000000 00000003633 13077405420 016600 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_ISENSOR_EVENT_CONNECTION_H #define ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class BitTube; class ISensorEventConnection : public IInterface { public: DECLARE_META_INTERFACE(SensorEventConnection); virtual sp getSensorChannel() const = 0; virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0; virtual status_t setEventRate(int handle, nsecs_t ns) = 0; virtual status_t flush() = 0; }; // ---------------------------------------------------------------------------- class BnSensorEventConnection : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H include/gui/ISensorServer.h0100644 0000000 0000000 00000003646 13077405420 014751 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_ISENSORSERVER_H #define ANDROID_GUI_ISENSORSERVER_H #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class Sensor; class ISensorEventConnection; class String8; class ISensorServer : public IInterface { public: DECLARE_META_INTERFACE(SensorServer); virtual Vector getSensorList(const String16& opPackageName) = 0; virtual Vector getDynamicSensorList(const String16& opPackageName) = 0; virtual sp createSensorEventConnection(const String8& packageName, int mode, const String16& opPackageName) = 0; virtual int32_t isDataInjectionEnabled() = 0; }; // ---------------------------------------------------------------------------- class BnSensorServer : public BnInterface { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_ISENSORSERVER_H include/gui/ISurfaceComposer.h0100644 0000000 0000000 00000015031 13077405420 015400 0ustar000000000 0000000 /* * Copyright (C) 2006 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_GUI_ISURFACE_COMPOSER_H #define ANDROID_GUI_ISURFACE_COMPOSER_H #include #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class ComposerState; class DisplayState; struct DisplayInfo; struct DisplayStatInfo; class HdrCapabilities; class IDisplayEventConnection; class IMemoryHeap; class Rect; /* * This class defines the Binder IPC interface for accessing various * SurfaceFlinger features. */ class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer); // flags for setTransactionState() enum { eSynchronous = 0x01, eAnimation = 0x02, }; enum { eDisplayIdMain = 0, eDisplayIdHdmi = 1 }; enum Rotation { eRotateNone = 0, eRotate90 = 1, eRotate180 = 2, eRotate270 = 3 }; /* create connection with surface flinger, requires * ACCESS_SURFACE_FLINGER permission */ virtual sp createConnection() = 0; /* create a graphic buffer allocator */ virtual sp createGraphicBufferAlloc() = 0; /* return an IDisplayEventConnection */ virtual sp createDisplayEventConnection() = 0; /* create a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ virtual sp createDisplay(const String8& displayName, bool secure) = 0; /* destroy a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ virtual void destroyDisplay(const sp& display) = 0; /* get the token for the existing default displays. possible values * for id are eDisplayIdMain and eDisplayIdHdmi. */ virtual sp getBuiltInDisplay(int32_t id) = 0; /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission */ virtual void bootFinished() = 0; /* verify that an IGraphicBufferProducer was created by SurfaceFlinger. */ virtual bool authenticateSurfaceTexture( const sp& surface) const = 0; /* set display power mode. depending on the mode, it can either trigger * screen on, off or low power mode and wait for it to complete. * requires ACCESS_SURFACE_FLINGER permission. */ virtual void setPowerMode(const sp& display, int mode) = 0; /* returns information for each configuration of the given display * intended to be used to get information about built-in displays */ virtual status_t getDisplayConfigs(const sp& display, Vector* configs) = 0; /* returns display statistics for a given display * intended to be used by the media framework to properly schedule * video frames */ virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) = 0; /* indicates which of the configurations returned by getDisplayInfo is * currently active */ virtual int getActiveConfig(const sp& display) = 0; /* specifies which configuration (of those returned by getDisplayInfo) * should be used */ virtual status_t setActiveConfig(const sp& display, int id) = 0; /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ virtual status_t captureScreen(const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Rotation rotation = eRotateNone) = 0; /* Clears the frame statistics for animations. * * Requires the ACCESS_SURFACE_FLINGER permission. */ virtual status_t clearAnimationFrameStats() = 0; /* Gets the frame statistics for animations. * * Requires the ACCESS_SURFACE_FLINGER permission. */ virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0; /* Gets the supported HDR capabilities of the given display. * * Requires the ACCESS_SURFACE_FLINGER permission. */ virtual status_t getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities) const = 0; }; // ---------------------------------------------------------------------------- class BnSurfaceComposer: public BnInterface { public: enum { // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, CREATE_GRAPHIC_BUFFER_ALLOC, CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, GET_BUILT_IN_DISPLAY, SET_TRANSACTION_STATE, AUTHENTICATE_SURFACE, GET_DISPLAY_CONFIGS, GET_ACTIVE_CONFIG, SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, GET_DISPLAY_STATS, GET_HDR_CAPABILITIES, }; virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_ISURFACE_COMPOSER_H include/gui/ISurfaceComposerClient.h0100644 0000000 0000000 00000005472 13077405420 016547 0ustar000000000 0000000 /* * Copyright (C) 2007 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_GUI_ISURFACE_COMPOSER_CLIENT_H #define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- class IGraphicBufferProducer; class ISurfaceComposerClient : public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposerClient); // flags for createSurface() enum { // (keep in sync with Surface.java) eHidden = 0x00000004, eDestroyBackbuffer = 0x00000020, eSecure = 0x00000080, eNonPremultiplied = 0x00000100, eOpaque = 0x00000400, eProtectedByApp = 0x00000800, eProtectedByDRM = 0x00001000, eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, eFXSurfaceDim = 0x00020000, eFXSurfaceMask = 0x000F0000, }; /* * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t destroySurface(const sp& handle) = 0; /* * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t clearLayerFrameStats(const sp& handle) const = 0; /* * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t getLayerFrameStats(const sp& handle, FrameStats* outStats) const = 0; }; // ---------------------------------------------------------------------------- class BnSurfaceComposerClient: public BnInterface { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H include/gui/Sensor.h0100644 0000000 0000000 00000010614 13077405420 013442 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_SENSOR_H #define ANDROID_GUI_SENSOR_H #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Concrete types for the NDK struct ASensor { }; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class Parcel; // ---------------------------------------------------------------------------- class Sensor : public ASensor, public LightFlattenable { public: enum { TYPE_ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD, TYPE_GYROSCOPE = ASENSOR_TYPE_GYROSCOPE, TYPE_LIGHT = ASENSOR_TYPE_LIGHT, TYPE_PROXIMITY = ASENSOR_TYPE_PROXIMITY }; struct uuid_t{ union { uint8_t b[16]; int64_t i64[2]; }; uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));} uuid_t() : b{0} {} }; Sensor(const char * name = ""); Sensor(struct sensor_t const* hwSensor, int halVersion = 0); Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0); ~Sensor(); const String8& getName() const; const String8& getVendor() const; int32_t getHandle() const; int32_t getType() const; float getMinValue() const; float getMaxValue() const; float getResolution() const; float getPowerUsage() const; int32_t getMinDelay() const; nsecs_t getMinDelayNs() const; int32_t getVersion() const; uint32_t getFifoReservedEventCount() const; uint32_t getFifoMaxEventCount() const; const String8& getStringType() const; const String8& getRequiredPermission() const; bool isRequiredPermissionRuntime() const; int32_t getRequiredAppOp() const; int32_t getMaxDelay() const; uint32_t getFlags() const; bool isWakeUpSensor() const; bool isDynamicSensor() const; bool hasAdditionalInfo() const; int32_t getReportingMode() const; // Note that after setId() has been called, getUuid() no longer // returns the UUID. // TODO(b/29547335): Remove getUuid(), add getUuidIndex(), and // make sure setId() doesn't change the UuidIndex. const uuid_t& getUuid() const; int32_t getId() const; void setId(int32_t id); // LightFlattenable protocol inline bool isFixedSize() const { return false; } size_t getFlattenedSize() const; status_t flatten(void* buffer, size_t size) const; status_t unflatten(void const* buffer, size_t size); private: String8 mName; String8 mVendor; int32_t mHandle; int32_t mType; float mMinValue; float mMaxValue; float mResolution; float mPower; int32_t mMinDelay; int32_t mVersion; uint32_t mFifoReservedEventCount; uint32_t mFifoMaxEventCount; String8 mStringType; String8 mRequiredPermission; bool mRequiredPermissionRuntime = false; int32_t mRequiredAppOp; int32_t mMaxDelay; uint32_t mFlags; // TODO(b/29547335): Get rid of this field and replace with an index. // The index will be into a separate global vector of UUIDs. // Also add an mId field (and change flatten/unflatten appropriately). uuid_t mUuid; static void flattenString8(void*& buffer, size_t& size, const String8& string8); static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8); }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_SENSOR_H include/gui/SensorEventQueue.h0100644 0000000 0000000 00000007073 13077405420 015456 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_EVENT_QUEUE_H #define ANDROID_SENSOR_EVENT_QUEUE_H #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- #define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1U << 31) struct ALooper; struct ASensorEvent; // Concrete types for the NDK struct ASensorEventQueue { ALooper* looper; }; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class ISensorEventConnection; class Sensor; class Looper; // ---------------------------------------------------------------------------- class SensorEventQueue : public ASensorEventQueue, public RefBase { public: enum { MAX_RECEIVE_BUFFER_EVENT_COUNT = 256 }; /** * Typical sensor delay (sample period) in microseconds. */ // Fastest sampling, system will bound it to minDelay static constexpr int32_t SENSOR_DELAY_FASTEST = 0; // Typical sample period for game, 50Hz; static constexpr int32_t SENSOR_DELAY_GAME = 20000; // Typical sample period for UI, 15Hz static constexpr int32_t SENSOR_DELAY_UI = 66667; // Default sensor sample period static constexpr int32_t SENSOR_DELAY_NORMAL = 200000; SensorEventQueue(const sp& connection); virtual ~SensorEventQueue(); virtual void onFirstRef(); int getFd() const; static ssize_t write(const sp& tube, ASensorEvent const* events, size_t numEvents); ssize_t read(ASensorEvent* events, size_t numEvents); status_t waitForEvent() const; status_t wake() const; status_t enableSensor(Sensor const* sensor) const; status_t enableSensor(Sensor const* sensor, int32_t samplingPeriodUs) const; status_t disableSensor(Sensor const* sensor) const; status_t setEventRate(Sensor const* sensor, nsecs_t ns) const; // these are here only to support SensorManager.java status_t enableSensor(int32_t handle, int32_t samplingPeriodUs, int maxBatchReportLatencyUs, int reservedFlags) const; status_t disableSensor(int32_t handle) const; status_t flush() const; // Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK. void sendAck(const ASensorEvent* events, int count); status_t injectSensorEvent(const ASensorEvent& event); private: sp getLooper() const; sp mSensorEventConnection; sp mSensorChannel; mutable Mutex mLock; mutable sp mLooper; ASensorEvent* mRecBuffer; size_t mAvailable; size_t mConsumed; uint32_t mNumAcksToSend; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SENSOR_EVENT_QUEUE_H include/gui/SensorManager.h0100644 0000000 0000000 00000004744 13077405420 014744 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_SENSOR_MANAGER_H #define ANDROID_GUI_SENSOR_MANAGER_H #include #include #include #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Concrete types for the NDK struct ASensorManager { }; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class ISensorServer; class Sensor; class SensorEventQueue; // ---------------------------------------------------------------------------- class SensorManager : public ASensorManager { public: static SensorManager& getInstanceForPackage(const String16& packageName); ~SensorManager(); ssize_t getSensorList(Sensor const* const** list); ssize_t getDynamicSensorList(Vector& list); Sensor const* getDefaultSensor(int type); sp createEventQueue(String8 packageName = String8(""), int mode = 0); bool isDataInjectionEnabled(); private: // DeathRecipient interface void sensorManagerDied(); SensorManager(const String16& opPackageName); status_t assertStateLocked(); private: static Mutex sLock; static std::map sPackageInstances; Mutex mLock; sp mSensorServer; Sensor const** mSensorList; Vector mSensors; sp mDeathObserver; const String16 mOpPackageName; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_SENSOR_MANAGER_H include/gui/StreamSplitter.h0100644 0000000 0000000 00000016654 13077405420 015165 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_GUI_STREAMSPLITTER_H #define ANDROID_GUI_STREAMSPLITTER_H #include #include #include #include #include #include namespace android { class GraphicBuffer; class IGraphicBufferConsumer; class IGraphicBufferProducer; // StreamSplitter is an autonomous class that manages one input BufferQueue // and multiple output BufferQueues. By using the buffer attach and detach logic // in BufferQueue, it is able to present the illusion of a single split // BufferQueue, where each buffer queued to the input is available to be // acquired by each of the outputs, and is able to be dequeued by the input // again only once all of the outputs have released it. class StreamSplitter : public BnConsumerListener { public: // createSplitter creates a new splitter, outSplitter, using inputQueue as // the input BufferQueue. Output BufferQueues must be added using addOutput // before queueing any buffers to the input. // // A return value other than NO_ERROR means that an error has occurred and // outSplitter has not been modified. BAD_VALUE is returned if inputQueue or // outSplitter is NULL. See IGraphicBufferConsumer::consumerConnect for // explanations of other error codes. static status_t createSplitter(const sp& inputQueue, sp* outSplitter); // addOutput adds an output BufferQueue to the splitter. The splitter // connects to outputQueue as a CPU producer, and any buffers queued // to the input will be queued to each output. It is assumed that all of the // outputs are added before any buffers are queued on the input. If any // output is abandoned by its consumer, the splitter will abandon its input // queue (see onAbandoned). // // A return value other than NO_ERROR means that an error has occurred and // outputQueue has not been added to the splitter. BAD_VALUE is returned if // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations // of other error codes. status_t addOutput(const sp& outputQueue); // setName sets the consumer name of the input queue void setName(const String8& name); private: // From IConsumerListener // // During this callback, we store some tracking information, detach the // buffer from the input, and attach it to each of the outputs. This call // can block if there are too many outstanding buffers. If it blocks, it // will resume when onBufferReleasedByOutput releases a buffer back to the // input. virtual void onFrameAvailable(const BufferItem& item); // From IConsumerListener // We don't care about released buffers because we detach each buffer as // soon as we acquire it. See the comment for onBufferReleased below for // some clarifying notes about the name. virtual void onBuffersReleased() {} // From IConsumerListener // We don't care about sideband streams, since we won't be splitting them virtual void onSidebandStreamChanged() {} // This is the implementation of the onBufferReleased callback from // IProducerListener. It gets called from an OutputListener (see below), and // 'from' is which producer interface from which the callback was received. // // During this callback, we detach the buffer from the output queue that // generated the callback, update our state tracking to see if this is the // last output releasing the buffer, and if so, release it to the input. // If we release the buffer to the input, we allow a blocked // onFrameAvailable call to proceed. void onBufferReleasedByOutput(const sp& from); // When this is called, the splitter disconnects from (i.e., abandons) its // input queue and signals any waiting onFrameAvailable calls to wake up. // It still processes callbacks from other outputs, but only detaches their // buffers so they can continue operating until they run out of buffers to // acquire. This must be called with mMutex locked. void onAbandonedLocked(); // This is a thin wrapper class that lets us determine which BufferQueue // the IProducerListener::onBufferReleased callback is associated with. We // create one of these per output BufferQueue, and then pass the producer // into onBufferReleasedByOutput above. class OutputListener : public BnProducerListener, public IBinder::DeathRecipient { public: OutputListener(const sp& splitter, const sp& output); virtual ~OutputListener(); // From IProducerListener virtual void onBufferReleased(); // From IBinder::DeathRecipient virtual void binderDied(const wp& who); private: sp mSplitter; sp mOutput; }; class BufferTracker : public LightRefBase { public: BufferTracker(const sp& buffer); const sp& getBuffer() const { return mBuffer; } const sp& getMergedFence() const { return mMergedFence; } void mergeFence(const sp& with); // Returns the new value // Only called while mMutex is held size_t incrementReleaseCountLocked() { return ++mReleaseCount; } private: // Only destroy through LightRefBase friend LightRefBase; ~BufferTracker(); // Disallow copying BufferTracker(const BufferTracker& other); BufferTracker& operator=(const BufferTracker& other); sp mBuffer; // One instance that holds this native handle sp mMergedFence; size_t mReleaseCount; }; // Only called from createSplitter StreamSplitter(const sp& inputQueue); // Must be accessed through RefBase virtual ~StreamSplitter(); static const int MAX_OUTSTANDING_BUFFERS = 2; // mIsAbandoned is set to true when an output dies. Once the StreamSplitter // has been abandoned, it will continue to detach buffers from other // outputs, but it will disconnect from the input and not attempt to // communicate with it further. bool mIsAbandoned; Mutex mMutex; Condition mReleaseCondition; int mOutstandingBuffers; sp mInput; Vector > mOutputs; // Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking // objects (which are mostly for counting how many outputs have released the // buffer, but also contain merged release fences). KeyedVector > mBuffers; }; } // namespace android #endif include/gui/Surface.h0100644 0000000 0000000 00000040247 13077405420 013566 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H #include #include #include #include #include #include #include #include struct ANativeWindow_Buffer; namespace android { /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. * * This is typically used by programs that want to render frames through * some means (maybe OpenGL, a software renderer, or a hardware decoder) * and have the frames they create forwarded to SurfaceFlinger for * compositing. For example, a video decoder could render a frame and call * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by * Surface. Surface then forwards the buffers through Binder IPC * to the BufferQueue's producer interface, providing the new frame to a * consumer such as GLConsumer. */ class Surface : public ANativeObjectBase { public: /* * creates a Surface from the given IGraphicBufferProducer (which concrete * implementation is a BufferQueue). * * Surface is mainly state-less while it's disconnected, it can be * viewed as a glorified IGraphicBufferProducer holder. It's therefore * safe to create other Surfaces from the same IGraphicBufferProducer. * * However, once a Surface is connected, it'll prevent other Surfaces * referring to the same IGraphicBufferProducer to become connected and * therefore prevent them to be used as actual producers of buffers. * * the controlledByApp flag indicates that this Surface (producer) is * controlled by the application. This flag is used at connect time. */ Surface(const sp& bufferProducer, bool controlledByApp = false); /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this * Surface was created with. Usually it's an error to use the * IGraphicBufferProducer while the Surface is connected. */ sp getIGraphicBufferProducer() const; /* convenience function to check that the given surface is non NULL as * well as its IGraphicBufferProducer */ static bool isValid(const sp& surface) { return surface != NULL && surface->getIGraphicBufferProducer() != NULL; } /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. * * A sideband stream is a device-specific mechanism for passing buffers * from the producer to the consumer without using dequeueBuffer/ * queueBuffer. If a sideband stream is present, the consumer can choose * whether to acquire buffers from the sideband stream or from the queued * buffers. * * Passing NULL or a different stream handle will detach the previous * handle if any. */ void setSidebandStream(const sp& stream); /* Allocates buffers based on the current dimensions/format. * * This function will allocate up to the maximum number of buffers * permitted by the current BufferQueue configuration. It will use the * default format and dimensions. This is most useful to avoid an allocation * delay during dequeueBuffer. If there are already the maximum number of * buffers allocated, this function has no effect. */ void allocateBuffers(); /* Sets the generation number on the IGraphicBufferProducer and updates the * generation number on any buffers attached to the Surface after this call. * See IGBP::setGenerationNumber for more information. */ status_t setGenerationNumber(uint32_t generationNumber); // See IGraphicBufferProducer::getConsumerName String8 getConsumerName() const; // See IGraphicBufferProducer::getNextFrameNumber uint64_t getNextFrameNumber() const; /* Set the scaling mode to be used with a Surface. * See NATIVE_WINDOW_SET_SCALING_MODE and its parameters * in . */ int setScalingMode(int mode); // See IGraphicBufferProducer::setDequeueTimeout status_t setDequeueTimeout(nsecs_t timeout); /* * Wait for frame number to increase past lastFrame for at most * timeoutNs. Useful for one thread to wait for another unknown * thread to queue a buffer. */ bool waitForNextFrame(uint64_t lastFrame, nsecs_t timeout); // See IGraphicBufferProducer::getLastQueuedBuffer // See GLConsumer::getTransformMatrix for outTransformMatrix format status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]); status_t getUniqueId(uint64_t* outId) const; protected: virtual ~Surface(); private: // can't be copied Surface& operator = (const Surface& rhs); Surface(const Surface& rhs); // ANativeWindow hooks static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd); static int hook_perform(ANativeWindow* window, int operation, ...); static int hook_query(const ANativeWindow* window, int what, int* value); static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_setSwapInterval(ANativeWindow* window, int interval); static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); int dispatchConnect(va_list args); int dispatchDisconnect(va_list args); int dispatchSetBufferCount(va_list args); int dispatchSetBuffersGeometry(va_list args); int dispatchSetBuffersDimensions(va_list args); int dispatchSetBuffersUserDimensions(va_list args); int dispatchSetBuffersFormat(va_list args); int dispatchSetScalingMode(va_list args); int dispatchSetBuffersTransform(va_list args); int dispatchSetBuffersStickyTransform(va_list args); int dispatchSetBuffersTimestamp(va_list args); int dispatchSetCrop(va_list args); int dispatchSetPostTransformCrop(va_list args); int dispatchSetUsage(va_list args); int dispatchLock(va_list args); int dispatchUnlockAndPost(va_list args); int dispatchSetSidebandStream(va_list args); int dispatchSetBuffersDataSpace(va_list args); int dispatchSetSurfaceDamage(va_list args); int dispatchSetSharedBufferMode(va_list args); int dispatchSetAutoRefresh(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); virtual int perform(int operation, va_list args); virtual int query(int what, int* value) const; virtual int setSwapInterval(int interval); virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); virtual int connect(int api); virtual int disconnect(int api); virtual int setBufferCount(int bufferCount); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int setBuffersUserDimensions(uint32_t width, uint32_t height); virtual int setBuffersFormat(PixelFormat format); virtual int setBuffersTransform(uint32_t transform); virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); virtual int setBuffersDataSpace(android_dataspace dataSpace); virtual int setCrop(Rect const* rect); virtual int setUsage(uint32_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); virtual int connect(int api, const sp& listener); virtual int detachNextBuffer(sp* outBuffer, sp* outFence); virtual int attachBuffer(ANativeWindowBuffer*); protected: enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; private: void freeAllBuffers(); int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; struct BufferSlot { sp buffer; Region dirtyRegion; }; // mSurfaceTexture is the interface to the surface texture server. All // operations on the surface texture client ultimately translate into // interactions with the server using this interface. // TODO: rename to mBufferProducer sp mGraphicBufferProducer; // mSlots stores the buffers that have been allocated for each buffer slot. // It is initialized to null pointers, and gets filled in with the result of // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. BufferSlot mSlots[NUM_BUFFER_SLOTS]; // mReqWidth is the buffer width that will be requested at the next dequeue // operation. It is initialized to 1. uint32_t mReqWidth; // mReqHeight is the buffer height that will be requested at the next // dequeue operation. It is initialized to 1. uint32_t mReqHeight; // mReqFormat is the buffer pixel format that will be requested at the next // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. PixelFormat mReqFormat; // mReqUsage is the set of buffer usage flags that will be requested // at the next deuque operation. It is initialized to 0. uint32_t mReqUsage; // mTimestamp is the timestamp that will be used for the next buffer queue // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that // a timestamp is auto-generated when queueBuffer is called. int64_t mTimestamp; // mDataSpace is the buffer dataSpace that will be used for the next buffer // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which // means that the buffer contains some type of color data. android_dataspace mDataSpace; // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mCrop; // mScalingMode is the scaling mode that will be used for the next // buffers that get queued. It is set by calling setScalingMode. int mScalingMode; // mTransform is the transform identifier that will be used for the next // buffer that gets queued. It is set by calling setTransform. uint32_t mTransform; // mStickyTransform is a transform that is applied on top of mTransform // in each buffer that is queued. This is typically used to force the // compositor to apply a transform, and will prevent the transform hint // from being set by the compositor. uint32_t mStickyTransform; // mDefaultWidth is default width of the buffers, regardless of the // native_window_set_buffers_dimensions call. uint32_t mDefaultWidth; // mDefaultHeight is default height of the buffers, regardless of the // native_window_set_buffers_dimensions call. uint32_t mDefaultHeight; // mUserWidth, if non-zero, is an application-specified override // of mDefaultWidth. This is lower priority than the width set by // native_window_set_buffers_dimensions. uint32_t mUserWidth; // mUserHeight, if non-zero, is an application-specified override // of mDefaultHeight. This is lower priority than the height set // by native_window_set_buffers_dimensions. uint32_t mUserHeight; // mTransformHint is the transform probably applied to buffers of this // window. this is only a hint, actual transform may differ. uint32_t mTransformHint; // mProducerControlledByApp whether this buffer producer is controlled // by the application bool mProducerControlledByApp; // mSwapIntervalZero set if we should drop buffers at queue() time to // achieve an asynchronous swap interval bool mSwapIntervalZero; // mConsumerRunningBehind whether the consumer is running more than // one buffer behind the producer. mutable bool mConsumerRunningBehind; // mMutex is the mutex used to prevent concurrent access to the member // variables of Surface objects. It must be locked whenever the // member variables are accessed. mutable Mutex mMutex; // must be used from the lock/unlock thread sp mLockedBuffer; sp mPostedBuffer; bool mConnectedToCpu; // When a CPU producer is attached, this reflects the region that the // producer wished to update as well as whether the Surface was able to copy // the previous buffer back to allow a partial update. // // When a non-CPU producer is attached, this reflects the surface damage // (the change since the previous frame) passed in by the producer. Region mDirtyRegion; // Stores the current generation number. See setGenerationNumber and // IGraphicBufferProducer::setGenerationNumber for more information. uint32_t mGenerationNumber; // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going // over Binder. int mSharedBufferSlot; // This is true if the shared buffer has already been queued/canceled. It's // used to prevent a mismatch between the number of queue/dequeue calls. bool mSharedBufferHasBeenQueued; Condition mQueueBufferCondition; }; namespace view { /** * A simple holder for an IGraphicBufferProducer, to match the managed-side * android.view.Surface parcelable behavior. * * This implements android/view/Surface.aidl * * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly * used in managed Binder calls. */ class Surface : public Parcelable { public: String16 name; sp graphicBufferProducer; virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; // nameAlreadyWritten set to true by Surface.java, because it splits // Parceling itself between managed and native code, so it only wants a part // of the full parceling to happen on its native side. status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const; // nameAlreadyRead set to true by Surface.java, because it splits // Parceling itself between managed and native code, so it only wants a part // of the full parceling to happen on its native side. status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead); private: static String16 readMaybeEmptyString16(const Parcel* parcel); }; } // namespace view }; // namespace android #endif // ANDROID_GUI_SURFACE_H include/gui/SurfaceComposerClient.h0100644 0000000 0000000 00000022401 13077405420 016425 0ustar000000000 0000000 /* * Copyright (C) 2007 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_GUI_SURFACE_COMPOSER_CLIENT_H #define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H #include #include #include #include #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class DisplayInfo; class Composer; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; class Region; // --------------------------------------------------------------------------- class SurfaceComposerClient : public RefBase { friend class Composer; public: SurfaceComposerClient(); virtual ~SurfaceComposerClient(); // Always make sure we could initialize status_t initCheck() const; // Return the connection of this client sp connection() const; // Forcibly remove connection before all references have gone away. void dispose(); // callback when the composer is dies status_t linkToComposerDeath(const sp& recipient, void* cookie = NULL, uint32_t flags = 0); // Get a list of supported configurations for a given display static status_t getDisplayConfigs(const sp& display, Vector* configs); // Get the DisplayInfo for the currently-active configuration static status_t getDisplayInfo(const sp& display, DisplayInfo* info); // Get the index of the current active configuration (relative to the list // returned by getDisplayInfo) static int getActiveConfig(const sp& display); // Set a new active configuration using an index relative to the list // returned by getDisplayInfo static status_t setActiveConfig(const sp& display, int id); /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp& display, int mode); // ------------------------------------------------------------------------ // surface creation / destruction //! Create a surface sp createSurface( const String8& name,// name of the surface uint32_t w, // width in pixel uint32_t h, // height in pixel PixelFormat format, // pixel-format desired uint32_t flags = 0 // usage flags ); //! Create a virtual display static sp createDisplay(const String8& displayName, bool secure); //! Destroy a virtual display static void destroyDisplay(const sp& display); //! Get the token for the existing default displays. //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. static sp getBuiltInDisplay(int32_t id); // ------------------------------------------------------------------------ // Composer parameters // All composer parameters must be changed within a transaction // several surfaces can be updated in one transaction, all changes are // committed at once when the transaction is closed. // closeGlobalTransaction() requires an IPC with the server. //! Open a composer transaction on all active SurfaceComposerClients. static void openGlobalTransaction(); //! Close a composer transaction on all active SurfaceComposerClients. static void closeGlobalTransaction(bool synchronous = false); //! Flag the currently open transaction as an animation transaction. static void setAnimationTransaction(); status_t hide(const sp& id); status_t show(const sp& id); status_t setFlags(const sp& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const sp& id, const Region& transparent); status_t setLayer(const sp& id, uint32_t layer); status_t setAlpha(const sp& id, float alpha=1.0f); status_t setMatrix(const sp& id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setPosition(const sp& id, float x, float y); status_t setSize(const sp& id, uint32_t w, uint32_t h); status_t setCrop(const sp& id, const Rect& crop); status_t setFinalCrop(const sp& id, const Rect& crop); status_t setLayerStack(const sp& id, uint32_t layerStack); status_t deferTransactionUntil(const sp& id, const sp& handle, uint64_t frameNumber); status_t setOverrideScalingMode(const sp& id, int32_t overrideScalingMode); status_t setPositionAppliesWithResize(const sp& id); status_t destroySurface(const sp& id); status_t clearLayerFrameStats(const sp& token) const; status_t getLayerFrameStats(const sp& token, FrameStats* outStats) const; static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); static status_t getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities); static void setDisplaySurface(const sp& token, const sp& bufferProducer); static void setDisplayLayerStack(const sp& token, uint32_t layerStack); static void setDisplaySize(const sp& token, uint32_t width, uint32_t height); /* setDisplayProjection() defines the projection of layer stacks * to a given display. * * - orientation defines the display's orientation. * - layerStackRect defines which area of the window manager coordinate * space will be used. * - displayRect defines where on the display will layerStackRect be * mapped to. displayRect is specified post-orientation, that is * it uses the orientation seen by the end-user. */ static void setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); private: virtual void onFirstRef(); Composer& getComposer(); mutable Mutex mLock; status_t mStatus; sp mClient; Composer& mComposer; }; // --------------------------------------------------------------------------- class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); static status_t capture( const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform); private: mutable sp mCpuConsumer; mutable sp mProducer; CpuConsumer::LockedBuffer mBuffer; bool mHaveBuffer; public: ScreenshotClient(); ~ScreenshotClient(); // frees the previous screenshot and captures a new one // if cropping isn't required, callers may pass in a default Rect, e.g.: // update(display, Rect(), useIdentityTransform); status_t update(const sp& display, Rect sourceCrop, bool useIdentityTransform); status_t update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform); status_t update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform); status_t update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, uint32_t rotation); sp getCpuConsumer() const; // release memory occupied by the screenshot void release(); // pixels are valid until this object is freed or // release() or update() is called void const* getPixels() const; uint32_t getWidth() const; uint32_t getHeight() const; PixelFormat getFormat() const; uint32_t getStride() const; // size of allocated memory in bytes size_t getSize() const; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H include/gui/SurfaceControl.h0100644 0000000 0000000 00000007625 13077405420 015132 0ustar000000000 0000000 /* * Copyright (C) 2007 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_GUI_SURFACE_CONTROL_H #define ANDROID_GUI_SURFACE_CONTROL_H #include #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class IGraphicBufferProducer; class Surface; class SurfaceComposerClient; // --------------------------------------------------------------------------- class SurfaceControl : public RefBase { public: static bool isValid(const sp& surface) { return (surface != 0) && surface->isValid(); } bool isValid() { return mHandle!=0 && mClient!=0; } static bool isSameSurface( const sp& lhs, const sp& rhs); // release surface data from java void clear(); // disconnect any api that's connected void disconnect(); status_t setLayerStack(uint32_t layerStack); status_t setLayer(uint32_t layer); status_t setPosition(float x, float y); status_t setSize(uint32_t w, uint32_t h); status_t hide(); status_t show(); status_t setFlags(uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const Region& transparent); status_t setAlpha(float alpha=1.0f); status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy); status_t setCrop(const Rect& crop); status_t setFinalCrop(const Rect& crop); // If the size changes in this transaction, position updates specified // in this transaction will not complete until a buffer of the new size // arrives. status_t setPositionAppliesWithResize(); // Defers applying any changes made in this transaction until the Layer // identified by handle reaches the given frameNumber status_t deferTransactionUntil(sp handle, uint64_t frameNumber); // Set an override scaling mode as documented in // the override scaling mode will take precedence over any client // specified scaling mode. -1 will clear the override scaling mode. status_t setOverrideScalingMode(int32_t overrideScalingMode); static status_t writeSurfaceToParcel( const sp& control, Parcel* parcel); sp getSurface() const; sp getHandle() const; status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); SurfaceControl(const SurfaceControl& rhs); friend class SurfaceComposerClient; friend class Surface; SurfaceControl( const sp& client, const sp& handle, const sp& gbp); ~SurfaceControl(); status_t validate() const; void destroy(); sp mClient; sp mHandle; sp mGraphicBufferProducer; mutable Mutex mLock; mutable sp mSurfaceData; }; }; // namespace android #endif // ANDROID_GUI_SURFACE_CONTROL_H include/input/0040755 0000000 0000000 00000000000 13077405420 012374 5ustar000000000 0000000 include/input/IInputFlinger.h0100644 0000000 0000000 00000002514 13077405420 015263 0ustar000000000 0000000 /* * Copyright (C) 2013 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 _LIBINPUT_IINPUT_FLINGER_H #define _LIBINPUT_IINPUT_FLINGER_H #include #include #include namespace android { /* * This class defines the Binder IPC interface for accessing various * InputFlinger features. */ class IInputFlinger : public IInterface { public: DECLARE_META_INTERFACE(InputFlinger); }; /** * Binder implementation. */ class BnInputFlinger : public BnInterface { public: enum { DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, }; virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; } // namespace android #endif // _LIBINPUT_IINPUT_FLINGER_H include/input/Input.h0100644 0000000 0000000 00000050513 13077405420 013645 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _LIBINPUT_INPUT_H #define _LIBINPUT_INPUT_H /** * Native input event structures. */ #include #include #include #include #include #include #include #include /* * Additional private constants not defined in ndk/ui/input.h. */ enum { /* Signifies that the key is being predispatched */ AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000, /* Private control to determine when an app is tracking a key sequence. */ AKEY_EVENT_FLAG_START_TRACKING = 0x40000000, /* Key event is inconsistent with previously sent key events. */ AKEY_EVENT_FLAG_TAINTED = 0x80000000, }; enum { /** * This flag indicates that the window that received this motion event is partly * or wholly obscured by another visible window above it. This flag is set to true * even if the event did not directly pass through the obscured area. * A security sensitive application can check this flag to identify situations in which * a malicious application may have covered up part of its content for the purpose * of misleading the user or hijacking touches. An appropriate response might be * to drop the suspect touches or to take additional precautions to confirm the user's * actual intent. */ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2, /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; enum { /* Used when a motion event is not associated with any display. * Typically used for non-pointer events. */ ADISPLAY_ID_NONE = -1, /* The default display id. */ ADISPLAY_ID_DEFAULT = 0, }; enum { /* * Indicates that an input device has switches. * This input source flag is hidden from the API because switches are only used by the system * and applications have no way to interact with them. */ AINPUT_SOURCE_SWITCH = 0x80000000, }; enum { /** * Constants for LEDs. Hidden from the API since we don't actually expose a way to interact * with LEDs to developers * * NOTE: If you add LEDs here, you must also add them to InputEventLabels.h */ ALED_NUM_LOCK = 0x00, ALED_CAPS_LOCK = 0x01, ALED_SCROLL_LOCK = 0x02, ALED_COMPOSE = 0x03, ALED_KANA = 0x04, ALED_SLEEP = 0x05, ALED_SUSPEND = 0x06, ALED_MUTE = 0x07, ALED_MISC = 0x08, ALED_MAIL = 0x09, ALED_CHARGING = 0x0a, ALED_CONTROLLER_1 = 0x10, ALED_CONTROLLER_2 = 0x11, ALED_CONTROLLER_3 = 0x12, ALED_CONTROLLER_4 = 0x13, }; /* Maximum number of controller LEDs we support */ #define MAX_CONTROLLER_LEDS 4 /* * SystemUiVisibility constants from View. */ enum { ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0, ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001, }; /* * Maximum number of pointers supported per motion event. * Smallest number of pointers is 1. * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers * will occasionally emit 11. There is not much harm making this constant bigger.) */ #define MAX_POINTERS 16 /* * Maximum number of samples supported per motion event. */ #define MAX_SAMPLES UINT16_MAX /* * Maximum pointer id value supported in a motion event. * Smallest pointer id is 0. * (This is limited by our use of BitSet32 to track pointer assignments.) */ #define MAX_POINTER_ID 31 /* * Declare a concrete type for the NDK's input event forward declaration. */ struct AInputEvent { virtual ~AInputEvent() { } }; /* * Declare a concrete type for the NDK's input device forward declaration. */ struct AInputDevice { virtual ~AInputDevice() { } }; namespace android { #ifdef __ANDROID__ class Parcel; #endif /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. * * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. */ enum { /* These flags originate in RawEvents and are generally set in the key map. * NOTE: If you want a flag to be able to set in a keylayout file, then you must add it to * InputEventLabels.h as well. */ // Indicates that the event should wake the device. POLICY_FLAG_WAKE = 0x00000001, // Indicates that the key is virtual, such as a capacitive button, and should // generate haptic feedback. Virtual keys may be suppressed for some time // after a recent touch to prevent accidental activation of virtual keys adjacent // to the touch screen during an edge swipe. POLICY_FLAG_VIRTUAL = 0x00000002, // Indicates that the key is the special function modifier. POLICY_FLAG_FUNCTION = 0x00000004, // Indicates that the key represents a special gesture that has been detected by // the touch firmware or driver. Causes touch events from the same device to be canceled. POLICY_FLAG_GESTURE = 0x00000008, POLICY_FLAG_RAW_MASK = 0x0000ffff, /* These flags are set by the input dispatcher. */ // Indicates that the input event was injected. POLICY_FLAG_INJECTED = 0x01000000, // Indicates that the input event is from a trusted source such as a directly attached // input device or an application with system-wide event injection permission. POLICY_FLAG_TRUSTED = 0x02000000, // Indicates that the input event has passed through an input filter. POLICY_FLAG_FILTERED = 0x04000000, // Disables automatic key repeating behavior. POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000, /* These flags are set by the input reader policy as it intercepts each event. */ // Indicates that the device was in an interactive state when the // event was intercepted. POLICY_FLAG_INTERACTIVE = 0x20000000, // Indicates that the event should be dispatched to applications. // The input event should still be sent to the InputDispatcher so that it can see all // input events received include those that it will not deliver. POLICY_FLAG_PASS_TO_USER = 0x40000000, }; /* * Pointer coordinate data. */ struct PointerCoords { enum { MAX_AXES = 30 }; // 30 so that sizeof(PointerCoords) == 128 // Bitfield of axes that are present in this structure. uint64_t bits __attribute__((aligned(8))); // Values of axes that are stored in this structure packed in order by axis id // for each axis that is present in the structure according to 'bits'. float values[MAX_AXES]; inline void clear() { BitSet64::clear(bits); } bool isEmpty() const { return BitSet64::isEmpty(bits); } float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); void scale(float scale); void applyOffset(float xOffset, float yOffset); inline float getX() const { return getAxisValue(AMOTION_EVENT_AXIS_X); } inline float getY() const { return getAxisValue(AMOTION_EVENT_AXIS_Y); } #ifdef __ANDROID__ status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; #endif bool operator==(const PointerCoords& other) const; inline bool operator!=(const PointerCoords& other) const { return !(*this == other); } void copyFrom(const PointerCoords& other); private: void tooManyAxes(int axis); }; /* * Pointer property data. */ struct PointerProperties { // The id of the pointer. int32_t id; // The pointer tool type. int32_t toolType; inline void clear() { id = -1; toolType = 0; } bool operator==(const PointerProperties& other) const; inline bool operator!=(const PointerProperties& other) const { return !(*this == other); } void copyFrom(const PointerProperties& other); }; /* * Input events. */ class InputEvent : public AInputEvent { public: virtual ~InputEvent() { } virtual int32_t getType() const = 0; inline int32_t getDeviceId() const { return mDeviceId; } inline int32_t getSource() const { return mSource; } inline void setSource(int32_t source) { mSource = source; } protected: void initialize(int32_t deviceId, int32_t source); void initialize(const InputEvent& from); int32_t mDeviceId; int32_t mSource; }; /* * Key events. */ class KeyEvent : public InputEvent { public: virtual ~KeyEvent() { } virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; } inline int32_t getAction() const { return mAction; } inline int32_t getFlags() const { return mFlags; } inline void setFlags(int32_t flags) { mFlags = flags; } inline int32_t getKeyCode() const { return mKeyCode; } inline int32_t getScanCode() const { return mScanCode; } inline int32_t getMetaState() const { return mMetaState; } inline int32_t getRepeatCount() const { return mRepeatCount; } inline nsecs_t getDownTime() const { return mDownTime; } inline nsecs_t getEventTime() const { return mEventTime; } static const char* getLabel(int32_t keyCode); static int32_t getKeyCodeFromLabel(const char* label); void initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); void initialize(const KeyEvent& from); protected: int32_t mAction; int32_t mFlags; int32_t mKeyCode; int32_t mScanCode; int32_t mMetaState; int32_t mRepeatCount; nsecs_t mDownTime; nsecs_t mEventTime; }; /* * Motion events. */ class MotionEvent : public InputEvent { public: virtual ~MotionEvent() { } virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; } inline int32_t getAction() const { return mAction; } inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } inline int32_t getActionIndex() const { return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } inline void setFlags(int32_t flags) { mFlags = flags; } inline int32_t getEdgeFlags() const { return mEdgeFlags; } inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; } inline int32_t getMetaState() const { return mMetaState; } inline void setMetaState(int32_t metaState) { mMetaState = metaState; } inline int32_t getButtonState() const { return mButtonState; } inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; } inline int32_t getActionButton() const { return mActionButton; } inline void setActionButton(int32_t button) { mActionButton = button; } inline float getXOffset() const { return mXOffset; } inline float getYOffset() const { return mYOffset; } inline float getXPrecision() const { return mXPrecision; } inline float getYPrecision() const { return mYPrecision; } inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } inline size_t getPointerCount() const { return mPointerProperties.size(); } inline const PointerProperties* getPointerProperties(size_t pointerIndex) const { return &mPointerProperties[pointerIndex]; } inline int32_t getPointerId(size_t pointerIndex) const { return mPointerProperties[pointerIndex].id; } inline int32_t getToolType(size_t pointerIndex) const { return mPointerProperties[pointerIndex].toolType; } inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } const PointerCoords* getRawPointerCoords(size_t pointerIndex) const; float getRawAxisValue(int32_t axis, size_t pointerIndex) const; inline float getRawX(size_t pointerIndex) const { return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); } inline float getRawY(size_t pointerIndex) const { return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); } float getAxisValue(int32_t axis, size_t pointerIndex) const; inline float getX(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); } inline float getY(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); } inline float getPressure(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex); } inline float getSize(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex); } inline float getTouchMajor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex); } inline float getTouchMinor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex); } inline float getToolMajor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex); } inline float getToolMinor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex); } inline float getOrientation(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex); } inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { return mSampleEventTimes[historicalIndex]; } const PointerCoords* getHistoricalRawPointerCoords( size_t pointerIndex, size_t historicalIndex) const; float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawAxisValue( AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); } inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawAxisValue( AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); } float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); } inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); } inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex); } inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex); } inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex); } inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex); } inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex); } inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex); } inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); } ssize_t findPointerIndex(int32_t pointerId) const; void initialize( int32_t deviceId, int32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); void addSample( nsecs_t eventTime, const PointerCoords* pointerCoords); void offsetLocation(float xOffset, float yOffset); void scale(float scaleFactor); // Apply 3x3 perspective matrix transformation. // Matrix is in row-major form and compatible with SkMatrix. void transform(const float matrix[9]); #ifdef __ANDROID__ status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; #endif static bool isTouchEvent(int32_t source, int32_t action); inline bool isTouchEvent() const { return isTouchEvent(mSource, mAction); } // Low-level accessors. inline const PointerProperties* getPointerProperties() const { return mPointerProperties.array(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } inline const PointerCoords* getSamplePointerCoords() const { return mSamplePointerCoords.array(); } static const char* getLabel(int32_t axis); static int32_t getAxisFromLabel(const char* label); protected: int32_t mAction; int32_t mActionButton; int32_t mFlags; int32_t mEdgeFlags; int32_t mMetaState; int32_t mButtonState; float mXOffset; float mYOffset; float mXPrecision; float mYPrecision; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; Vector mSamplePointerCoords; }; /* * Input event factory. */ class InputEventFactoryInterface { protected: virtual ~InputEventFactoryInterface() { } public: InputEventFactoryInterface() { } virtual KeyEvent* createKeyEvent() = 0; virtual MotionEvent* createMotionEvent() = 0; }; /* * A simple input event factory implementation that uses a single preallocated instance * of each type of input event that are reused for each request. */ class PreallocatedInputEventFactory : public InputEventFactoryInterface { public: PreallocatedInputEventFactory() { } virtual ~PreallocatedInputEventFactory() { } virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } private: KeyEvent mKeyEvent; MotionEvent mMotionEvent; }; /* * An input event factory implementation that maintains a pool of input events. */ class PooledInputEventFactory : public InputEventFactoryInterface { public: PooledInputEventFactory(size_t maxPoolSize = 20); virtual ~PooledInputEventFactory(); virtual KeyEvent* createKeyEvent(); virtual MotionEvent* createMotionEvent(); void recycle(InputEvent* event); private: const size_t mMaxPoolSize; Vector mKeyEventPool; Vector mMotionEventPool; }; } // namespace android #endif // _LIBINPUT_INPUT_H include/input/InputDevice.h0100644 0000000 0000000 00000013547 13077405420 014773 0ustar000000000 0000000 /* * Copyright (C) 2012 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 _LIBINPUT_INPUT_DEVICE_H #define _LIBINPUT_INPUT_DEVICE_H #include #include namespace android { /* * Identifies a device. */ struct InputDeviceIdentifier { inline InputDeviceIdentifier() : bus(0), vendor(0), product(0), version(0) { } // Information provided by the kernel. String8 name; String8 location; String8 uniqueId; uint16_t bus; uint16_t vendor; uint16_t product; uint16_t version; // A composite input device descriptor string that uniquely identifies the device // even across reboots or reconnections. The value of this field is used by // upper layers of the input system to associate settings with individual devices. // It is hashed from whatever kernel provided information is available. // Ideally, the way this value is computed should not change between Android releases // because that would invalidate persistent settings that rely on it. String8 descriptor; // A value added to uniquely identify a device in the absence of a unique id. This // is intended to be a minimum way to distinguish from other active devices and may // reuse values that are not associated with an input anymore. uint16_t nonce; }; /* * Describes the characteristics and capabilities of an input device. */ class InputDeviceInfo { public: InputDeviceInfo(); InputDeviceInfo(const InputDeviceInfo& other); ~InputDeviceInfo(); struct MotionRange { int32_t axis; uint32_t source; float min; float max; float flat; float fuzz; float resolution; }; void initialize(int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, bool hasMic); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } inline int32_t getGeneration() const { return mGeneration; } inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; } inline const String8& getAlias() const { return mAlias; } inline const String8& getDisplayName() const { return mAlias.isEmpty() ? mIdentifier.name : mAlias; } inline bool isExternal() const { return mIsExternal; } inline bool hasMic() const { return mHasMic; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; void addSource(uint32_t source); void addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz, float resolution); void addMotionRange(const MotionRange& range); inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } inline int32_t getKeyboardType() const { return mKeyboardType; } inline void setKeyCharacterMap(const sp& value) { mKeyCharacterMap = value; } inline sp getKeyCharacterMap() const { return mKeyCharacterMap; } inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } inline bool hasVibrator() const { return mHasVibrator; } inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; } inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; } inline const Vector& getMotionRanges() const { return mMotionRanges; } private: int32_t mId; int32_t mGeneration; int32_t mControllerNumber; InputDeviceIdentifier mIdentifier; String8 mAlias; bool mIsExternal; bool mHasMic; uint32_t mSources; int32_t mKeyboardType; sp mKeyCharacterMap; bool mHasVibrator; bool mHasButtonUnderPad; Vector mMotionRanges; }; /* Types of input device configuration files. */ enum InputDeviceConfigurationFileType { INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */ }; /* * Gets the path of an input device configuration file, if one is available. * Considers both system provided and user installed configuration files. * * The device identifier is used to construct several default configuration file * names to try based on the device name, vendor, product, and version. * * Returns an empty string if not found. */ extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type); /* * Gets the path of an input device configuration file, if one is available. * Considers both system provided and user installed configuration files. * * The name is case-sensitive and is used to construct the filename to resolve. * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores. * * Returns an empty string if not found. */ extern String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type); } // namespace android #endif // _LIBINPUT_INPUT_DEVICE_H include/input/InputEventLabels.h0100644 0000000 0000000 00000031607 13077405420 015775 0ustar000000000 0000000 /* * Copyright (C) 2008 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 _LIBINPUT_INPUT_EVENT_LABELS_H #define _LIBINPUT_INPUT_EVENT_LABELS_H #include #include #define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key } #define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis } #define DEFINE_LED(led) { #led, ALED_##led } #define DEFINE_FLAG(flag) { #flag, POLICY_FLAG_##flag } namespace android { template size_t size(T (&)[N]) { return N; } struct InputEventLabel { const char *literal; int value; }; static const InputEventLabel KEYCODES[] = { // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. DEFINE_KEYCODE(UNKNOWN), DEFINE_KEYCODE(SOFT_LEFT), DEFINE_KEYCODE(SOFT_RIGHT), DEFINE_KEYCODE(HOME), DEFINE_KEYCODE(BACK), DEFINE_KEYCODE(CALL), DEFINE_KEYCODE(ENDCALL), DEFINE_KEYCODE(0), DEFINE_KEYCODE(1), DEFINE_KEYCODE(2), DEFINE_KEYCODE(3), DEFINE_KEYCODE(4), DEFINE_KEYCODE(5), DEFINE_KEYCODE(6), DEFINE_KEYCODE(7), DEFINE_KEYCODE(8), DEFINE_KEYCODE(9), DEFINE_KEYCODE(STAR), DEFINE_KEYCODE(POUND), DEFINE_KEYCODE(DPAD_UP), DEFINE_KEYCODE(DPAD_DOWN), DEFINE_KEYCODE(DPAD_LEFT), DEFINE_KEYCODE(DPAD_RIGHT), DEFINE_KEYCODE(DPAD_CENTER), DEFINE_KEYCODE(VOLUME_UP), DEFINE_KEYCODE(VOLUME_DOWN), DEFINE_KEYCODE(POWER), DEFINE_KEYCODE(CAMERA), DEFINE_KEYCODE(CLEAR), DEFINE_KEYCODE(A), DEFINE_KEYCODE(B), DEFINE_KEYCODE(C), DEFINE_KEYCODE(D), DEFINE_KEYCODE(E), DEFINE_KEYCODE(F), DEFINE_KEYCODE(G), DEFINE_KEYCODE(H), DEFINE_KEYCODE(I), DEFINE_KEYCODE(J), DEFINE_KEYCODE(K), DEFINE_KEYCODE(L), DEFINE_KEYCODE(M), DEFINE_KEYCODE(N), DEFINE_KEYCODE(O), DEFINE_KEYCODE(P), DEFINE_KEYCODE(Q), DEFINE_KEYCODE(R), DEFINE_KEYCODE(S), DEFINE_KEYCODE(T), DEFINE_KEYCODE(U), DEFINE_KEYCODE(V), DEFINE_KEYCODE(W), DEFINE_KEYCODE(X), DEFINE_KEYCODE(Y), DEFINE_KEYCODE(Z), DEFINE_KEYCODE(COMMA), DEFINE_KEYCODE(PERIOD), DEFINE_KEYCODE(ALT_LEFT), DEFINE_KEYCODE(ALT_RIGHT), DEFINE_KEYCODE(SHIFT_LEFT), DEFINE_KEYCODE(SHIFT_RIGHT), DEFINE_KEYCODE(TAB), DEFINE_KEYCODE(SPACE), DEFINE_KEYCODE(SYM), DEFINE_KEYCODE(EXPLORER), DEFINE_KEYCODE(ENVELOPE), DEFINE_KEYCODE(ENTER), DEFINE_KEYCODE(DEL), DEFINE_KEYCODE(GRAVE), DEFINE_KEYCODE(MINUS), DEFINE_KEYCODE(EQUALS), DEFINE_KEYCODE(LEFT_BRACKET), DEFINE_KEYCODE(RIGHT_BRACKET), DEFINE_KEYCODE(BACKSLASH), DEFINE_KEYCODE(SEMICOLON), DEFINE_KEYCODE(APOSTROPHE), DEFINE_KEYCODE(SLASH), DEFINE_KEYCODE(AT), DEFINE_KEYCODE(NUM), DEFINE_KEYCODE(HEADSETHOOK), DEFINE_KEYCODE(FOCUS), // *Camera* focus DEFINE_KEYCODE(PLUS), DEFINE_KEYCODE(MENU), DEFINE_KEYCODE(NOTIFICATION), DEFINE_KEYCODE(SEARCH), DEFINE_KEYCODE(MEDIA_PLAY_PAUSE), DEFINE_KEYCODE(MEDIA_STOP), DEFINE_KEYCODE(MEDIA_NEXT), DEFINE_KEYCODE(MEDIA_PREVIOUS), DEFINE_KEYCODE(MEDIA_REWIND), DEFINE_KEYCODE(MEDIA_FAST_FORWARD), DEFINE_KEYCODE(MUTE), DEFINE_KEYCODE(PAGE_UP), DEFINE_KEYCODE(PAGE_DOWN), DEFINE_KEYCODE(PICTSYMBOLS), DEFINE_KEYCODE(SWITCH_CHARSET), DEFINE_KEYCODE(BUTTON_A), DEFINE_KEYCODE(BUTTON_B), DEFINE_KEYCODE(BUTTON_C), DEFINE_KEYCODE(BUTTON_X), DEFINE_KEYCODE(BUTTON_Y), DEFINE_KEYCODE(BUTTON_Z), DEFINE_KEYCODE(BUTTON_L1), DEFINE_KEYCODE(BUTTON_R1), DEFINE_KEYCODE(BUTTON_L2), DEFINE_KEYCODE(BUTTON_R2), DEFINE_KEYCODE(BUTTON_THUMBL), DEFINE_KEYCODE(BUTTON_THUMBR), DEFINE_KEYCODE(BUTTON_START), DEFINE_KEYCODE(BUTTON_SELECT), DEFINE_KEYCODE(BUTTON_MODE), DEFINE_KEYCODE(ESCAPE), DEFINE_KEYCODE(FORWARD_DEL), DEFINE_KEYCODE(CTRL_LEFT), DEFINE_KEYCODE(CTRL_RIGHT), DEFINE_KEYCODE(CAPS_LOCK), DEFINE_KEYCODE(SCROLL_LOCK), DEFINE_KEYCODE(META_LEFT), DEFINE_KEYCODE(META_RIGHT), DEFINE_KEYCODE(FUNCTION), DEFINE_KEYCODE(SYSRQ), DEFINE_KEYCODE(BREAK), DEFINE_KEYCODE(MOVE_HOME), DEFINE_KEYCODE(MOVE_END), DEFINE_KEYCODE(INSERT), DEFINE_KEYCODE(FORWARD), DEFINE_KEYCODE(MEDIA_PLAY), DEFINE_KEYCODE(MEDIA_PAUSE), DEFINE_KEYCODE(MEDIA_CLOSE), DEFINE_KEYCODE(MEDIA_EJECT), DEFINE_KEYCODE(MEDIA_RECORD), DEFINE_KEYCODE(F1), DEFINE_KEYCODE(F2), DEFINE_KEYCODE(F3), DEFINE_KEYCODE(F4), DEFINE_KEYCODE(F5), DEFINE_KEYCODE(F6), DEFINE_KEYCODE(F7), DEFINE_KEYCODE(F8), DEFINE_KEYCODE(F9), DEFINE_KEYCODE(F10), DEFINE_KEYCODE(F11), DEFINE_KEYCODE(F12), DEFINE_KEYCODE(NUM_LOCK), DEFINE_KEYCODE(NUMPAD_0), DEFINE_KEYCODE(NUMPAD_1), DEFINE_KEYCODE(NUMPAD_2), DEFINE_KEYCODE(NUMPAD_3), DEFINE_KEYCODE(NUMPAD_4), DEFINE_KEYCODE(NUMPAD_5), DEFINE_KEYCODE(NUMPAD_6), DEFINE_KEYCODE(NUMPAD_7), DEFINE_KEYCODE(NUMPAD_8), DEFINE_KEYCODE(NUMPAD_9), DEFINE_KEYCODE(NUMPAD_DIVIDE), DEFINE_KEYCODE(NUMPAD_MULTIPLY), DEFINE_KEYCODE(NUMPAD_SUBTRACT), DEFINE_KEYCODE(NUMPAD_ADD), DEFINE_KEYCODE(NUMPAD_DOT), DEFINE_KEYCODE(NUMPAD_COMMA), DEFINE_KEYCODE(NUMPAD_ENTER), DEFINE_KEYCODE(NUMPAD_EQUALS), DEFINE_KEYCODE(NUMPAD_LEFT_PAREN), DEFINE_KEYCODE(NUMPAD_RIGHT_PAREN), DEFINE_KEYCODE(VOLUME_MUTE), DEFINE_KEYCODE(INFO), DEFINE_KEYCODE(CHANNEL_UP), DEFINE_KEYCODE(CHANNEL_DOWN), DEFINE_KEYCODE(ZOOM_IN), DEFINE_KEYCODE(ZOOM_OUT), DEFINE_KEYCODE(TV), DEFINE_KEYCODE(WINDOW), DEFINE_KEYCODE(GUIDE), DEFINE_KEYCODE(DVR), DEFINE_KEYCODE(BOOKMARK), DEFINE_KEYCODE(CAPTIONS), DEFINE_KEYCODE(SETTINGS), DEFINE_KEYCODE(TV_POWER), DEFINE_KEYCODE(TV_INPUT), DEFINE_KEYCODE(STB_POWER), DEFINE_KEYCODE(STB_INPUT), DEFINE_KEYCODE(AVR_POWER), DEFINE_KEYCODE(AVR_INPUT), DEFINE_KEYCODE(PROG_RED), DEFINE_KEYCODE(PROG_GREEN), DEFINE_KEYCODE(PROG_YELLOW), DEFINE_KEYCODE(PROG_BLUE), DEFINE_KEYCODE(APP_SWITCH), DEFINE_KEYCODE(BUTTON_1), DEFINE_KEYCODE(BUTTON_2), DEFINE_KEYCODE(BUTTON_3), DEFINE_KEYCODE(BUTTON_4), DEFINE_KEYCODE(BUTTON_5), DEFINE_KEYCODE(BUTTON_6), DEFINE_KEYCODE(BUTTON_7), DEFINE_KEYCODE(BUTTON_8), DEFINE_KEYCODE(BUTTON_9), DEFINE_KEYCODE(BUTTON_10), DEFINE_KEYCODE(BUTTON_11), DEFINE_KEYCODE(BUTTON_12), DEFINE_KEYCODE(BUTTON_13), DEFINE_KEYCODE(BUTTON_14), DEFINE_KEYCODE(BUTTON_15), DEFINE_KEYCODE(BUTTON_16), DEFINE_KEYCODE(LANGUAGE_SWITCH), DEFINE_KEYCODE(MANNER_MODE), DEFINE_KEYCODE(3D_MODE), DEFINE_KEYCODE(CONTACTS), DEFINE_KEYCODE(CALENDAR), DEFINE_KEYCODE(MUSIC), DEFINE_KEYCODE(CALCULATOR), DEFINE_KEYCODE(ZENKAKU_HANKAKU), DEFINE_KEYCODE(EISU), DEFINE_KEYCODE(MUHENKAN), DEFINE_KEYCODE(HENKAN), DEFINE_KEYCODE(KATAKANA_HIRAGANA), DEFINE_KEYCODE(YEN), DEFINE_KEYCODE(RO), DEFINE_KEYCODE(KANA), DEFINE_KEYCODE(ASSIST), DEFINE_KEYCODE(BRIGHTNESS_DOWN), DEFINE_KEYCODE(BRIGHTNESS_UP), DEFINE_KEYCODE(MEDIA_AUDIO_TRACK), DEFINE_KEYCODE(SLEEP), DEFINE_KEYCODE(WAKEUP), DEFINE_KEYCODE(PAIRING), DEFINE_KEYCODE(MEDIA_TOP_MENU), DEFINE_KEYCODE(11), DEFINE_KEYCODE(12), DEFINE_KEYCODE(LAST_CHANNEL), DEFINE_KEYCODE(TV_DATA_SERVICE), DEFINE_KEYCODE(VOICE_ASSIST), DEFINE_KEYCODE(TV_RADIO_SERVICE), DEFINE_KEYCODE(TV_TELETEXT), DEFINE_KEYCODE(TV_NUMBER_ENTRY), DEFINE_KEYCODE(TV_TERRESTRIAL_ANALOG), DEFINE_KEYCODE(TV_TERRESTRIAL_DIGITAL), DEFINE_KEYCODE(TV_SATELLITE), DEFINE_KEYCODE(TV_SATELLITE_BS), DEFINE_KEYCODE(TV_SATELLITE_CS), DEFINE_KEYCODE(TV_SATELLITE_SERVICE), DEFINE_KEYCODE(TV_NETWORK), DEFINE_KEYCODE(TV_ANTENNA_CABLE), DEFINE_KEYCODE(TV_INPUT_HDMI_1), DEFINE_KEYCODE(TV_INPUT_HDMI_2), DEFINE_KEYCODE(TV_INPUT_HDMI_3), DEFINE_KEYCODE(TV_INPUT_HDMI_4), DEFINE_KEYCODE(TV_INPUT_COMPOSITE_1), DEFINE_KEYCODE(TV_INPUT_COMPOSITE_2), DEFINE_KEYCODE(TV_INPUT_COMPONENT_1), DEFINE_KEYCODE(TV_INPUT_COMPONENT_2), DEFINE_KEYCODE(TV_INPUT_VGA_1), DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION), DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_UP), DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_DOWN), DEFINE_KEYCODE(TV_ZOOM_MODE), DEFINE_KEYCODE(TV_CONTENTS_MENU), DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), DEFINE_KEYCODE(HELP), DEFINE_KEYCODE(NAVIGATE_PREVIOUS), DEFINE_KEYCODE(NAVIGATE_NEXT), DEFINE_KEYCODE(NAVIGATE_IN), DEFINE_KEYCODE(NAVIGATE_OUT), DEFINE_KEYCODE(STEM_PRIMARY), DEFINE_KEYCODE(STEM_1), DEFINE_KEYCODE(STEM_2), DEFINE_KEYCODE(STEM_3), DEFINE_KEYCODE(DPAD_UP_LEFT), DEFINE_KEYCODE(DPAD_DOWN_LEFT), DEFINE_KEYCODE(DPAD_UP_RIGHT), DEFINE_KEYCODE(DPAD_DOWN_RIGHT), DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), DEFINE_KEYCODE(MEDIA_STEP_FORWARD), DEFINE_KEYCODE(MEDIA_STEP_BACKWARD), DEFINE_KEYCODE(SOFT_SLEEP), DEFINE_KEYCODE(CUT), DEFINE_KEYCODE(COPY), DEFINE_KEYCODE(PASTE), { NULL, 0 } }; static const InputEventLabel AXES[] = { DEFINE_AXIS(X), DEFINE_AXIS(Y), DEFINE_AXIS(PRESSURE), DEFINE_AXIS(SIZE), DEFINE_AXIS(TOUCH_MAJOR), DEFINE_AXIS(TOUCH_MINOR), DEFINE_AXIS(TOOL_MAJOR), DEFINE_AXIS(TOOL_MINOR), DEFINE_AXIS(ORIENTATION), DEFINE_AXIS(VSCROLL), DEFINE_AXIS(HSCROLL), DEFINE_AXIS(Z), DEFINE_AXIS(RX), DEFINE_AXIS(RY), DEFINE_AXIS(RZ), DEFINE_AXIS(HAT_X), DEFINE_AXIS(HAT_Y), DEFINE_AXIS(LTRIGGER), DEFINE_AXIS(RTRIGGER), DEFINE_AXIS(THROTTLE), DEFINE_AXIS(RUDDER), DEFINE_AXIS(WHEEL), DEFINE_AXIS(GAS), DEFINE_AXIS(BRAKE), DEFINE_AXIS(DISTANCE), DEFINE_AXIS(TILT), DEFINE_AXIS(GENERIC_1), DEFINE_AXIS(GENERIC_2), DEFINE_AXIS(GENERIC_3), DEFINE_AXIS(GENERIC_4), DEFINE_AXIS(GENERIC_5), DEFINE_AXIS(GENERIC_6), DEFINE_AXIS(GENERIC_7), DEFINE_AXIS(GENERIC_8), DEFINE_AXIS(GENERIC_9), DEFINE_AXIS(GENERIC_10), DEFINE_AXIS(GENERIC_11), DEFINE_AXIS(GENERIC_12), DEFINE_AXIS(GENERIC_13), DEFINE_AXIS(GENERIC_14), DEFINE_AXIS(GENERIC_15), DEFINE_AXIS(GENERIC_16), // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. { NULL, 0 } }; static const InputEventLabel LEDS[] = { DEFINE_LED(NUM_LOCK), DEFINE_LED(CAPS_LOCK), DEFINE_LED(SCROLL_LOCK), DEFINE_LED(COMPOSE), DEFINE_LED(KANA), DEFINE_LED(SLEEP), DEFINE_LED(SUSPEND), DEFINE_LED(MUTE), DEFINE_LED(MISC), DEFINE_LED(MAIL), DEFINE_LED(CHARGING), DEFINE_LED(CONTROLLER_1), DEFINE_LED(CONTROLLER_2), DEFINE_LED(CONTROLLER_3), DEFINE_LED(CONTROLLER_4), // NOTE: If you add new LEDs here, you must also add them to Input.h { NULL, 0 } }; static const InputEventLabel FLAGS[] = { DEFINE_FLAG(VIRTUAL), DEFINE_FLAG(FUNCTION), DEFINE_FLAG(GESTURE), { NULL, 0 } }; static int lookupValueByLabel(const char* literal, const InputEventLabel *list) { while (list->literal) { if (strcmp(literal, list->literal) == 0) { return list->value; } list++; } return list->value; } static const char* lookupLabelByValue(int value, const InputEventLabel* list) { while (list->literal) { if (list->value == value) { return list->literal; } list++; } return NULL; } static int32_t getKeyCodeByLabel(const char* label) { return int32_t(lookupValueByLabel(label, KEYCODES)); } static const char* getLabelByKeyCode(int32_t keyCode) { if (keyCode >= 0 && keyCode < size(KEYCODES)) { return KEYCODES[keyCode].literal; } return NULL; } static uint32_t getKeyFlagByLabel(const char* label) { return uint32_t(lookupValueByLabel(label, FLAGS)); } static int32_t getAxisByLabel(const char* label) { return int32_t(lookupValueByLabel(label, AXES)); } static const char* getAxisLabel(int32_t axisId) { return lookupLabelByValue(axisId, AXES); } static int32_t getLedByLabel(const char* label) { return int32_t(lookupValueByLabel(label, LEDS)); } } // namespace android #endif // _LIBINPUT_INPUT_EVENT_LABELS_H include/input/InputTransport.h0100644 0000000 0000000 00000037607 13077405420 015573 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _LIBINPUT_INPUT_TRANSPORT_H #define _LIBINPUT_INPUT_TRANSPORT_H /** * Native input transport. * * The InputChannel provides a mechanism for exchanging InputMessage structures across processes. * * The InputPublisher and InputConsumer each handle one end-point of an input channel. * The InputPublisher is used by the input dispatcher to send events to the application. * The InputConsumer is used by the application to receive events from the input dispatcher. */ #include #include #include #include #include #include #include namespace android { /* * Intermediate representation used to send input events and related signals. * * Note that this structure is used for IPCs so its layout must be identical * on 64 and 32 bit processes. This is tested in StructLayout_test.cpp. */ struct InputMessage { enum { TYPE_KEY = 1, TYPE_MOTION = 2, TYPE_FINISHED = 3, }; struct Header { uint32_t type; // We don't need this field in order to align the body below but we // leave it here because InputMessage::size() and other functions // compute the size of this structure as sizeof(Header) + sizeof(Body). uint32_t padding; } header; // Body *must* be 8 byte aligned. union Body { struct Key { uint32_t seq; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t repeatCount; nsecs_t downTime __attribute__((aligned(8))); inline size_t size() const { return sizeof(Key); } } key; struct Motion { uint32_t seq; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; int32_t action; int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); float xOffset; float yOffset; float xPrecision; float yPrecision; uint32_t pointerCount; // Note that PointerCoords requires 8 byte alignment. struct Pointer { PointerProperties properties; PointerCoords coords; } pointers[MAX_POINTERS]; int32_t getActionId() const { uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; return pointers[index].properties.id; } inline size_t size() const { return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS + sizeof(Pointer) * pointerCount; } } motion; struct Finished { uint32_t seq; bool handled; inline size_t size() const { return sizeof(Finished); } } finished; } __attribute__((aligned(8))) body; bool isValid(size_t actualSize) const; size_t size() const; }; /* * An input channel consists of a local unix domain socket used to send and receive * input messages across processes. Each channel has a descriptive name for debugging purposes. * * Each endpoint has its own InputChannel object that specifies its file descriptor. * * The input channel is closed when all references to it are released. */ class InputChannel : public RefBase { protected: virtual ~InputChannel(); public: InputChannel(const String8& name, int fd); /* Creates a pair of input channels. * * Returns OK on success. */ static status_t openInputChannelPair(const String8& name, sp& outServerChannel, sp& outClientChannel); inline String8 getName() const { return mName; } inline int getFd() const { return mFd; } /* Sends a message to the other endpoint. * * If the channel is full then the message is guaranteed not to have been sent at all. * Try again after the consumer has sent a finished signal indicating that it has * consumed some of the pending messages from the channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t sendMessage(const InputMessage* msg); /* Receives a message sent by the other endpoint. * * If there is no message present, try again after poll() indicates that the fd * is readable. * * Returns OK on success. * Returns WOULD_BLOCK if there is no message present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t receiveMessage(InputMessage* msg); /* Returns a new object that has a duplicate of this channel's fd. */ sp dup() const; private: String8 mName; int mFd; }; /* * Publishes input events to an input channel. */ class InputPublisher { public: /* Creates a publisher associated with an input channel. */ explicit InputPublisher(const sp& channel); /* Destroys the publisher and releases its input channel. */ ~InputPublisher(); /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } /* Publishes a key event to the input channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ status_t publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); /* Publishes a motion event to the input channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. * Other errors probably indicate that the channel is broken. */ status_t publishMotionEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); /* Receives the finished signal from the consumer in reply to the original dispatch signal. * If a signal was received, returns the message sequence number, * and whether the consumer handled the message. * * The returned sequence number is never 0 unless the operation failed. * * Returns OK on success. * Returns WOULD_BLOCK if there is no signal present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled); private: sp mChannel; }; /* * Consumes input events from an input channel. */ class InputConsumer { public: /* Creates a consumer associated with an input channel. */ explicit InputConsumer(const sp& channel); /* Destroys the consumer and releases its input channel. */ ~InputConsumer(); /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } /* Consumes an input event from the input channel and copies its contents into * an InputEvent object created using the specified factory. * * Tries to combine a series of move events into larger batches whenever possible. * * If consumeBatches is false, then defers consuming pending batched events if it * is possible for additional samples to be added to them later. Call hasPendingBatch() * to determine whether a pending batch is available to be consumed. * * If consumeBatches is true, then events are still batched but they are consumed * immediately as soon as the input channel is exhausted. * * The frameTime parameter specifies the time when the current display frame started * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown. * * The returned sequence number is never 0 unless the operation failed. * * Returns OK on success. * Returns WOULD_BLOCK if there is no event present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns NO_MEMORY if the event could not be created. * Other errors probably indicate that the channel is broken. */ status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); /* Sends a finished signal to the publisher to inform it that the message * with the specified sequence number has finished being process and whether * the message was handled by the consumer. * * Returns OK on success. * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ status_t sendFinishedSignal(uint32_t seq, bool handled); /* Returns true if there is a deferred event waiting. * * Should be called after calling consume() to determine whether the consumer * has a deferred event to be processed. Deferred events are somewhat special in * that they have already been removed from the input channel. If the input channel * becomes empty, the client may need to do extra work to ensure that it processes * the deferred event despite the fact that the input channel's file descriptor * is not readable. * * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. * This guarantees that all deferred events will be processed. * * Alternately, the caller can call hasDeferredEvent() to determine whether there is * a deferred event waiting and then ensure that its event loop wakes up at least * one more time to consume the deferred event. */ bool hasDeferredEvent() const; /* Returns true if there is a pending batch. * * Should be called after calling consume() with consumeBatches == false to determine * whether consume() should be called again later on with consumeBatches == true. */ bool hasPendingBatch() const; private: // True if touch resampling is enabled. const bool mResampleTouch; // The input channel. sp mChannel; // The current input message. InputMessage mMsg; // True if mMsg contains a valid input message that was deferred from the previous // call to consume and that still needs to be handled. bool mMsgDeferred; // Batched motion events per device and source. struct Batch { Vector samples; }; Vector mBatches; // Touch state per device and source, only for sources of class pointer. struct History { nsecs_t eventTime; BitSet32 idBits; int32_t idToIndex[MAX_POINTER_ID + 1]; PointerCoords pointers[MAX_POINTERS]; void initializeFrom(const InputMessage* msg) { eventTime = msg->body.motion.eventTime; idBits.clear(); for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) { uint32_t id = msg->body.motion.pointers[i].properties.id; idBits.markBit(id); idToIndex[id] = i; pointers[i].copyFrom(msg->body.motion.pointers[i].coords); } } const PointerCoords& getPointerById(uint32_t id) const { return pointers[idToIndex[id]]; } }; struct TouchState { int32_t deviceId; int32_t source; size_t historyCurrent; size_t historySize; History history[2]; History lastResample; void initialize(int32_t deviceId, int32_t source) { this->deviceId = deviceId; this->source = source; historyCurrent = 0; historySize = 0; lastResample.eventTime = 0; lastResample.idBits.clear(); } void addHistory(const InputMessage* msg) { historyCurrent ^= 1; if (historySize < 2) { historySize += 1; } history[historyCurrent].initializeFrom(msg); } const History* getHistory(size_t index) const { return &history[(historyCurrent + index) & 1]; } }; Vector mTouchStates; // Chain of batched sequence numbers. When multiple input messages are combined into // a batch, we append a record here that associates the last sequence number in the // batch with the previous one. When the finished signal is sent, we traverse the // chain to individually finish all input messages that were part of the batch. struct SeqChain { uint32_t seq; // sequence number of batched input message uint32_t chain; // sequence number of previous batched input message }; Vector mSeqChains; status_t consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); status_t consumeSamples(InputEventFactoryInterface* factory, Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent); void updateTouchState(InputMessage* msg); void rewriteMessage(const TouchState& state, InputMessage* msg); void resampleTouchState(nsecs_t frameTime, MotionEvent* event, const InputMessage *next); ssize_t findBatch(int32_t deviceId, int32_t source) const; ssize_t findTouchState(int32_t deviceId, int32_t source) const; status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled); static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); static void addSample(MotionEvent* event, const InputMessage* msg); static bool canAddSample(const Batch& batch, const InputMessage* msg); static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); static bool shouldResampleTool(int32_t toolType); static bool isTouchResamplingEnabled(); }; } // namespace android #endif // _LIBINPUT_INPUT_TRANSPORT_H include/input/KeyCharacterMap.h0100644 0000000 0000000 00000021641 13077405420 015551 0ustar000000000 0000000 /* * Copyright (C) 2008 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 _LIBINPUT_KEY_CHARACTER_MAP_H #define _LIBINPUT_KEY_CHARACTER_MAP_H #include #ifdef __ANDROID__ #include #endif #include #include #include #include #include #include #include // Maximum number of keys supported by KeyCharacterMaps #define MAX_KEYS 8192 namespace android { /** * Describes a mapping from Android key codes to characters. * Also specifies other functions of the keyboard such as the keyboard type * and key modifier semantics. * * This object is immutable after it has been loaded. */ class KeyCharacterMap : public RefBase { public: enum KeyboardType { KEYBOARD_TYPE_UNKNOWN = 0, KEYBOARD_TYPE_NUMERIC = 1, KEYBOARD_TYPE_PREDICTIVE = 2, KEYBOARD_TYPE_ALPHA = 3, KEYBOARD_TYPE_FULL = 4, KEYBOARD_TYPE_SPECIAL_FUNCTION = 5, KEYBOARD_TYPE_OVERLAY = 6, }; enum Format { // Base keyboard layout, may contain device-specific options, such as "type" declaration. FORMAT_BASE = 0, // Overlay keyboard layout, more restrictive, may be published by applications, // cannot override device-specific options. FORMAT_OVERLAY = 1, // Either base or overlay layout ok. FORMAT_ANY = 2, }; // Substitute key code and meta state for fallback action. struct FallbackAction { int32_t keyCode; int32_t metaState; }; /* Loads a key character map from a file. */ static status_t load(const String8& filename, Format format, sp* outMap); /* Loads a key character map from its string contents. */ static status_t loadContents(const String8& filename, const char* contents, Format format, sp* outMap); /* Combines a base key character map and an overlay. */ static sp combine(const sp& base, const sp& overlay); /* Returns an empty key character map. */ static sp empty(); /* Gets the keyboard type. */ int32_t getKeyboardType() const; /* Gets the primary character for this key as in the label physically printed on it. * Returns 0 if none (eg. for non-printing keys). */ char16_t getDisplayLabel(int32_t keyCode) const; /* Gets the Unicode character for the number or symbol generated by the key * when the keyboard is used as a dialing pad. * Returns 0 if no number or symbol is generated. */ char16_t getNumber(int32_t keyCode) const; /* Gets the Unicode character generated by the key and meta key modifiers. * Returns 0 if no character is generated. */ char16_t getCharacter(int32_t keyCode, int32_t metaState) const; /* Gets the fallback action to use by default if the application does not * handle the specified key. * Returns true if an action was available, false if none. */ bool getFallbackAction(int32_t keyCode, int32_t metaState, FallbackAction* outFallbackAction) const; /* Gets the first matching Unicode character that can be generated by the key, * preferring the one with the specified meta key modifiers. * Returns 0 if no matching character is generated. */ char16_t getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, int32_t metaState) const; /* Gets a sequence of key events that could plausibly generate the specified * character sequence. Returns false if some of the characters cannot be generated. */ bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector& outEvents) const; /* Maps a scan code and usage code to a key code, in case this key map overrides * the mapping in some way. */ status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const; /* Tries to find a replacement key code for a given key code and meta state * in character map. */ void tryRemapKey(int32_t scanCode, int32_t metaState, int32_t* outKeyCode, int32_t* outMetaState) const; #ifdef __ANDROID__ /* Reads a key map from a parcel. */ static sp readFromParcel(Parcel* parcel); /* Writes a key map to a parcel. */ void writeToParcel(Parcel* parcel) const; #endif protected: virtual ~KeyCharacterMap(); private: struct Behavior { Behavior(); Behavior(const Behavior& other); /* The next behavior in the list, or NULL if none. */ Behavior* next; /* The meta key modifiers for this behavior. */ int32_t metaState; /* The character to insert. */ char16_t character; /* The fallback keycode if the key is not handled. */ int32_t fallbackKeyCode; /* The replacement keycode if the key has to be replaced outright. */ int32_t replacementKeyCode; }; struct Key { Key(); Key(const Key& other); ~Key(); /* The single character label printed on the key, or 0 if none. */ char16_t label; /* The number or symbol character generated by the key, or 0 if none. */ char16_t number; /* The list of key behaviors sorted from most specific to least specific * meta key binding. */ Behavior* firstBehavior; }; class Parser { enum State { STATE_TOP = 0, STATE_KEY = 1, }; enum { PROPERTY_LABEL = 1, PROPERTY_NUMBER = 2, PROPERTY_META = 3, }; struct Property { inline Property(int32_t property = 0, int32_t metaState = 0) : property(property), metaState(metaState) { } int32_t property; int32_t metaState; }; KeyCharacterMap* mMap; Tokenizer* mTokenizer; Format mFormat; State mState; int32_t mKeyCode; public: Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format); ~Parser(); status_t parse(); private: status_t parseType(); status_t parseMap(); status_t parseMapKey(); status_t parseKey(); status_t parseKeyProperty(); status_t finishKey(Key* key); status_t parseModifier(const String8& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; static sp sEmpty; KeyedVector mKeys; int mType; KeyedVector mKeysByScanCode; KeyedVector mKeysByUsageCode; KeyCharacterMap(); KeyCharacterMap(const KeyCharacterMap& other); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, const Key** outKey, const Behavior** outBehavior) const; static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; static status_t load(Tokenizer* tokenizer, Format format, sp* outMap); static void addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t* currentMetaState); static bool addSingleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); static void addDoubleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t leftKeyCode, int32_t leftKeyMetaState, int32_t rightKeyCode, int32_t rightKeyMetaState, int32_t eitherKeyMetaState, int32_t* currentMetaState); static void addLockedMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); }; } // namespace android #endif // _LIBINPUT_KEY_CHARACTER_MAP_H include/input/KeyLayoutMap.h0100644 0000000 0000000 00000006205 13077405420 015131 0ustar000000000 0000000 /* * Copyright (C) 2008 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 _LIBINPUT_KEY_LAYOUT_MAP_H #define _LIBINPUT_KEY_LAYOUT_MAP_H #include #include #include #include #include namespace android { struct AxisInfo { enum Mode { // Axis value is reported directly. MODE_NORMAL = 0, // Axis value should be inverted before reporting. MODE_INVERT = 1, // Axis value should be split into two axes MODE_SPLIT = 2, }; // Axis mode. Mode mode; // Axis id. // When split, this is the axis used for values smaller than the split position. int32_t axis; // When split, this is the axis used for values after higher than the split position. int32_t highAxis; // The split value, or 0 if not split. int32_t splitValue; // The flat value, or -1 if none. int32_t flatOverride; AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) { } }; /** * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. * * This object is immutable after it has been loaded. */ class KeyLayoutMap : public RefBase { public: static status_t load(const String8& filename, sp* outMap); status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode, uint32_t* outFlags) const; status_t findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const; status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const; status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const; status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const; protected: virtual ~KeyLayoutMap(); private: struct Key { int32_t keyCode; uint32_t flags; }; struct Led { int32_t ledCode; }; KeyedVector mKeysByScanCode; KeyedVector mKeysByUsageCode; KeyedVector mAxes; KeyedVector mLedsByScanCode; KeyedVector mLedsByUsageCode; KeyLayoutMap(); const Key* getKey(int32_t scanCode, int32_t usageCode) const; class Parser { KeyLayoutMap* mMap; Tokenizer* mTokenizer; public: Parser(KeyLayoutMap* map, Tokenizer* tokenizer); ~Parser(); status_t parse(); private: status_t parseKey(); status_t parseAxis(); status_t parseLed(); }; }; } // namespace android #endif // _LIBINPUT_KEY_LAYOUT_MAP_H include/input/Keyboard.h0100644 0000000 0000000 00000006046 13077405420 014310 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _LIBINPUT_KEYBOARD_H #define _LIBINPUT_KEYBOARD_H #include #include #include #include #include #include namespace android { enum { /* Device id of the built in keyboard. */ DEVICE_ID_BUILT_IN_KEYBOARD = 0, /* Device id of a generic virtual keyboard with a full layout that can be used * to synthesize key events. */ DEVICE_ID_VIRTUAL_KEYBOARD = -1, }; class KeyLayoutMap; class KeyCharacterMap; /** * Loads the key layout map and key character map for a keyboard device. */ class KeyMap { public: String8 keyLayoutFile; sp keyLayoutMap; String8 keyCharacterMapFile; sp keyCharacterMap; KeyMap(); ~KeyMap(); status_t load(const InputDeviceIdentifier& deviceIdenfier, const PropertyMap* deviceConfiguration); inline bool haveKeyLayout() const { return !keyLayoutFile.isEmpty(); } inline bool haveKeyCharacterMap() const { return !keyCharacterMapFile.isEmpty(); } inline bool isComplete() const { return haveKeyLayout() && haveKeyCharacterMap(); } private: bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name); status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); String8 getPath(const InputDeviceIdentifier& deviceIdentifier, const String8& name, InputDeviceConfigurationFileType type); }; /** * Returns true if the keyboard is eligible for use as a built-in keyboard. */ extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap); /** * Updates a meta state field when a key is pressed or released. */ extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); /** * Normalizes the meta state such that if either the left or right modifier * meta state bits are set then the result will also include the universal * bit for that modifier. */ extern int32_t normalizeMetaState(int32_t oldMetaState); /** * Returns true if a key is a meta key like ALT or CAPS_LOCK. */ extern bool isMetaKey(int32_t keyCode); } // namespace android #endif // _LIBINPUT_KEYBOARD_H include/input/VelocityControl.h0100644 0000000 0000000 00000007232 13077405420 015705 0ustar000000000 0000000 /* * Copyright (C) 2012 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 _LIBINPUT_VELOCITY_CONTROL_H #define _LIBINPUT_VELOCITY_CONTROL_H #include #include #include namespace android { /* * Specifies parameters that govern pointer or wheel acceleration. */ struct VelocityControlParameters { // A scale factor that is multiplied with the raw velocity deltas // prior to applying any other velocity control factors. The scale // factor should be used to adapt the input device resolution // (eg. counts per inch) to the output device resolution (eg. pixels per inch). // // Must be a positive value. // Default is 1.0 (no scaling). float scale; // The scaled speed at which acceleration begins to be applied. // This value establishes the upper bound of a low speed regime for // small precise motions that are performed without any acceleration. // // Must be a non-negative value. // Default is 0.0 (no low threshold). float lowThreshold; // The scaled speed at which maximum acceleration is applied. // The difference between highThreshold and lowThreshold controls // the range of speeds over which the acceleration factor is interpolated. // The wider the range, the smoother the acceleration. // // Must be a non-negative value greater than or equal to lowThreshold. // Default is 0.0 (no high threshold). float highThreshold; // The acceleration factor. // When the speed is above the low speed threshold, the velocity will scaled // by an interpolated value between 1.0 and this amount. // // Must be a positive greater than or equal to 1.0. // Default is 1.0 (no acceleration). float acceleration; VelocityControlParameters() : scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { } VelocityControlParameters(float scale, float lowThreshold, float highThreshold, float acceleration) : scale(scale), lowThreshold(lowThreshold), highThreshold(highThreshold), acceleration(acceleration) { } }; /* * Implements mouse pointer and wheel speed control and acceleration. */ class VelocityControl { public: VelocityControl(); /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); /* Resets the current movement counters to zero. * This has the effect of nullifying any acceleration. */ void reset(); /* Translates a raw movement delta into an appropriately * scaled / accelerated delta based on the current velocity. */ void move(nsecs_t eventTime, float* deltaX, float* deltaY); private: // If no movements are received within this amount of time, // we assume the movement has stopped and reset the movement counters. static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms VelocityControlParameters mParameters; nsecs_t mLastMovementTime; VelocityTracker::Position mRawPosition; VelocityTracker mVelocityTracker; }; } // namespace android #endif // _LIBINPUT_VELOCITY_CONTROL_H include/input/VelocityTracker.h0100644 0000000 0000000 00000021147 13077405420 015661 0ustar000000000 0000000 /* * Copyright (C) 2012 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 _LIBINPUT_VELOCITY_TRACKER_H #define _LIBINPUT_VELOCITY_TRACKER_H #include #include #include namespace android { class VelocityTrackerStrategy; /* * Calculates the velocity of pointer movements over time. */ class VelocityTracker { public: struct Position { float x, y; }; struct Estimator { static const size_t MAX_DEGREE = 4; // Estimator time base. nsecs_t time; // Polynomial coefficients describing motion in X and Y. float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; // Polynomial degree (number of coefficients), or zero if no information is // available. uint32_t degree; // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). float confidence; inline void clear() { time = 0; degree = 0; confidence = 0; for (size_t i = 0; i <= MAX_DEGREE; i++) { xCoeff[i] = 0; yCoeff[i] = 0; } } }; // Creates a velocity tracker using the specified strategy. // If strategy is NULL, uses the default strategy for the platform. VelocityTracker(const char* strategy = NULL); ~VelocityTracker(); // Resets the velocity tracker state. void clear(); // Resets the velocity tracker state for specific pointers. // Call this method when some pointers have changed and may be reusing // an id that was assigned to a different pointer earlier. void clearPointers(BitSet32 idBits); // Adds movement information for a set of pointers. // The idBits bitfield specifies the pointer ids of the pointers whose positions // are included in the movement. // The positions array contains position information for each pointer in order by // increasing id. Its size should be equal to the number of one bits in idBits. void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions); // Adds movement information for all pointers in a MotionEvent, including historical samples. void addMovement(const MotionEvent* event); // Gets the velocity of the specified pointer id in position units per second. // Returns false and sets the velocity components to zero if there is // insufficient movement information for the pointer. bool getVelocity(uint32_t id, float* outVx, float* outVy) const; // Gets an estimator for the recent movements of the specified pointer id. // Returns false and clears the estimator if there is no information available // about the pointer. bool getEstimator(uint32_t id, Estimator* outEstimator) const; // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId; } // Gets a bitset containing all pointer ids from the most recent movement. inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } private: static const char* DEFAULT_STRATEGY; nsecs_t mLastEventTime; BitSet32 mCurrentPointerIdBits; int32_t mActivePointerId; VelocityTrackerStrategy* mStrategy; bool configureStrategy(const char* strategy); static VelocityTrackerStrategy* createStrategy(const char* strategy); }; /* * Implements a particular velocity tracker algorithm. */ class VelocityTrackerStrategy { protected: VelocityTrackerStrategy() { } public: virtual ~VelocityTrackerStrategy() { } virtual void clear() = 0; virtual void clearPointers(BitSet32 idBits) = 0; virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions) = 0; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; }; /* * Velocity tracker algorithm based on least-squares linear regression. */ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { public: enum Weighting { // No weights applied. All data points are equally reliable. WEIGHTING_NONE, // Weight by time delta. Data points clustered together are weighted less. WEIGHTING_DELTA, // Weight such that points within a certain horizon are weighed more than those // outside of that horizon. WEIGHTING_CENTRAL, // Weight such that points older than a certain amount are weighed less. WEIGHTING_RECENT, }; // Degree must be no greater than Estimator::MAX_DEGREE. LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); virtual ~LeastSquaresVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(BitSet32 idBits); virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Sample horizon. // We don't use too much history by default since we want to react to quick // changes in direction. static const nsecs_t HORIZON = 100 * 1000000; // 100 ms // Number of samples to keep. static const uint32_t HISTORY_SIZE = 20; struct Movement { nsecs_t eventTime; BitSet32 idBits; VelocityTracker::Position positions[MAX_POINTERS]; inline const VelocityTracker::Position& getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; float chooseWeight(uint32_t index) const; const uint32_t mDegree; const Weighting mWeighting; uint32_t mIndex; Movement mMovements[HISTORY_SIZE]; }; /* * Velocity tracker algorithm that uses an IIR filter. */ class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { public: // Degree must be 1 or 2. IntegratingVelocityTrackerStrategy(uint32_t degree); ~IntegratingVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(BitSet32 idBits); virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Current state estimate for a particular pointer. struct State { nsecs_t updateTime; uint32_t degree; float xpos, xvel, xaccel; float ypos, yvel, yaccel; }; const uint32_t mDegree; BitSet32 mPointerIdBits; State mPointerState[MAX_POINTER_ID + 1]; void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; /* * Velocity tracker strategy used prior to ICS. */ class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); virtual ~LegacyVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(BitSet32 idBits); virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Oldest sample to consider when calculating the velocity. static const nsecs_t HORIZON = 200 * 1000000; // 100 ms // Number of samples to keep. static const uint32_t HISTORY_SIZE = 20; // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms struct Movement { nsecs_t eventTime; BitSet32 idBits; VelocityTracker::Position positions[MAX_POINTERS]; inline const VelocityTracker::Position& getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; uint32_t mIndex; Movement mMovements[HISTORY_SIZE]; }; } // namespace android #endif // _LIBINPUT_VELOCITY_TRACKER_H include/input/VirtualKeyMap.h0100644 0000000 0000000 00000003742 13077405420 015305 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _LIBINPUT_VIRTUAL_KEY_MAP_H #define _LIBINPUT_VIRTUAL_KEY_MAP_H #include #include #include #include #include #include #include namespace android { /* Describes a virtual key. */ struct VirtualKeyDefinition { int32_t scanCode; // configured position data, specified in display coords int32_t centerX; int32_t centerY; int32_t width; int32_t height; }; /** * Describes a collection of virtual keys on a touch screen in terms of * virtual scan codes and hit rectangles. * * This object is immutable after it has been loaded. */ class VirtualKeyMap { public: ~VirtualKeyMap(); static status_t load(const String8& filename, VirtualKeyMap** outMap); inline const Vector& getVirtualKeys() const { return mVirtualKeys; } private: class Parser { VirtualKeyMap* mMap; Tokenizer* mTokenizer; public: Parser(VirtualKeyMap* map, Tokenizer* tokenizer); ~Parser(); status_t parse(); private: bool consumeFieldDelimiterAndSkipWhitespace(); bool parseNextIntField(int32_t* outValue); }; Vector mVirtualKeys; VirtualKeyMap(); }; } // namespace android #endif // _LIBINPUT_KEY_CHARACTER_MAP_H include/media/0040755 0000000 0000000 00000000000 13077405420 012314 5ustar000000000 0000000 include/media/drm/0040755 0000000 0000000 00000000000 13077405420 013076 5ustar000000000 0000000 include/media/drm/DrmAPI.h0100644 0000000 0000000 00000046347 13077405420 014336 0ustar000000000 0000000 /* * Copyright (C) 2013 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 DRM_API_H_ #define DRM_API_H_ #include #include #include #include #include #include #include // Loadable DrmEngine shared libraries should define the entry points // createDrmFactory and createCryptoFactory as shown below: // // extern "C" { // extern android::DrmFactory *createDrmFactory(); // extern android::CryptoFactory *createCryptoFactory(); // } namespace android { class DrmPlugin; class DrmPluginListener; // DRMs are implemented in DrmEngine plugins, which are dynamically // loadable shared libraries that implement the entry points // createDrmFactory and createCryptoFactory. createDrmFactory // constructs and returns an instance of a DrmFactory object. Similarly, // createCryptoFactory creates an instance of a CryptoFactory object. // When a MediaCrypto or MediaDrm object needs to be constructed, all // available DrmEngines present in the plugins directory on the device // are scanned for a matching DrmEngine that can support the crypto // scheme. When a match is found, the DrmEngine's createCryptoPlugin and // createDrmPlugin methods are used to create CryptoPlugin or // DrmPlugin instances to support that DRM scheme. class DrmFactory { public: DrmFactory() {} virtual ~DrmFactory() {} // DrmFactory::isCryptoSchemeSupported can be called to determine // if the plugin factory is able to construct plugins that support a // given crypto scheme, which is specified by a UUID. virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0; // DrmFactory::isContentTypeSupported can be called to determine // if the plugin factory is able to construct plugins that support a // given media container format specified by mimeType virtual bool isContentTypeSupported(const String8 &mimeType) = 0; // Construct a DrmPlugin for the crypto scheme specified by UUID. virtual status_t createDrmPlugin( const uint8_t uuid[16], DrmPlugin **plugin) = 0; private: DrmFactory(const DrmFactory &); DrmFactory &operator=(const DrmFactory &); }; class DrmPlugin { public: enum EventType { kDrmPluginEventProvisionRequired = 1, kDrmPluginEventKeyNeeded, kDrmPluginEventKeyExpired, kDrmPluginEventVendorDefined, kDrmPluginEventSessionReclaimed, kDrmPluginEventExpirationUpdate, kDrmPluginEventKeysChange, }; // Drm keys can be for offline content or for online streaming. // Offline keys are persisted on the device and may be used when the device // is disconnected from the network. The Release type is used to request // that offline keys be no longer restricted to offline use. enum KeyType { kKeyType_Offline, kKeyType_Streaming, kKeyType_Release }; // Enumerate KeyRequestTypes to allow an app to determine the // type of a key request returned from getKeyRequest. enum KeyRequestType { kKeyRequestType_Unknown, kKeyRequestType_Initial, kKeyRequestType_Renewal, kKeyRequestType_Release }; // Enumerate KeyStatusTypes which indicate the state of a key enum KeyStatusType { kKeyStatusType_Usable, kKeyStatusType_Expired, kKeyStatusType_OutputNotAllowed, kKeyStatusType_StatusPending, kKeyStatusType_InternalError }; // Used by sendKeysChange to report the usability status of each // key to the app. struct KeyStatus { Vector mKeyId; KeyStatusType mType; }; DrmPlugin() {} virtual ~DrmPlugin() {} // Open a new session with the DrmPlugin object. A session ID is returned // in the sessionId parameter. virtual status_t openSession(Vector &sessionId) = 0; // Close a session on the DrmPlugin object. virtual status_t closeSession(Vector const &sessionId) = 0; // A key request/response exchange occurs between the app and a License // Server to obtain the keys required to decrypt the content. getKeyRequest() // is used to obtain an opaque key request blob that is delivered to the // license server. // // The scope parameter may be a sessionId or a keySetId, depending on the // specified keyType. When the keyType is kKeyType_Offline or // kKeyType_Streaming, scope should be set to the sessionId the keys will be // provided to. When the keyType is kKeyType_Release, scope should be set to // the keySetId of the keys being released. Releasing keys from a device // invalidates them for all sessions. // // The init data passed to getKeyRequest is container-specific and its // meaning is interpreted based on the mime type provided in the mimeType // parameter to getKeyRequest. It could contain, for example, the content // ID, key ID or other data obtained from the content metadata that is required // in generating the key request. Init may be null when keyType is // kKeyType_Release. // // mimeType identifies the mime type of the content // // keyType specifies if the keys are to be used for streaming or offline content // // optionalParameters are included in the key request message to allow a // client application to provide additional message parameters to the server. // // If successful, the opaque key request blob is returned to the caller. virtual status_t getKeyRequest(Vector const &scope, Vector const &initData, String8 const &mimeType, KeyType keyType, KeyedVector const &optionalParameters, Vector &request, String8 &defaultUrl, KeyRequestType *keyRequestType) = 0; // // After a key response is received by the app, it is provided to the // Drm plugin using provideKeyResponse. // // scope may be a sessionId or a keySetId depending on the type of the // response. Scope should be set to the sessionId when the response is // for either streaming or offline key requests. Scope should be set to the // keySetId when the response is for a release request. // // When the response is for an offline key request, a keySetId is returned // in the keySetId vector parameter that can be used to later restore the // keys to a new session with the method restoreKeys. When the response is // for a streaming or release request, no keySetId is returned. // virtual status_t provideKeyResponse(Vector const &scope, Vector const &response, Vector &keySetId) = 0; // Remove the current keys from a session virtual status_t removeKeys(Vector const &sessionId) = 0; // Restore persisted offline keys into a new session. keySetId identifies // the keys to load, obtained from a prior call to provideKeyResponse(). virtual status_t restoreKeys(Vector const &sessionId, Vector const &keySetId) = 0; // Request an informative description of the license for the session. The status // is in the form of {name, value} pairs. Since DRM license policies vary by // vendor, the specific status field names are determined by each DRM vendor. // Refer to your DRM provider documentation for definitions of the field names // for a particular DrmEngine. virtual status_t queryKeyStatus(Vector const &sessionId, KeyedVector &infoMap) const = 0; // A provision request/response exchange occurs between the app and a // provisioning server to retrieve a device certificate. getProvisionRequest // is used to obtain an opaque key request blob that is delivered to the // provisioning server. // // If successful, the opaque provision request blob is returned to the caller. virtual status_t getProvisionRequest(String8 const &cert_type, String8 const &cert_authority, Vector &request, String8 &defaultUrl) = 0; // After a provision response is received by the app, it is provided to the // Drm plugin using provideProvisionResponse. virtual status_t provideProvisionResponse(Vector const &response, Vector &certificate, Vector &wrapped_key) = 0; // A means of enforcing the contractual requirement for a concurrent stream // limit per subscriber across devices is provided via SecureStop. SecureStop // is a means of securely monitoring the lifetime of sessions. Since playback // on a device can be interrupted due to reboot, power failure, etc. a means // of persisting the lifetime information on the device is needed. // // A signed version of the sessionID is written to persistent storage on the // device when each MediaCrypto object is created. The sessionID is signed by // the device private key to prevent tampering. // // In the normal case, playback will be completed, the session destroyed and // the Secure Stops will be queried. The App queries secure stops and forwards // the secure stop message to the server which verifies the signature and // notifies the server side database that the session destruction has been // confirmed. The persisted record on the client is only removed after positive // confirmation that the server received the message using releaseSecureStops(). virtual status_t getSecureStops(List > &secureStops) = 0; virtual status_t getSecureStop(Vector const &ssid, Vector &secureStop) = 0; virtual status_t releaseSecureStops(Vector const &ssRelease) = 0; virtual status_t releaseAllSecureStops() = 0; // Read a property value given the device property string. There are a few forms // of property access methods, depending on the data type returned. // Since DRM plugin properties may vary, additional field names may be defined // by each DRM vendor. Refer to your DRM provider documentation for definitions // of its additional field names. // // Standard values are: // "vendor" [string] identifies the maker of the plugin // "version" [string] identifies the version of the plugin // "description" [string] describes the plugin // 'deviceUniqueId' [byte array] The device unique identifier is established // during device provisioning and provides a means of uniquely identifying // each device. virtual status_t getPropertyString(String8 const &name, String8 &value ) const = 0; virtual status_t getPropertyByteArray(String8 const &name, Vector &value ) const = 0; // Write a property value given the device property string. There are a few forms // of property setting methods, depending on the data type. // Since DRM plugin properties may vary, additional field names may be defined // by each DRM vendor. Refer to your DRM provider documentation for definitions // of its field names. virtual status_t setPropertyString(String8 const &name, String8 const &value ) = 0; virtual status_t setPropertyByteArray(String8 const &name, Vector const &value ) = 0; // The following methods implement operations on a CryptoSession to support // encrypt, decrypt, sign verify operations on operator-provided // session keys. // // The algorithm string conforms to JCA Standard Names for Cipher // Transforms and is case insensitive. For example "AES/CBC/PKCS5Padding". // // Return OK if the algorithm is supported, otherwise return BAD_VALUE // virtual status_t setCipherAlgorithm(Vector const &sessionId, String8 const &algorithm) = 0; // // The algorithm string conforms to JCA Standard Names for Mac // Algorithms and is case insensitive. For example "HmacSHA256". // // Return OK if the algorithm is supported, otherwise return BAD_VALUE // virtual status_t setMacAlgorithm(Vector const &sessionId, String8 const &algorithm) = 0; // Encrypt the provided input buffer with the cipher algorithm // specified by setCipherAlgorithm and the key selected by keyId, // and return the encrypted data. virtual status_t encrypt(Vector const &sessionId, Vector const &keyId, Vector const &input, Vector const &iv, Vector &output) = 0; // Decrypt the provided input buffer with the cipher algorithm // specified by setCipherAlgorithm and the key selected by keyId, // and return the decrypted data. virtual status_t decrypt(Vector const &sessionId, Vector const &keyId, Vector const &input, Vector const &iv, Vector &output) = 0; // Compute a signature on the provided message using the mac algorithm // specified by setMacAlgorithm and the key selected by keyId, // and return the signature. virtual status_t sign(Vector const &sessionId, Vector const &keyId, Vector const &message, Vector &signature) = 0; // Compute a signature on the provided message using the mac algorithm // specified by setMacAlgorithm and the key selected by keyId, // and compare with the expected result. Set result to true or // false depending on the outcome. virtual status_t verify(Vector const &sessionId, Vector const &keyId, Vector const &message, Vector const &signature, bool &match) = 0; // Compute an RSA signature on the provided message using the algorithm // specified by algorithm. virtual status_t signRSA(Vector const &sessionId, String8 const &algorithm, Vector const &message, Vector const &wrapped_key, Vector &signature) = 0; status_t setListener(const sp& listener) { Mutex::Autolock lock(mEventLock); mListener = listener; return OK; } protected: // Plugins call these methods to deliver events to the java app void sendEvent(EventType eventType, int extra, Vector const *sessionId, Vector const *data); void sendExpirationUpdate(Vector const *sessionId, int64_t expiryTimeInMS); void sendKeysChange(Vector const *sessionId, Vector const *keyStatusList, bool hasNewUsableKey); private: Mutex mEventLock; sp mListener; DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin); }; class DrmPluginListener: virtual public RefBase { public: virtual void sendEvent(DrmPlugin::EventType eventType, int extra, Vector const *sessionId, Vector const *data) = 0; virtual void sendExpirationUpdate(Vector const *sessionId, int64_t expiryTimeInMS) = 0; virtual void sendKeysChange(Vector const *sessionId, Vector const *keyStatusList, bool hasNewUsableKey) = 0; }; inline void DrmPlugin::sendEvent(EventType eventType, int extra, Vector const *sessionId, Vector const *data) { mEventLock.lock(); sp listener = mListener; mEventLock.unlock(); if (listener != NULL) { listener->sendEvent(eventType, extra, sessionId, data); } } inline void DrmPlugin::sendExpirationUpdate(Vector const *sessionId, int64_t expiryTimeInMS) { mEventLock.lock(); sp listener = mListener; mEventLock.unlock(); if (listener != NULL) { listener->sendExpirationUpdate(sessionId, expiryTimeInMS); } } inline void DrmPlugin::sendKeysChange(Vector const *sessionId, Vector const *keyStatusList, bool hasNewUsableKey) { mEventLock.lock(); sp listener = mListener; mEventLock.unlock(); if (listener != NULL) { listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); } } } // namespace android #endif // DRM_API_H_ include/media/editor/0040755 0000000 0000000 00000000000 13077405420 013602 5ustar000000000 0000000 include/media/editor/II420ColorConverter.h0100644 0000000 0000000 00000012504 13077405420 017370 0ustar000000000 0000000 /* * 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 II420_COLOR_CONVERTER_H #define II420_COLOR_CONVERTER_H #include #include #ifdef __cplusplus extern "C" { #endif typedef struct II420ColorConverter { /* * getDecoderOutputFormat * Returns the color format (OMX_COLOR_FORMATTYPE) of the decoder output. * If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed, * and convertDecoderOutputToI420() can be a no-op. */ int (*getDecoderOutputFormat)(); /* * convertDecoderOutputToI420 * @Desc Converts from the decoder output format to I420 format. * @note Caller (e.g. VideoEditor) owns the buffers * @param decoderBits (IN) Pointer to the buffer contains decoder output * @param decoderWidth (IN) Buffer width, as reported by the decoder * metadata (kKeyWidth) * @param decoderHeight (IN) Buffer height, as reported by the decoder * metadata (kKeyHeight) * @param decoderRect (IN) The rectangle of the actual frame, as * reported by decoder metadata (kKeyCropRect) * @param dstBits (OUT) Pointer to the output I420 buffer * @return -1 Any error * @return 0 No Error */ int (*convertDecoderOutputToI420)( void* decoderBits, int decoderWidth, int decoderHeight, ARect decoderRect, void* dstBits); /* * getEncoderIntputFormat * Returns the color format (OMX_COLOR_FORMATTYPE) of the encoder input. * If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed, * and convertI420ToEncoderInput() and getEncoderInputBufferInfo() can * be no-ops. */ int (*getEncoderInputFormat)(); /* convertI420ToEncoderInput * @Desc This function converts from I420 to the encoder input format * @note Caller (e.g. VideoEditor) owns the buffers * @param srcBits (IN) Pointer to the input I420 buffer * @param srcWidth (IN) Width of the I420 frame * @param srcHeight (IN) Height of the I420 frame * @param encoderWidth (IN) Encoder buffer width, as calculated by * getEncoderBufferInfo() * @param encoderHeight (IN) Encoder buffer height, as calculated by * getEncoderBufferInfo() * @param encoderRect (IN) Rect coordinates of the actual frame inside * the encoder buffer, as calculated by * getEncoderBufferInfo(). * @param encoderBits (OUT) Pointer to the output buffer. The size of * this buffer is calculated by * getEncoderBufferInfo() * @return -1 Any error * @return 0 No Error */ int (*convertI420ToEncoderInput)( void* srcBits, int srcWidth, int srcHeight, int encoderWidth, int encoderHeight, ARect encoderRect, void* encoderBits); /* getEncoderInputBufferInfo * @Desc This function returns metadata for the encoder input buffer * based on the actual I420 frame width and height. * @note This API should be be used to obtain the necessary information * before calling convertI420ToEncoderInput(). * VideoEditor knows only the width and height of the I420 buffer, * but it also needs know the width, height, and size of the * encoder input buffer. The encoder input buffer width and height * are used to set the metadata for the encoder. * @param srcWidth (IN) Width of the I420 frame * @param srcHeight (IN) Height of the I420 frame * @param encoderWidth (OUT) Encoder buffer width needed * @param encoderHeight (OUT) Encoder buffer height needed * @param encoderRect (OUT) Rect coordinates of the actual frame inside * the encoder buffer * @param encoderBufferSize (OUT) The size of the buffer that need to be * allocated by the caller before invoking * convertI420ToEncoderInput(). * @return -1 Any error * @return 0 No Error */ int (*getEncoderInputBufferInfo)( int srcWidth, int srcHeight, int* encoderWidth, int* encoderHeight, ARect* encoderRect, int* encoderBufferSize); } II420ColorConverter; /* The only function that the shared library needs to expose: It fills the function pointers in II420ColorConverter */ void getI420ColorConverter(II420ColorConverter *converter); #if defined(__cplusplus) } #endif #endif // II420_COLOR_CONVERTER_H include/media/hardware/0040755 0000000 0000000 00000000000 13077405420 014111 5ustar000000000 0000000 include/media/hardware/CryptoAPI.h0100644 0000000 0000000 00000010141 13077405420 016066 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #ifndef CRYPTO_API_H_ #define CRYPTO_API_H_ namespace android { struct AString; struct CryptoPlugin; struct CryptoFactory { CryptoFactory() {} virtual ~CryptoFactory() {} virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0; virtual status_t createPlugin( const uint8_t uuid[16], const void *data, size_t size, CryptoPlugin **plugin) = 0; private: CryptoFactory(const CryptoFactory &); CryptoFactory &operator=(const CryptoFactory &); }; struct CryptoPlugin { enum Mode { kMode_Unencrypted = 0, kMode_AES_CTR = 1, kMode_AES_WV = 2, kMode_AES_CBC = 3, }; struct SubSample { uint32_t mNumBytesOfClearData; uint32_t mNumBytesOfEncryptedData; }; struct Pattern { // Number of blocks to be encrypted in the pattern. If zero, pattern // encryption is inoperative. uint32_t mEncryptBlocks; // Number of blocks to be skipped (left clear) in the pattern. If zero, // pattern encryption is inoperative. uint32_t mSkipBlocks; }; CryptoPlugin() {} virtual ~CryptoPlugin() {} // If this method returns false, a non-secure decoder will be used to // decode the data after decryption. The decrypt API below will have // to support insecure decryption of the data (secure = false) for // media data of the given mime type. virtual bool requiresSecureDecoderComponent(const char *mime) const = 0; // To implement resolution constraints, the crypto plugin needs to know // the resolution of the video being decrypted. The media player should // call this method when the resolution is determined and any time it // is subsequently changed. virtual void notifyResolution(uint32_t /* width */, uint32_t /* height */) {} // A MediaDrm session may be associated with a MediaCrypto session. The // associated MediaDrm session is used to load decryption keys // into the crypto/drm plugin. The keys are then referenced by key-id // in the 'key' parameter to the decrypt() method. // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if // the session is not opened and a code from MediaErrors.h otherwise. virtual status_t setMediaDrmSession(const Vector & /*sessionId */) { return ERROR_UNSUPPORTED; } // If the error returned falls into the range // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be // filled in with an appropriate string. // At the java level these special errors will then trigger a // MediaCodec.CryptoException that gives clients access to both // the error code and the errorDetailMsg. // Returns a non-negative result to indicate the number of bytes written // to the dstPtr, or a negative result to indicate an error. virtual ssize_t decrypt( bool secure, const uint8_t key[16], const uint8_t iv[16], Mode mode, const Pattern &pattern, const void *srcPtr, const SubSample *subSamples, size_t numSubSamples, void *dstPtr, AString *errorDetailMsg) = 0; private: CryptoPlugin(const CryptoPlugin &); CryptoPlugin &operator=(const CryptoPlugin &); }; } // namespace android extern "C" { extern android::CryptoFactory *createCryptoFactory(); } #endif // CRYPTO_API_H_ include/media/hardware/HDCPAPI.h0100644 0000000 0000000 00000015537 13077405420 015342 0ustar000000000 0000000 /* * Copyright (C) 2012 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 HDCP_API_H_ #define HDCP_API_H_ #include #include namespace android { // Two different kinds of modules are covered under the same HDCPModule // structure below, a module either implements decryption or encryption. struct HDCPModule { typedef void (*ObserverFunc)(void *cookie, int msg, int ext1, int ext2); // The msg argument in calls to the observer notification function. enum { // Sent in response to a call to "HDCPModule::initAsync" once // initialization has either been successfully completed, // i.e. the HDCP session is now fully setup (AKE, Locality Check, // SKE and any authentication with repeaters completed) or failed. // ext1 should be a suitable error code (status_t), ext2 is // unused for ENCRYPTION and in the case of HDCP_INITIALIZATION_COMPLETE // holds the local TCP port the module is listening on. HDCP_INITIALIZATION_COMPLETE, HDCP_INITIALIZATION_FAILED, // Sent upon completion of a call to "HDCPModule::shutdownAsync". // ext1 should be a suitable error code, ext2 is unused. HDCP_SHUTDOWN_COMPLETE, HDCP_SHUTDOWN_FAILED, HDCP_UNAUTHENTICATED_CONNECTION, HDCP_UNAUTHORIZED_CONNECTION, HDCP_REVOKED_CONNECTION, HDCP_TOPOLOGY_EXECEEDED, HDCP_UNKNOWN_ERROR, // DECRYPTION only: Indicates that a client has successfully connected, // a secure session established and the module is ready to accept // future calls to "decrypt". HDCP_SESSION_ESTABLISHED, }; // HDCPModule capability bit masks enum { // HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt // from an input byte-array buffer to an output byte-array buffer HDCP_CAPS_ENCRYPT = (1 << 0), // HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from // a native buffer to an output byte-array buffer. The format of the // input native buffer is specific to vendor's encoder implementation. // It is the same format as that used by the encoder when // "storeMetaDataInBuffers" extension is enabled on its output port. HDCP_CAPS_ENCRYPT_NATIVE = (1 << 1), }; // Module can call the notification function to signal completion/failure // of asynchronous operations (such as initialization) or out of band // events. HDCPModule(void *cookie, ObserverFunc observerNotify) {}; virtual ~HDCPModule() {}; // ENCRYPTION: Request to setup an HDCP session with the host specified // by addr and listening on the specified port. // DECRYPTION: Request to setup an HDCP session, addr is the interface // address the module should bind its socket to. port will be 0. // The module will pick the port to listen on itself and report its choice // in the "ext2" argument of the HDCP_INITIALIZATION_COMPLETE callback. virtual status_t initAsync(const char *addr, unsigned port) = 0; // Request to shutdown the active HDCP session. virtual status_t shutdownAsync() = 0; // Returns the capability bitmask of this HDCP session. virtual uint32_t getCaps() { return HDCP_CAPS_ENCRYPT; } // ENCRYPTION only: // Encrypt data according to the HDCP spec. "size" bytes of data are // available at "inData" (virtual address), "size" may not be a multiple // of 128 bits (16 bytes). An equal number of encrypted bytes should be // written to the buffer at "outData" (virtual address). // This operation is to be synchronous, i.e. this call does not return // until outData contains size bytes of encrypted data. // streamCTR will be assigned by the caller (to 0 for the first PES stream, // 1 for the second and so on) // inputCTR _will_be_maintained_by_the_callee_ for each PES stream. virtual status_t encrypt( const void *inData, size_t size, uint32_t streamCTR, uint64_t *outInputCTR, void *outData) { return INVALID_OPERATION; } // Encrypt data according to the HDCP spec. "size" bytes of data starting // at location "offset" are available in "buffer" (buffer handle). "size" // may not be a multiple of 128 bits (16 bytes). An equal number of // encrypted bytes should be written to the buffer at "outData" (virtual // address). This operation is to be synchronous, i.e. this call does not // return until outData contains size bytes of encrypted data. // streamCTR will be assigned by the caller (to 0 for the first PES stream, // 1 for the second and so on) // inputCTR _will_be_maintained_by_the_callee_ for each PES stream. virtual status_t encryptNative( buffer_handle_t buffer, size_t offset, size_t size, uint32_t streamCTR, uint64_t *outInputCTR, void *outData) { return INVALID_OPERATION; } // DECRYPTION only: // Decrypt data according to the HDCP spec. // "size" bytes of encrypted data are available at "inData" // (virtual address), "size" may not be a multiple of 128 bits (16 bytes). // An equal number of decrypted bytes should be written to the buffer // at "outData" (virtual address). // This operation is to be synchronous, i.e. this call does not return // until outData contains size bytes of decrypted data. // Both streamCTR and inputCTR will be provided by the caller. virtual status_t decrypt( const void *inData, size_t size, uint32_t streamCTR, uint64_t inputCTR, void *outData) { return INVALID_OPERATION; } private: HDCPModule(const HDCPModule &); HDCPModule &operator=(const HDCPModule &); }; } // namespace android // A shared library exporting the following methods should be included to // support HDCP functionality. The shared library must be called // "libstagefright_hdcp.so", it will be dynamically loaded into the // mediaserver process. extern "C" { // Create a module for ENCRYPTION. extern android::HDCPModule *createHDCPModule( void *cookie, android::HDCPModule::ObserverFunc); // Create a module for DECRYPTION. extern android::HDCPModule *createHDCPModuleForDecryption( void *cookie, android::HDCPModule::ObserverFunc); } #endif // HDCP_API_H_ include/media/hardware/HardwareAPI.h0100644 0000000 0000000 00000063056 13077405420 016360 0ustar000000000 0000000 /* * Copyright (C) 2009 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 HARDWARE_API_H_ #define HARDWARE_API_H_ #include #include #include #include #include "VideoAPI.h" #include namespace android { // This structure is used to enable Android native buffer use for either // graphic buffers or secure buffers. // // TO CONTROL ANDROID GRAPHIC BUFFER USAGE: // // A pointer to this struct is passed to the OMX_SetParameter when the extension // index for the 'OMX.google.android.index.enableAndroidNativeBuffers' extension // is given. // // When Android native buffer use is disabled for a port (the default state), // the OMX node should operate as normal, and expect UseBuffer calls to set its // buffers. This is the mode that will be used when CPU access to the buffer is // required. // // When Android native buffer use has been enabled for a given port, the video // color format for the port is to be interpreted as an Android pixel format // rather than an OMX color format. Enabling Android native buffers may also // change how the component receives the native buffers. If store-metadata-mode // is enabled on the port, the component will receive the buffers as specified // in the section below. Otherwise, unless the node supports the // 'OMX.google.android.index.useAndroidNativeBuffer2' extension, it should // expect to receive UseAndroidNativeBuffer calls (via OMX_SetParameter) rather // than UseBuffer calls for that port. // // TO CONTROL ANDROID SECURE BUFFER USAGE: // // A pointer to this struct is passed to the OMX_SetParameter when the extension // index for the 'OMX.google.android.index.allocateNativeHandle' extension // is given. // // When native handle use is disabled for a port (the default state), // the OMX node should operate as normal, and expect AllocateBuffer calls to // return buffer pointers. This is the mode that will be used for non-secure // buffers if component requires allocate buffers instead of use buffers. // // When native handle use has been enabled for a given port, the component // shall allocate native_buffer_t objects containing that can be passed between // processes using binder. This is the mode that will be used for secure buffers. // When an OMX component allocates native handle for buffers, it must close and // delete that handle when it frees those buffers. Even though pBuffer will point // to a native handle, nFilledLength, nAllocLength and nOffset will correspond // to the data inside the opaque buffer. struct EnableAndroidNativeBuffersParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL enable; }; typedef struct EnableAndroidNativeBuffersParams AllocateNativeHandleParams; // A pointer to this struct is passed to OMX_SetParameter() when the extension index // "OMX.google.android.index.storeMetaDataInBuffers" or // "OMX.google.android.index.storeANWBufferInMetadata" is given. // // When meta data is stored in the video buffers passed between OMX clients // and OMX components, interpretation of the buffer data is up to the // buffer receiver, and the data may or may not be the actual video data, but // some information helpful for the receiver to locate the actual data. // The buffer receiver thus needs to know how to interpret what is stored // in these buffers, with mechanisms pre-determined externally. How to // interpret the meta data is outside of the scope of this parameter. // // Currently, this is used to pass meta data from video source (camera component, for instance) to // video encoder to avoid memcpying of input video frame data, as well as to pass dynamic output // buffer to video decoder. To do this, bStoreMetaData is set to OMX_TRUE. // // If bStoreMetaData is set to false, real YUV frame data will be stored in input buffers, and // the output buffers contain either real YUV frame data, or are themselves native handles as // directed by enable/use-android-native-buffer parameter settings. // In addition, if no OMX_SetParameter() call is made on a port with the corresponding extension // index, the component should not assume that the client is not using metadata mode for the port. // // If the component supports this using the "OMX.google.android.index.storeANWBufferInMetadata" // extension and bStoreMetaData is set to OMX_TRUE, data is passed using the VideoNativeMetadata // layout as defined below. Each buffer will be accompanied by a fence. The fence must signal // before the buffer can be used (e.g. read from or written into). When returning such buffer to // the client, component must provide a new fence that must signal before the returned buffer can // be used (e.g. read from or written into). The component owns the incoming fenceFd, and must close // it when fence has signaled. The client will own and close the returned fence file descriptor. // // If the component supports this using the "OMX.google.android.index.storeMetaDataInBuffers" // extension and bStoreMetaData is set to OMX_TRUE, data is passed using VideoGrallocMetadata // (the layout of which is the VideoGrallocMetadata defined below). Camera input can be also passed // as "CameraSource", the layout of which is vendor dependent. // // Metadata buffers are registered with the component using UseBuffer calls, or can be allocated // by the component for encoder-metadata-output buffers. struct StoreMetaDataInBuffersParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bStoreMetaData; }; // Meta data buffer layout used to transport output frames to the decoder for // dynamic buffer handling. struct VideoGrallocMetadata { MetadataBufferType eType; // must be kMetadataBufferTypeGrallocSource #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS OMX_PTR pHandle; #else buffer_handle_t pHandle; #endif }; // Legacy name for VideoGrallocMetadata struct. struct VideoDecoderOutputMetaData : public VideoGrallocMetadata {}; struct VideoNativeMetadata { MetadataBufferType eType; // must be kMetadataBufferTypeANWBuffer #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS OMX_PTR pBuffer; #else struct ANativeWindowBuffer* pBuffer; #endif int nFenceFd; // -1 if unused }; // Meta data buffer layout for passing a native_handle to codec struct VideoNativeHandleMetadata { MetadataBufferType eType; // must be kMetadataBufferTypeNativeHandleSource #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS OMX_PTR pHandle; #else native_handle_t *pHandle; #endif }; // A pointer to this struct is passed to OMX_SetParameter() when the extension // index "OMX.google.android.index.prepareForAdaptivePlayback" is given. // // This method is used to signal a video decoder, that the user has requested // seamless resolution change support (if bEnable is set to OMX_TRUE). // nMaxFrameWidth and nMaxFrameHeight are the dimensions of the largest // anticipated frames in the video. If bEnable is OMX_FALSE, no resolution // change is expected, and the nMaxFrameWidth/Height fields are unused. // // If the decoder supports dynamic output buffers, it may ignore this // request. Otherwise, it shall request resources in such a way so that it // avoids full port-reconfiguration (due to output port-definition change) // during resolution changes. // // DO NOT USE THIS STRUCTURE AS IT WILL BE REMOVED. INSTEAD, IMPLEMENT // METADATA SUPPORT FOR VIDEO DECODERS. struct PrepareForAdaptivePlaybackParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bEnable; OMX_U32 nMaxFrameWidth; OMX_U32 nMaxFrameHeight; }; // A pointer to this struct is passed to OMX_SetParameter when the extension // index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is // given. This call will only be performed if a prior call was made with the // 'OMX.google.android.index.enableAndroidNativeBuffers' extension index, // enabling use of Android native buffers. struct UseAndroidNativeBufferParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_PTR pAppPrivate; OMX_BUFFERHEADERTYPE **bufferHeader; const sp& nativeBuffer; }; // A pointer to this struct is passed to OMX_GetParameter when the extension // index for the 'OMX.google.android.index.getAndroidNativeBufferUsage' // extension is given. The usage bits returned from this query will be used to // allocate the Gralloc buffers that get passed to the useAndroidNativeBuffer // command. struct GetAndroidNativeBufferUsageParams { OMX_U32 nSize; // IN OMX_VERSIONTYPE nVersion; // IN OMX_U32 nPortIndex; // IN OMX_U32 nUsage; // OUT }; // An enum OMX_COLOR_FormatAndroidOpaque to indicate an opaque colorformat // is declared in media/stagefright/openmax/OMX_IVCommon.h // This will inform the encoder that the actual // colorformat will be relayed by the GRalloc Buffers. // OMX_COLOR_FormatAndroidOpaque = 0x7F000001, // A pointer to this struct is passed to OMX_SetParameter when the extension // index for the 'OMX.google.android.index.prependSPSPPSToIDRFrames' extension // is given. // A successful result indicates that future IDR frames will be prefixed by // SPS/PPS. struct PrependSPSPPSToIDRFramesParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_BOOL bEnable; }; // A pointer to this struct is passed to OMX_GetParameter when the extension // index for the 'OMX.google.android.index.describeColorFormat' // extension is given. This method can be called from any component state // other than invalid. The color-format, frame width/height, and stride/ // slice-height parameters are ones that are associated with a raw video // port (input or output), but the stride/slice height parameters may be // incorrect. bUsingNativeBuffers is OMX_TRUE if native android buffers will // be used (while specifying this color format). // // The component shall fill out the MediaImage structure that // corresponds to the described raw video format, and the potentially corrected // stride and slice-height info. // // The behavior is slightly different if bUsingNativeBuffers is OMX_TRUE, // though most implementations can ignore this difference. When using native buffers, // the component may change the configured color format to an optimized format. // Additionally, when allocating these buffers for flexible usecase, the framework // will set the SW_READ/WRITE_OFTEN usage flags. In this case (if bUsingNativeBuffers // is OMX_TRUE), the component shall fill out the MediaImage information for the // scenario when these SW-readable/writable buffers are locked using gralloc_lock. // Note, that these buffers may also be locked using gralloc_lock_ycbcr, which must // be supported for vendor-specific formats. // // For non-YUV packed planar/semiplanar image formats, or if bUsingNativeBuffers // is OMX_TRUE and the component does not support this color format with native // buffers, the component shall set mNumPlanes to 0, and mType to MEDIA_IMAGE_TYPE_UNKNOWN. // @deprecated: use DescribeColorFormat2Params struct DescribeColorFormat2Params; struct DescribeColorFormatParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; // input: parameters from OMX_VIDEO_PORTDEFINITIONTYPE OMX_COLOR_FORMATTYPE eColorFormat; OMX_U32 nFrameWidth; OMX_U32 nFrameHeight; OMX_U32 nStride; OMX_U32 nSliceHeight; OMX_BOOL bUsingNativeBuffers; // output: fill out the MediaImage fields MediaImage sMediaImage; DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only }; // A pointer to this struct is passed to OMX_GetParameter when the extension // index for the 'OMX.google.android.index.describeColorFormat2' // extension is given. This is operationally the same as DescribeColorFormatParams // but can be used for HDR and RGBA/YUVA formats. struct DescribeColorFormat2Params { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; // input: parameters from OMX_VIDEO_PORTDEFINITIONTYPE OMX_COLOR_FORMATTYPE eColorFormat; OMX_U32 nFrameWidth; OMX_U32 nFrameHeight; OMX_U32 nStride; OMX_U32 nSliceHeight; OMX_BOOL bUsingNativeBuffers; // output: fill out the MediaImage2 fields MediaImage2 sMediaImage; void initFromV1(const DescribeColorFormatParams&); // for internal use only }; // A pointer to this struct is passed to OMX_SetParameter or OMX_GetParameter // when the extension index for the // 'OMX.google.android.index.configureVideoTunnelMode' extension is given. // If the extension is supported then tunneled playback mode should be supported // by the codec. If bTunneled is set to OMX_TRUE then the video decoder should // operate in "tunneled" mode and output its decoded frames directly to the // sink. In this case nAudioHwSync is the HW SYNC ID of the audio HAL Output // stream to sync the video with. If bTunneled is set to OMX_FALSE, "tunneled" // mode should be disabled and nAudioHwSync should be ignored. // OMX_GetParameter is used to query tunneling configuration. bTunneled should // return whether decoder is operating in tunneled mode, and if it is, // pSidebandWindow should contain the codec allocated sideband window handle. struct ConfigureVideoTunnelModeParams { OMX_U32 nSize; // IN OMX_VERSIONTYPE nVersion; // IN OMX_U32 nPortIndex; // IN OMX_BOOL bTunneled; // IN/OUT OMX_U32 nAudioHwSync; // IN OMX_PTR pSidebandWindow; // OUT }; // Color space description (aspects) parameters. // This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the // 'OMX.google.android.index.describeColorAspects' extension is given. Component SHALL behave // as described below if it supports this extension. // // bDataSpaceChanged and bRequestingDataSpace is assumed to be OMX_FALSE unless noted otherwise. // // VIDEO ENCODERS: the framework uses OMX_SetConfig to specify color aspects of the coded video. // This may happen: // a) before the component transitions to idle state // b) before the input frame is sent via OMX_EmptyThisBuffer in executing state // c) during execution, just before an input frame with a different color aspect information // is sent. // // The framework also uses OMX_GetConfig to // d) verify the color aspects that will be written to the stream // e) (optional) verify the color aspects that should be reported to the container for a // given dataspace/pixelformat received // // 1. Encoders SHOULD maintain an internal color aspect state, initialized to Unspecified values. // This represents the values that will be written into the bitstream. // 2. Upon OMX_SetConfig, they SHOULD update their internal state to the aspects received // (including Unspecified values). For specific aspect values that are not supported by the // codec standard, encoders SHOULD substitute Unspecified values; or they MAY use a suitable // alternative (e.g. to suggest the use of BT.709 EOTF instead of SMPTE 240M.) // 3. OMX_GetConfig SHALL return the internal state (values that will be written). // 4. OMX_SetConfig SHALL always succeed before receiving the first frame. It MAY fail afterwards, // but only if the configured values would change AND the component does not support updating the // color information to those values mid-stream. If component supports updating a portion of // the color information, those values should be updated in the internal state, and OMX_SetConfig // SHALL succeed. Otherwise, the internal state SHALL remain intact and OMX_SetConfig SHALL fail // with OMX_ErrorUnsupportedSettings. // 5. When the framework receives an input frame with an unexpected dataspace, it will query // encoders for the color aspects that should be reported to the container using OMX_GetConfig // with bDataSpaceChanged set to OMX_TRUE, and nPixelFormat/nDataSpace containing the new // format/dataspace values. This allows vendors to use extended dataspace during capture and // composition (e.g. screenrecord) - while performing color-space conversion inside the encoder - // and encode and report a different color-space information in the bitstream/container. // sColorAspects contains the requested color aspects by the client for reference, which may // include aspects not supported by the encoding. This is used together with guidance for // dataspace selection; see 6. below. // // VIDEO DECODERS: the framework uses OMX_SetConfig to specify the default color aspects to use // for the video. // This may happen: // a) before the component transitions to idle state // b) during execution, when the resolution or the default color aspects change. // // The framework also uses OMX_GetConfig to // c) get the final color aspects reported by the coded bitstream after taking the default values // into account. // // 1. Decoders should maintain two color aspect states - the default state as reported by the // framework, and the coded state as reported by the bitstream - as each state can change // independently from the other. // 2. Upon OMX_SetConfig, it SHALL update its default state regardless of whether such aspects // could be supplied by the component bitstream. (E.g. it should blindly support all enumeration // values, even unknown ones, and the Other value). This SHALL always succeed. // 3. Upon OMX_GetConfig, the component SHALL return the final color aspects by replacing // Unspecified coded values with the default values. This SHALL always succeed. // 4. Whenever the component processes color aspect information in the bitstream even with an // Unspecified value, it SHOULD update its internal coded state with that information just before // the frame with the new information would be outputted, and the component SHALL signal an // OMX_EventPortSettingsChanged event with data2 set to the extension index. // NOTE: Component SHOULD NOT signal a separate event purely for color aspect change, if it occurs // together with a port definition (e.g. size) or crop change. // 5. If the aspects a component encounters in the bitstream cannot be represented with enumeration // values as defined below, the component SHALL set those aspects to Other. Restricted values in // the bitstream SHALL be treated as defined by the relevant bitstream specifications/standards, // or as Unspecified, if not defined. // // BOTH DECODERS AND ENCODERS: the framework uses OMX_GetConfig during idle and executing state to // f) (optional) get guidance for the dataspace to set for given color aspects, by setting // bRequestingDataSpace to OMX_TRUE. The component SHALL return OMX_ErrorUnsupportedSettings // IF it does not support this request. // // 6. This is an information request that can happen at any time, independent of the normal // configuration process. This allows vendors to use extended dataspace during capture, playback // and composition - while performing color-space conversion inside the component. Component // SHALL set the desired dataspace into nDataSpace. Otherwise, it SHALL return // OMX_ErrorUnsupportedSettings to let the framework choose a nearby standard dataspace. // // 6.a. For encoders, this query happens before the first frame is received using surface encoding. // This allows the encoder to use a specific dataspace for the color aspects (e.g. because the // device supports additional dataspaces, or because it wants to perform color-space extension // to facilitate a more optimal rendering/capture pipeline.). // // 6.b. For decoders, this query happens before the first frame, and every time the color aspects // change, while using surface buffers. This allows the decoder to use a specific dataspace for // the color aspects (e.g. because the device supports additional dataspaces, or because it wants // to perform color-space extension by inline color-space conversion to facilitate a more optimal // rendering pipeline.). // // Note: the size of sAspects may increase in the future by additional fields. // Implementations SHOULD NOT require a certain size. struct DescribeColorAspectsParams { OMX_U32 nSize; // IN OMX_VERSIONTYPE nVersion; // IN OMX_U32 nPortIndex; // IN OMX_BOOL bRequestingDataSpace; // IN OMX_BOOL bDataSpaceChanged; // IN OMX_U32 nPixelFormat; // IN OMX_U32 nDataSpace; // OUT ColorAspects sAspects; // IN/OUT }; // HDR color description parameters. // This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the // 'OMX.google.android.index.describeHDRColorInfo' extension is given and an HDR stream // is detected. Component SHALL behave as described below if it supports this extension. // // Currently, only Static Metadata Descriptor Type 1 support is required. // // VIDEO ENCODERS: the framework uses OMX_SetConfig to specify the HDR static information of the // coded video. // This may happen: // a) before the component transitions to idle state // b) before the input frame is sent via OMX_EmptyThisBuffer in executing state // c) during execution, just before an input frame with a different HDR static // information is sent. // // The framework also uses OMX_GetConfig to // d) verify the HDR static information that will be written to the stream. // // 1. Encoders SHOULD maintain an internal HDR static info data, initialized to Unspecified values. // This represents the values that will be written into the bitstream. // 2. Upon OMX_SetConfig, they SHOULD update their internal state to the info received // (including Unspecified values). For specific parameters that are not supported by the // codec standard, encoders SHOULD substitute Unspecified values. NOTE: no other substitution // is allowed. // 3. OMX_GetConfig SHALL return the internal state (values that will be written). // 4. OMX_SetConfig SHALL always succeed before receiving the first frame if the encoder is // configured into an HDR compatible profile. It MAY fail with OMX_ErrorUnsupportedSettings error // code if it is not configured into such a profile, OR if the configured values would change // AND the component does not support updating the HDR static information mid-stream. If the // component supports updating a portion of the information, those values should be updated in // the internal state, and OMX_SetConfig SHALL succeed. Otherwise, the internal state SHALL // remain intact. // // VIDEO DECODERS: the framework uses OMX_SetConfig to specify the default HDR static information // to use for the video. // a) This only happens if the client supplies this information, in which case it occurs before // the component transitions to idle state. // b) This may also happen subsequently if the default HDR static information changes. // // The framework also uses OMX_GetConfig to // c) get the final HDR static information reported by the coded bitstream after taking the // default values into account. // // 1. Decoders should maintain two HDR static information structures - the default values as // reported by the framework, and the coded values as reported by the bitstream - as each // structure can change independently from the other. // 2. Upon OMX_SetConfig, it SHALL update its default structure regardless of whether such static // parameters could be supplied by the component bitstream. (E.g. it should blindly support all // parameter values, even seemingly illegal ones). This SHALL always succeed. // Note: The descriptor ID used in sInfo may change in subsequent calls. (although for now only // Type 1 support is required.) // 3. Upon OMX_GetConfig, the component SHALL return the final HDR static information by replacing // Unspecified coded values with the default values. This SHALL always succeed. This may be // provided using any supported descriptor ID (currently only Type 1) with the goal of expressing // the most of the available static information. // 4. Whenever the component processes HDR static information in the bitstream even ones with // Unspecified parameters, it SHOULD update its internal coded structure with that information // just before the frame with the new information would be outputted, and the component SHALL // signal an OMX_EventPortSettingsChanged event with data2 set to the extension index. // NOTE: Component SHOULD NOT signal a separate event purely for HDR static info change, if it // occurs together with a port definition (e.g. size), color aspect or crop change. // 5. If certain parameters of the HDR static information encountered in the bitstream cannot be // represented using sInfo, the component SHALL use the closest representation. // // Note: the size of sInfo may increase in the future by supporting additional descriptor types. // Implementations SHOULD NOT require a certain size. struct DescribeHDRStaticInfoParams { OMX_U32 nSize; // IN OMX_VERSIONTYPE nVersion; // IN OMX_U32 nPortIndex; // IN HDRStaticInfo sInfo; // IN/OUT }; } // namespace android extern android::OMXPluginBase *createOMXPlugin(); #endif // HARDWARE_API_H_ include/media/hardware/MetadataBufferType.h0100644 0000000 0000000 00000014347 13077405420 020004 0ustar000000000 0000000 /* * 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 METADATA_BUFFER_TYPE_H #define METADATA_BUFFER_TYPE_H #ifdef __cplusplus extern "C" { namespace android { #endif /* * MetadataBufferType defines the type of the metadata buffers that * can be passed to video encoder component for encoding, via Stagefright * media recording framework. To see how to work with the metadata buffers * in media recording framework, please consult HardwareAPI.h * * The creator of metadata buffers and video encoder share common knowledge * on what is actually being stored in these metadata buffers, and * how the information can be used by the video encoder component * to locate the actual pixel data as the source input for video * encoder, plus whatever other information that is necessary. Stagefright * media recording framework does not need to know anything specific about the * metadata buffers, except for receving each individual metadata buffer * as the source input, making a copy of the metadata buffer, and passing the * copy via OpenMAX API to the video encoder component. * * The creator of the metadata buffers must ensure that the first * 4 bytes in every metadata buffer indicates its buffer type, * and the rest of the metadata buffer contains the * actual metadata information. When a video encoder component receives * a metadata buffer, it uses the first 4 bytes in that buffer to find * out the type of the metadata buffer, and takes action appropriate * to that type of metadata buffers (for instance, locate the actual * pixel data input and then encoding the input data to produce a * compressed output buffer). * * The following shows the layout of a metadata buffer, * where buffer type is a 4-byte field of MetadataBufferType, * and the payload is the metadata information. * * -------------------------------------------------------------- * | buffer type | payload | * -------------------------------------------------------------- * */ typedef enum { /* * kMetadataBufferTypeCameraSource is used to indicate that * the source of the metadata buffer is the camera component. */ kMetadataBufferTypeCameraSource = 0, /* * kMetadataBufferTypeGrallocSource is used to indicate that * the payload of the metadata buffers can be interpreted as * a buffer_handle_t. * So in this case,the metadata that the encoder receives * will have a byte stream that consists of two parts: * 1. First, there is an integer indicating that it is a GRAlloc * source (kMetadataBufferTypeGrallocSource) * 2. This is followed by the buffer_handle_t that is a handle to the * GRalloc buffer. The encoder needs to interpret this GRalloc handle * and encode the frames. * -------------------------------------------------------------- * | kMetadataBufferTypeGrallocSource | buffer_handle_t buffer | * -------------------------------------------------------------- * * See the VideoGrallocMetadata structure. */ kMetadataBufferTypeGrallocSource = 1, /* * kMetadataBufferTypeGraphicBuffer is used to indicate that * the payload of the metadata buffers can be interpreted as * an ANativeWindowBuffer, and that a fence is provided. * * In this case, the metadata will have a byte stream that consists of three parts: * 1. First, there is an integer indicating that the metadata * contains an ANativeWindowBuffer (kMetadataBufferTypeANWBuffer) * 2. This is followed by the pointer to the ANativeWindowBuffer. * Codec must not free this buffer as it does not actually own this buffer. * 3. Finally, there is an integer containing a fence file descriptor. * The codec must wait on the fence before encoding or decoding into this * buffer. When the buffer is returned, codec must replace this file descriptor * with a new fence, that will be waited on before the buffer is replaced * (encoder) or read (decoder). * --------------------------------- * | kMetadataBufferTypeANWBuffer | * --------------------------------- * | ANativeWindowBuffer *buffer | * --------------------------------- * | int fenceFd | * --------------------------------- * * See the VideoNativeMetadata structure. */ kMetadataBufferTypeANWBuffer = 2, /* * kMetadataBufferTypeNativeHandleSource is used to indicate that * the payload of the metadata buffers can be interpreted as * a native_handle_t. * * In this case, the metadata that the encoder receives * will have a byte stream that consists of two parts: * 1. First, there is an integer indicating that the metadata contains a * native handle (kMetadataBufferTypeNativeHandleSource). * 2. This is followed by a pointer to native_handle_t. The encoder needs * to interpret this native handle and encode the frame. The encoder must * not free this native handle as it does not actually own this native * handle. The handle will be freed after the encoder releases the buffer * back to camera. * ---------------------------------------------------------------- * | kMetadataBufferTypeNativeHandleSource | native_handle_t* nh | * ---------------------------------------------------------------- * * See the VideoNativeHandleMetadata structure. */ kMetadataBufferTypeNativeHandleSource = 3, /* This value is used by framework, but is never used inside a metadata buffer */ kMetadataBufferTypeInvalid = -1, // Add more here... } MetadataBufferType; #ifdef __cplusplus } // namespace android } #endif #endif // METADATA_BUFFER_TYPE_H include/media/hardware/OMXPluginBase.h0100644 0000000 0000000 00000003103 13077405420 016671 0ustar000000000 0000000 /* * Copyright (C) 2009 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 OMX_PLUGIN_BASE_H_ #define OMX_PLUGIN_BASE_H_ #include #include #include #include namespace android { struct OMXPluginBase { OMXPluginBase() {} virtual ~OMXPluginBase() {} virtual OMX_ERRORTYPE makeComponentInstance( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) = 0; virtual OMX_ERRORTYPE destroyComponentInstance( OMX_COMPONENTTYPE *component) = 0; virtual OMX_ERRORTYPE enumerateComponents( OMX_STRING name, size_t size, OMX_U32 index) = 0; virtual OMX_ERRORTYPE getRolesOfComponent( const char *name, Vector *roles) = 0; private: OMXPluginBase(const OMXPluginBase &); OMXPluginBase &operator=(const OMXPluginBase &); }; } // namespace android #endif // OMX_PLUGIN_BASE_H_ include/media/hardware/VideoAPI.h0100644 0000000 0000000 00000033133 13077405420 015662 0ustar000000000 0000000 /* * Copyright (C) 2016 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 VIDEO_API_H_ #define VIDEO_API_H_ namespace android { /** * Structure describing a media image (frame) * Currently only supporting YUV * @deprecated. Use MediaImage2 instead */ struct MediaImage { enum Type { MEDIA_IMAGE_TYPE_UNKNOWN = 0, MEDIA_IMAGE_TYPE_YUV, }; enum PlaneIndex { Y = 0, U, V, MAX_NUM_PLANES }; Type mType; uint32_t mNumPlanes; // number of planes uint32_t mWidth; // width of largest plane (unpadded, as in nFrameWidth) uint32_t mHeight; // height of largest plane (unpadded, as in nFrameHeight) uint32_t mBitDepth; // useable bit depth struct PlaneInfo { uint32_t mOffset; // offset of first pixel of the plane in bytes // from buffer offset uint32_t mColInc; // column increment in bytes uint32_t mRowInc; // row increment in bytes uint32_t mHorizSubsampling; // subsampling compared to the largest plane uint32_t mVertSubsampling; // subsampling compared to the largest plane }; PlaneInfo mPlane[MAX_NUM_PLANES]; }; /** * Structure describing a media image (frame) */ struct __attribute__ ((__packed__)) MediaImage2 { enum Type : uint32_t { MEDIA_IMAGE_TYPE_UNKNOWN = 0, MEDIA_IMAGE_TYPE_YUV, MEDIA_IMAGE_TYPE_YUVA, MEDIA_IMAGE_TYPE_RGB, MEDIA_IMAGE_TYPE_RGBA, MEDIA_IMAGE_TYPE_Y, }; enum PlaneIndex : uint32_t { Y = 0, U = 1, V = 2, R = 0, G = 1, B = 2, A = 3, MAX_NUM_PLANES = 4, }; Type mType; uint32_t mNumPlanes; // number of planes uint32_t mWidth; // width of largest plane (unpadded, as in nFrameWidth) uint32_t mHeight; // height of largest plane (unpadded, as in nFrameHeight) uint32_t mBitDepth; // useable bit depth (always MSB) uint32_t mBitDepthAllocated; // bits per component (must be 8 or 16) struct __attribute__ ((__packed__)) PlaneInfo { uint32_t mOffset; // offset of first pixel of the plane in bytes // from buffer offset int32_t mColInc; // column increment in bytes int32_t mRowInc; // row increment in bytes uint32_t mHorizSubsampling; // subsampling compared to the largest plane uint32_t mVertSubsampling; // subsampling compared to the largest plane }; PlaneInfo mPlane[MAX_NUM_PLANES]; void initFromV1(const MediaImage&); // for internal use only }; static_assert(sizeof(MediaImage2::PlaneInfo) == 20, "wrong struct size"); static_assert(sizeof(MediaImage2) == 104, "wrong struct size"); /** * Aspects of color. */ // NOTE: this structure is expected to grow in the future if new color aspects are // added to codec bitstreams. OMX component should not require a specific nSize // though could verify that nSize is at least the size of the structure at the // time of implementation. All new fields will be added at the end of the structure // ensuring backward compatibility. struct __attribute__ ((__packed__)) ColorAspects { // this is in sync with the range values in graphics.h enum Range : uint32_t { RangeUnspecified, RangeFull, RangeLimited, RangeOther = 0xff, }; enum Primaries : uint32_t { PrimariesUnspecified, PrimariesBT709_5, // Rec.ITU-R BT.709-5 or equivalent PrimariesBT470_6M, // Rec.ITU-R BT.470-6 System M or equivalent PrimariesBT601_6_625, // Rec.ITU-R BT.601-6 625 or equivalent PrimariesBT601_6_525, // Rec.ITU-R BT.601-6 525 or equivalent PrimariesGenericFilm, // Generic Film PrimariesBT2020, // Rec.ITU-R BT.2020 or equivalent PrimariesOther = 0xff, }; // this partially in sync with the transfer values in graphics.h prior to the transfers // unlikely to be required by Android section enum Transfer : uint32_t { TransferUnspecified, TransferLinear, // Linear transfer characteristics TransferSRGB, // sRGB or equivalent TransferSMPTE170M, // SMPTE 170M or equivalent (e.g. BT.601/709/2020) TransferGamma22, // Assumed display gamma 2.2 TransferGamma28, // Assumed display gamma 2.8 TransferST2084, // SMPTE ST 2084 for 10/12/14/16 bit systems TransferHLG, // ARIB STD-B67 hybrid-log-gamma // transfers unlikely to be required by Android TransferSMPTE240M = 0x40, // SMPTE 240M TransferXvYCC, // IEC 61966-2-4 TransferBT1361, // Rec.ITU-R BT.1361 extended gamut TransferST428, // SMPTE ST 428-1 TransferOther = 0xff, }; enum MatrixCoeffs : uint32_t { MatrixUnspecified, MatrixBT709_5, // Rec.ITU-R BT.709-5 or equivalent MatrixBT470_6M, // KR=0.30, KB=0.11 or equivalent MatrixBT601_6, // Rec.ITU-R BT.601-6 625 or equivalent MatrixSMPTE240M, // SMPTE 240M or equivalent MatrixBT2020, // Rec.ITU-R BT.2020 non-constant luminance MatrixBT2020Constant, // Rec.ITU-R BT.2020 constant luminance MatrixOther = 0xff, }; // this is in sync with the standard values in graphics.h enum Standard : uint32_t { StandardUnspecified, StandardBT709, // PrimariesBT709_5 and MatrixBT709_5 StandardBT601_625, // PrimariesBT601_6_625 and MatrixBT601_6 StandardBT601_625_Unadjusted, // PrimariesBT601_6_625 and KR=0.222, KB=0.071 StandardBT601_525, // PrimariesBT601_6_525 and MatrixBT601_6 StandardBT601_525_Unadjusted, // PrimariesBT601_6_525 and MatrixSMPTE240M StandardBT2020, // PrimariesBT2020 and MatrixBT2020 StandardBT2020Constant, // PrimariesBT2020 and MatrixBT2020Constant StandardBT470M, // PrimariesBT470_6M and MatrixBT470_6M StandardFilm, // PrimariesGenericFilm and KR=0.253, KB=0.068 StandardOther = 0xff, }; Range mRange; // IN/OUT Primaries mPrimaries; // IN/OUT Transfer mTransfer; // IN/OUT MatrixCoeffs mMatrixCoeffs; // IN/OUT }; static_assert(sizeof(ColorAspects) == 16, "wrong struct size"); /** * HDR Metadata. */ // HDR Static Metadata Descriptor as defined by CTA-861-3. struct __attribute__ ((__packed__)) HDRStaticInfo { // Static_Metadata_Descriptor_ID enum ID : uint8_t { kType1 = 0, // Static Metadata Type 1 } mID; struct __attribute__ ((__packed__)) Primaries1 { // values are in units of 0.00002 uint16_t x; uint16_t y; }; // Static Metadata Descriptor Type 1 struct __attribute__ ((__packed__)) Type1 { Primaries1 mR; // display primary 0 Primaries1 mG; // display primary 1 Primaries1 mB; // display primary 2 Primaries1 mW; // white point uint16_t mMaxDisplayLuminance; // in cd/m^2 uint16_t mMinDisplayLuminance; // in 0.0001 cd/m^2 uint16_t mMaxContentLightLevel; // in cd/m^2 uint16_t mMaxFrameAverageLightLevel; // in cd/m^2 }; union { Type1 sType1; }; }; static_assert(sizeof(HDRStaticInfo::Primaries1) == 4, "wrong struct size"); static_assert(sizeof(HDRStaticInfo::Type1) == 24, "wrong struct size"); static_assert(sizeof(HDRStaticInfo) == 25, "wrong struct size"); #ifdef STRINGIFY_ENUMS inline static const char *asString(MediaImage::Type i, const char *def = "??") { switch (i) { case MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN: return "Unknown"; case MediaImage::MEDIA_IMAGE_TYPE_YUV: return "YUV"; default: return def; } } inline static const char *asString(MediaImage::PlaneIndex i, const char *def = "??") { switch (i) { case MediaImage::Y: return "Y"; case MediaImage::U: return "U"; case MediaImage::V: return "V"; default: return def; } } inline static const char *asString(MediaImage2::Type i, const char *def = "??") { switch (i) { case MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN: return "Unknown"; case MediaImage2::MEDIA_IMAGE_TYPE_YUV: return "YUV"; case MediaImage2::MEDIA_IMAGE_TYPE_YUVA: return "YUVA"; case MediaImage2::MEDIA_IMAGE_TYPE_RGB: return "RGB"; case MediaImage2::MEDIA_IMAGE_TYPE_RGBA: return "RGBA"; case MediaImage2::MEDIA_IMAGE_TYPE_Y: return "Y"; default: return def; } } inline static char asChar2( MediaImage2::PlaneIndex i, MediaImage2::Type j, char def = '?') { const char *planes = asString(j, NULL); // handle unknown values if (j == MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN || planes == NULL || i >= strlen(planes)) { return def; } return planes[i]; } inline static const char *asString(ColorAspects::Range i, const char *def = "??") { switch (i) { case ColorAspects::RangeUnspecified: return "Unspecified"; case ColorAspects::RangeFull: return "Full"; case ColorAspects::RangeLimited: return "Limited"; case ColorAspects::RangeOther: return "Other"; default: return def; } } inline static const char *asString(ColorAspects::Primaries i, const char *def = "??") { switch (i) { case ColorAspects::PrimariesUnspecified: return "Unspecified"; case ColorAspects::PrimariesBT709_5: return "BT709_5"; case ColorAspects::PrimariesBT470_6M: return "BT470_6M"; case ColorAspects::PrimariesBT601_6_625: return "BT601_6_625"; case ColorAspects::PrimariesBT601_6_525: return "BT601_6_525"; case ColorAspects::PrimariesGenericFilm: return "GenericFilm"; case ColorAspects::PrimariesBT2020: return "BT2020"; case ColorAspects::PrimariesOther: return "Other"; default: return def; } } inline static const char *asString(ColorAspects::Transfer i, const char *def = "??") { switch (i) { case ColorAspects::TransferUnspecified: return "Unspecified"; case ColorAspects::TransferLinear: return "Linear"; case ColorAspects::TransferSRGB: return "SRGB"; case ColorAspects::TransferSMPTE170M: return "SMPTE170M"; case ColorAspects::TransferGamma22: return "Gamma22"; case ColorAspects::TransferGamma28: return "Gamma28"; case ColorAspects::TransferST2084: return "ST2084"; case ColorAspects::TransferHLG: return "HLG"; case ColorAspects::TransferSMPTE240M: return "SMPTE240M"; case ColorAspects::TransferXvYCC: return "XvYCC"; case ColorAspects::TransferBT1361: return "BT1361"; case ColorAspects::TransferST428: return "ST428"; case ColorAspects::TransferOther: return "Other"; default: return def; } } inline static const char *asString(ColorAspects::MatrixCoeffs i, const char *def = "??") { switch (i) { case ColorAspects::MatrixUnspecified: return "Unspecified"; case ColorAspects::MatrixBT709_5: return "BT709_5"; case ColorAspects::MatrixBT470_6M: return "BT470_6M"; case ColorAspects::MatrixBT601_6: return "BT601_6"; case ColorAspects::MatrixSMPTE240M: return "SMPTE240M"; case ColorAspects::MatrixBT2020: return "BT2020"; case ColorAspects::MatrixBT2020Constant: return "BT2020Constant"; case ColorAspects::MatrixOther: return "Other"; default: return def; } } inline static const char *asString(ColorAspects::Standard i, const char *def = "??") { switch (i) { case ColorAspects::StandardUnspecified: return "Unspecified"; case ColorAspects::StandardBT709: return "BT709"; case ColorAspects::StandardBT601_625: return "BT601_625"; case ColorAspects::StandardBT601_625_Unadjusted: return "BT601_625_Unadjusted"; case ColorAspects::StandardBT601_525: return "BT601_525"; case ColorAspects::StandardBT601_525_Unadjusted: return "BT601_525_Unadjusted"; case ColorAspects::StandardBT2020: return "BT2020"; case ColorAspects::StandardBT2020Constant: return "BT2020Constant"; case ColorAspects::StandardBT470M: return "BT470M"; case ColorAspects::StandardFilm: return "Film"; case ColorAspects::StandardOther: return "Other"; default: return def; } } #endif } // namespace android #endif // VIDEO_API_H_ include/media/openmax/0040755 0000000 0000000 00000000000 13077405420 013763 5ustar000000000 0000000 include/media/openmax/OMX_AsString.h0100644 0000000 0000000 00000151421 13077405420 016412 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* NOTE: This file contains several sections for individual OMX include files. Each section has its own include guard. This file should be included AFTER the OMX include files. */ #ifdef ANDROID namespace android { #endif #ifdef OMX_Audio_h /* asString definitions if media/openmax/OMX_Audio.h was included */ #ifndef AS_STRING_FOR_OMX_AUDIO_H #define AS_STRING_FOR_OMX_AUDIO_H inline static const char *asString(OMX_AUDIO_CODINGTYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_CodingUnused: return "Unused"; // unused case OMX_AUDIO_CodingAutoDetect: return "AutoDetect"; // unused case OMX_AUDIO_CodingPCM: return "PCM"; case OMX_AUDIO_CodingADPCM: return "ADPCM"; // unused case OMX_AUDIO_CodingAMR: return "AMR"; case OMX_AUDIO_CodingGSMFR: return "GSMFR"; case OMX_AUDIO_CodingGSMEFR: return "GSMEFR"; // unused case OMX_AUDIO_CodingGSMHR: return "GSMHR"; // unused case OMX_AUDIO_CodingPDCFR: return "PDCFR"; // unused case OMX_AUDIO_CodingPDCEFR: return "PDCEFR"; // unused case OMX_AUDIO_CodingPDCHR: return "PDCHR"; // unused case OMX_AUDIO_CodingTDMAFR: return "TDMAFR"; // unused case OMX_AUDIO_CodingTDMAEFR: return "TDMAEFR"; // unused case OMX_AUDIO_CodingQCELP8: return "QCELP8"; // unused case OMX_AUDIO_CodingQCELP13: return "QCELP13"; // unused case OMX_AUDIO_CodingEVRC: return "EVRC"; // unused case OMX_AUDIO_CodingSMV: return "SMV"; // unused case OMX_AUDIO_CodingG711: return "G711"; case OMX_AUDIO_CodingG723: return "G723"; // unused case OMX_AUDIO_CodingG726: return "G726"; // unused case OMX_AUDIO_CodingG729: return "G729"; // unused case OMX_AUDIO_CodingAAC: return "AAC"; case OMX_AUDIO_CodingMP3: return "MP3"; case OMX_AUDIO_CodingSBC: return "SBC"; // unused case OMX_AUDIO_CodingVORBIS: return "VORBIS"; case OMX_AUDIO_CodingWMA: return "WMA"; // unused case OMX_AUDIO_CodingRA: return "RA"; // unused case OMX_AUDIO_CodingMIDI: return "MIDI"; // unused case OMX_AUDIO_CodingFLAC: return "FLAC"; default: return def; } } inline static const char *asString(OMX_AUDIO_PCMMODETYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_PCMModeLinear: return "Linear"; case OMX_AUDIO_PCMModeALaw: return "ALaw"; case OMX_AUDIO_PCMModeMULaw: return "MULaw"; default: return def; } } inline static const char *asString(OMX_AUDIO_CHANNELTYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_ChannelNone: return "None"; // unused case OMX_AUDIO_ChannelLF: return "LF"; case OMX_AUDIO_ChannelRF: return "RF"; case OMX_AUDIO_ChannelCF: return "CF"; case OMX_AUDIO_ChannelLS: return "LS"; case OMX_AUDIO_ChannelRS: return "RS"; case OMX_AUDIO_ChannelLFE: return "LFE"; case OMX_AUDIO_ChannelCS: return "CS"; case OMX_AUDIO_ChannelLR: return "LR"; case OMX_AUDIO_ChannelRR: return "RR"; default: return def; } } inline static const char *asString(OMX_AUDIO_CHANNELMODETYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_ChannelModeStereo: return "Stereo"; // case OMX_AUDIO_ChannelModeJointStereo: return "JointStereo"; // case OMX_AUDIO_ChannelModeDual: return "Dual"; case OMX_AUDIO_ChannelModeMono: return "Mono"; default: return def; } } inline static const char *asString(OMX_AUDIO_AACPROFILETYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_AACObjectNull: return "Null"; case OMX_AUDIO_AACObjectMain: return "Main"; case OMX_AUDIO_AACObjectLC: return "LC"; case OMX_AUDIO_AACObjectSSR: return "SSR"; case OMX_AUDIO_AACObjectLTP: return "LTP"; case OMX_AUDIO_AACObjectHE: return "HE"; case OMX_AUDIO_AACObjectScalable: return "Scalable"; case OMX_AUDIO_AACObjectERLC: return "ERLC"; case OMX_AUDIO_AACObjectLD: return "LD"; case OMX_AUDIO_AACObjectHE_PS: return "HE_PS"; default: return def; } } inline static const char *asString(OMX_AUDIO_AACSTREAMFORMATTYPE i, const char *def = "??") { switch (i) { // case OMX_AUDIO_AACStreamFormatMP2ADTS: return "MP2ADTS"; case OMX_AUDIO_AACStreamFormatMP4ADTS: return "MP4ADTS"; // case OMX_AUDIO_AACStreamFormatMP4LOAS: return "MP4LOAS"; // case OMX_AUDIO_AACStreamFormatMP4LATM: return "MP4LATM"; // case OMX_AUDIO_AACStreamFormatADIF: return "ADIF"; case OMX_AUDIO_AACStreamFormatMP4FF: return "MP4FF"; // case OMX_AUDIO_AACStreamFormatRAW: return "RAW"; default: return def; } } inline static const char *asString(OMX_AUDIO_AMRFRAMEFORMATTYPE i, const char *def = "??") { switch (i) { // case OMX_AUDIO_AMRFrameFormatConformance: return "Conformance"; // case OMX_AUDIO_AMRFrameFormatIF1: return "IF1"; // case OMX_AUDIO_AMRFrameFormatIF2: return "IF2"; case OMX_AUDIO_AMRFrameFormatFSF: return "FSF"; // case OMX_AUDIO_AMRFrameFormatRTPPayload: return "RTPPayload"; // case OMX_AUDIO_AMRFrameFormatITU: return "ITU"; default: return def; } } inline static const char *asString(OMX_AUDIO_AMRBANDMODETYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_AMRBandModeUnused: return "Unused"; case OMX_AUDIO_AMRBandModeNB0: return "NB0"; case OMX_AUDIO_AMRBandModeNB1: return "NB1"; case OMX_AUDIO_AMRBandModeNB2: return "NB2"; case OMX_AUDIO_AMRBandModeNB3: return "NB3"; case OMX_AUDIO_AMRBandModeNB4: return "NB4"; case OMX_AUDIO_AMRBandModeNB5: return "NB5"; case OMX_AUDIO_AMRBandModeNB6: return "NB6"; case OMX_AUDIO_AMRBandModeNB7: return "NB7"; case OMX_AUDIO_AMRBandModeWB0: return "WB0"; case OMX_AUDIO_AMRBandModeWB1: return "WB1"; case OMX_AUDIO_AMRBandModeWB2: return "WB2"; case OMX_AUDIO_AMRBandModeWB3: return "WB3"; case OMX_AUDIO_AMRBandModeWB4: return "WB4"; case OMX_AUDIO_AMRBandModeWB5: return "WB5"; case OMX_AUDIO_AMRBandModeWB6: return "WB6"; case OMX_AUDIO_AMRBandModeWB7: return "WB7"; case OMX_AUDIO_AMRBandModeWB8: return "WB8"; default: return def; } } inline static const char *asString(OMX_AUDIO_AMRDTXMODETYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_AMRDTXModeOff: return "ModeOff"; // case OMX_AUDIO_AMRDTXModeOnVAD1: return "ModeOnVAD1"; // case OMX_AUDIO_AMRDTXModeOnVAD2: return "ModeOnVAD2"; // case OMX_AUDIO_AMRDTXModeOnAuto: return "ModeOnAuto"; // case OMX_AUDIO_AMRDTXasEFR: return "asEFR"; default: return def; } } #endif // AS_STRING_FOR_OMX_AUDIO_H #endif // OMX_Audio_h #ifdef OMX_AudioExt_h /* asString definitions if media/openmax/OMX_AudioExt.h was included */ #ifndef AS_STRING_FOR_OMX_AUDIOEXT_H #define AS_STRING_FOR_OMX_AUDIOEXT_H inline static const char *asString(OMX_AUDIO_CODINGEXTTYPE i, const char *def = "??") { switch (i) { case OMX_AUDIO_CodingAndroidAC3: return "AndroidAC3"; case OMX_AUDIO_CodingAndroidOPUS: return "AndroidOPUS"; default: return asString((OMX_AUDIO_CODINGTYPE)i, def); } } #endif // AS_STRING_FOR_OMX_AUDIOEXT_H #endif // OMX_AudioExt_h #ifdef OMX_Component_h /* asString definitions if media/openmax/OMX_Component.h was included */ #ifndef AS_STRING_FOR_OMX_COMPONENT_H #define AS_STRING_FOR_OMX_COMPONENT_H inline static const char *asString(OMX_PORTDOMAINTYPE i, const char *def = "??") { switch (i) { case OMX_PortDomainAudio: return "Audio"; case OMX_PortDomainVideo: return "Video"; case OMX_PortDomainImage: return "Image"; // case OMX_PortDomainOther: return "Other"; default: return def; } } #endif // AS_STRING_FOR_OMX_COMPONENT_H #endif // OMX_Component_h #ifdef OMX_Core_h /* asString definitions if media/openmax/OMX_Core.h was included */ #ifndef AS_STRING_FOR_OMX_CORE_H #define AS_STRING_FOR_OMX_CORE_H inline static const char *asString(OMX_COMMANDTYPE i, const char *def = "??") { switch (i) { case OMX_CommandStateSet: return "StateSet"; case OMX_CommandFlush: return "Flush"; case OMX_CommandPortDisable: return "PortDisable"; case OMX_CommandPortEnable: return "PortEnable"; // case OMX_CommandMarkBuffer: return "MarkBuffer"; default: return def; } } inline static const char *asString(OMX_STATETYPE i, const char *def = "??") { switch (i) { case OMX_StateInvalid: return "Invalid"; case OMX_StateLoaded: return "Loaded"; case OMX_StateIdle: return "Idle"; case OMX_StateExecuting: return "Executing"; // case OMX_StatePause: return "Pause"; // case OMX_StateWaitForResources: return "WaitForResources"; default: return def; } } inline static const char *asString(OMX_ERRORTYPE i, const char *def = "??") { switch (i) { case OMX_ErrorNone: return "None"; case OMX_ErrorInsufficientResources: return "InsufficientResources"; case OMX_ErrorUndefined: return "Undefined"; case OMX_ErrorInvalidComponentName: return "InvalidComponentName"; case OMX_ErrorComponentNotFound: return "ComponentNotFound"; case OMX_ErrorInvalidComponent: return "InvalidComponent"; // unused case OMX_ErrorBadParameter: return "BadParameter"; case OMX_ErrorNotImplemented: return "NotImplemented"; case OMX_ErrorUnderflow: return "Underflow"; // unused case OMX_ErrorOverflow: return "Overflow"; // unused case OMX_ErrorHardware: return "Hardware"; // unused case OMX_ErrorInvalidState: return "InvalidState"; case OMX_ErrorStreamCorrupt: return "StreamCorrupt"; case OMX_ErrorPortsNotCompatible: return "PortsNotCompatible"; // unused case OMX_ErrorResourcesLost: return "ResourcesLost"; case OMX_ErrorNoMore: return "NoMore"; case OMX_ErrorVersionMismatch: return "VersionMismatch"; // unused case OMX_ErrorNotReady: return "NotReady"; // unused case OMX_ErrorTimeout: return "Timeout"; // unused case OMX_ErrorSameState: return "SameState"; // unused case OMX_ErrorResourcesPreempted: return "ResourcesPreempted"; // unused case OMX_ErrorPortUnresponsiveDuringAllocation: return "PortUnresponsiveDuringAllocation"; // unused case OMX_ErrorPortUnresponsiveDuringDeallocation: return "PortUnresponsiveDuringDeallocation"; // unused case OMX_ErrorPortUnresponsiveDuringStop: return "PortUnresponsiveDuringStop"; // unused case OMX_ErrorIncorrectStateTransition: return "IncorrectStateTransition"; // unused case OMX_ErrorIncorrectStateOperation: return "IncorrectStateOperation"; // unused case OMX_ErrorUnsupportedSetting: return "UnsupportedSetting"; case OMX_ErrorUnsupportedIndex: return "UnsupportedIndex"; case OMX_ErrorBadPortIndex: return "BadPortIndex"; case OMX_ErrorPortUnpopulated: return "PortUnpopulated"; // unused case OMX_ErrorComponentSuspended: return "ComponentSuspended"; // unused case OMX_ErrorDynamicResourcesUnavailable: return "DynamicResourcesUnavailable"; // unused case OMX_ErrorMbErrorsInFrame: return "MbErrorsInFrame"; // unused case OMX_ErrorFormatNotDetected: return "FormatNotDetected"; // unused case OMX_ErrorContentPipeOpenFailed: return "ContentPipeOpenFailed"; // unused case OMX_ErrorContentPipeCreationFailed: return "ContentPipeCreationFailed"; // unused case OMX_ErrorSeperateTablesUsed: return "SeperateTablesUsed"; // unused case OMX_ErrorTunnelingUnsupported: return "TunnelingUnsupported"; // unused default: return def; } } inline static const char *asString(OMX_EVENTTYPE i, const char *def = "??") { switch (i) { case OMX_EventCmdComplete: return "CmdComplete"; case OMX_EventError: return "Error"; // case OMX_EventMark: return "Mark"; case OMX_EventPortSettingsChanged: return "PortSettingsChanged"; case OMX_EventBufferFlag: return "BufferFlag"; // case OMX_EventResourcesAcquired: return "ResourcesAcquired"; // case OMX_EventComponentResumed: return "ComponentResumed"; // case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable"; // case OMX_EventPortFormatDetected: return "PortFormatDetected"; case OMX_EventOutputRendered: return "OutputRendered"; case OMX_EventDataSpaceChanged: return "DataSpaceChanged"; default: return def; } } #endif // AS_STRING_FOR_OMX_CORE_H #endif // OMX_Core_h #ifdef OMX_Image_h /* asString definitions if media/openmax/OMX_Image.h was included */ #ifndef AS_STRING_FOR_OMX_IMAGE_H #define AS_STRING_FOR_OMX_IMAGE_H inline static const char *asString(OMX_IMAGE_CODINGTYPE i, const char *def = "??") { switch (i) { case OMX_IMAGE_CodingUnused: return "Unused"; case OMX_IMAGE_CodingAutoDetect: return "AutoDetect"; // unused case OMX_IMAGE_CodingJPEG: return "JPEG"; case OMX_IMAGE_CodingJPEG2K: return "JPEG2K"; // unused case OMX_IMAGE_CodingEXIF: return "EXIF"; // unused case OMX_IMAGE_CodingTIFF: return "TIFF"; // unused case OMX_IMAGE_CodingGIF: return "GIF"; // unused case OMX_IMAGE_CodingPNG: return "PNG"; // unused case OMX_IMAGE_CodingLZW: return "LZW"; // unused case OMX_IMAGE_CodingBMP: return "BMP"; // unused default: return def; } } #endif // AS_STRING_FOR_OMX_IMAGE_H #endif // OMX_Image_h #ifdef OMX_Index_h /* asString definitions if media/openmax/OMX_Index.h was included */ #ifndef AS_STRING_FOR_OMX_INDEX_H #define AS_STRING_FOR_OMX_INDEX_H inline static const char *asString(OMX_INDEXTYPE i, const char *def = "??") { switch (i) { // case OMX_IndexParamPriorityMgmt: return "ParamPriorityMgmt"; // case OMX_IndexParamAudioInit: return "ParamAudioInit"; // case OMX_IndexParamImageInit: return "ParamImageInit"; // case OMX_IndexParamVideoInit: return "ParamVideoInit"; // case OMX_IndexParamOtherInit: return "ParamOtherInit"; // case OMX_IndexParamNumAvailableStreams: return "ParamNumAvailableStreams"; // case OMX_IndexParamActiveStream: return "ParamActiveStream"; // case OMX_IndexParamSuspensionPolicy: return "ParamSuspensionPolicy"; // case OMX_IndexParamComponentSuspended: return "ParamComponentSuspended"; // case OMX_IndexConfigCapturing: return "ConfigCapturing"; // case OMX_IndexConfigCaptureMode: return "ConfigCaptureMode"; // case OMX_IndexAutoPauseAfterCapture: return "AutoPauseAfterCapture"; // case OMX_IndexParamContentURI: return "ParamContentURI"; // case OMX_IndexParamCustomContentPipe: return "ParamCustomContentPipe"; // case OMX_IndexParamDisableResourceConcealment: // return "ParamDisableResourceConcealment"; // case OMX_IndexConfigMetadataItemCount: return "ConfigMetadataItemCount"; // case OMX_IndexConfigContainerNodeCount: return "ConfigContainerNodeCount"; // case OMX_IndexConfigMetadataItem: return "ConfigMetadataItem"; // case OMX_IndexConfigCounterNodeID: return "ConfigCounterNodeID"; // case OMX_IndexParamMetadataFilterType: return "ParamMetadataFilterType"; // case OMX_IndexParamMetadataKeyFilter: return "ParamMetadataKeyFilter"; // case OMX_IndexConfigPriorityMgmt: return "ConfigPriorityMgmt"; case OMX_IndexParamStandardComponentRole: return "ParamStandardComponentRole"; case OMX_IndexParamPortDefinition: return "ParamPortDefinition"; // case OMX_IndexParamCompBufferSupplier: return "ParamCompBufferSupplier"; case OMX_IndexParamAudioPortFormat: return "ParamAudioPortFormat"; case OMX_IndexParamAudioPcm: return "ParamAudioPcm"; case OMX_IndexParamAudioAac: return "ParamAudioAac"; // case OMX_IndexParamAudioRa: return "ParamAudioRa"; case OMX_IndexParamAudioMp3: return "ParamAudioMp3"; // case OMX_IndexParamAudioAdpcm: return "ParamAudioAdpcm"; // case OMX_IndexParamAudioG723: return "ParamAudioG723"; // case OMX_IndexParamAudioG729: return "ParamAudioG729"; case OMX_IndexParamAudioAmr: return "ParamAudioAmr"; // case OMX_IndexParamAudioWma: return "ParamAudioWma"; // case OMX_IndexParamAudioSbc: return "ParamAudioSbc"; // case OMX_IndexParamAudioMidi: return "ParamAudioMidi"; // case OMX_IndexParamAudioGsm_FR: return "ParamAudioGsm_FR"; // case OMX_IndexParamAudioMidiLoadUserSound: return "ParamAudioMidiLoadUserSound"; // case OMX_IndexParamAudioG726: return "ParamAudioG726"; // case OMX_IndexParamAudioGsm_EFR: return "ParamAudioGsm_EFR"; // case OMX_IndexParamAudioGsm_HR: return "ParamAudioGsm_HR"; // case OMX_IndexParamAudioPdc_FR: return "ParamAudioPdc_FR"; // case OMX_IndexParamAudioPdc_EFR: return "ParamAudioPdc_EFR"; // case OMX_IndexParamAudioPdc_HR: return "ParamAudioPdc_HR"; // case OMX_IndexParamAudioTdma_FR: return "ParamAudioTdma_FR"; // case OMX_IndexParamAudioTdma_EFR: return "ParamAudioTdma_EFR"; // case OMX_IndexParamAudioQcelp8: return "ParamAudioQcelp8"; // case OMX_IndexParamAudioQcelp13: return "ParamAudioQcelp13"; // case OMX_IndexParamAudioEvrc: return "ParamAudioEvrc"; // case OMX_IndexParamAudioSmv: return "ParamAudioSmv"; case OMX_IndexParamAudioVorbis: return "ParamAudioVorbis"; case OMX_IndexParamAudioFlac: return "ParamAudioFlac"; // case OMX_IndexConfigAudioMidiImmediateEvent: return "ConfigAudioMidiImmediateEvent"; // case OMX_IndexConfigAudioMidiControl: return "ConfigAudioMidiControl"; // case OMX_IndexConfigAudioMidiSoundBankProgram: // return "ConfigAudioMidiSoundBankProgram"; // case OMX_IndexConfigAudioMidiStatus: return "ConfigAudioMidiStatus"; // case OMX_IndexConfigAudioMidiMetaEvent: return "ConfigAudioMidiMetaEvent"; // case OMX_IndexConfigAudioMidiMetaEventData: return "ConfigAudioMidiMetaEventData"; // case OMX_IndexConfigAudioVolume: return "ConfigAudioVolume"; // case OMX_IndexConfigAudioBalance: return "ConfigAudioBalance"; // case OMX_IndexConfigAudioChannelMute: return "ConfigAudioChannelMute"; // case OMX_IndexConfigAudioMute: return "ConfigAudioMute"; // case OMX_IndexConfigAudioLoudness: return "ConfigAudioLoudness"; // case OMX_IndexConfigAudioEchoCancelation: return "ConfigAudioEchoCancelation"; // case OMX_IndexConfigAudioNoiseReduction: return "ConfigAudioNoiseReduction"; // case OMX_IndexConfigAudioBass: return "ConfigAudioBass"; // case OMX_IndexConfigAudioTreble: return "ConfigAudioTreble"; // case OMX_IndexConfigAudioStereoWidening: return "ConfigAudioStereoWidening"; // case OMX_IndexConfigAudioChorus: return "ConfigAudioChorus"; // case OMX_IndexConfigAudioEqualizer: return "ConfigAudioEqualizer"; // case OMX_IndexConfigAudioReverberation: return "ConfigAudioReverberation"; // case OMX_IndexConfigAudioChannelVolume: return "ConfigAudioChannelVolume"; // case OMX_IndexParamImagePortFormat: return "ParamImagePortFormat"; // case OMX_IndexParamFlashControl: return "ParamFlashControl"; // case OMX_IndexConfigFocusControl: return "ConfigFocusControl"; // case OMX_IndexParamQFactor: return "ParamQFactor"; // case OMX_IndexParamQuantizationTable: return "ParamQuantizationTable"; // case OMX_IndexParamHuffmanTable: return "ParamHuffmanTable"; // case OMX_IndexConfigFlashControl: return "ConfigFlashControl"; case OMX_IndexParamVideoPortFormat: return "ParamVideoPortFormat"; // case OMX_IndexParamVideoQuantization: return "ParamVideoQuantization"; // case OMX_IndexParamVideoFastUpdate: return "ParamVideoFastUpdate"; case OMX_IndexParamVideoBitrate: return "ParamVideoBitrate"; // case OMX_IndexParamVideoMotionVector: return "ParamVideoMotionVector"; case OMX_IndexParamVideoIntraRefresh: return "ParamVideoIntraRefresh"; case OMX_IndexParamVideoErrorCorrection: return "ParamVideoErrorCorrection"; // case OMX_IndexParamVideoVBSMC: return "ParamVideoVBSMC"; // case OMX_IndexParamVideoMpeg2: return "ParamVideoMpeg2"; case OMX_IndexParamVideoMpeg4: return "ParamVideoMpeg4"; // case OMX_IndexParamVideoWmv: return "ParamVideoWmv"; // case OMX_IndexParamVideoRv: return "ParamVideoRv"; case OMX_IndexParamVideoAvc: return "ParamVideoAvc"; case OMX_IndexParamVideoH263: return "ParamVideoH263"; case OMX_IndexParamVideoProfileLevelQuerySupported: return "ParamVideoProfileLevelQuerySupported"; case OMX_IndexParamVideoProfileLevelCurrent: return "ParamVideoProfileLevelCurrent"; case OMX_IndexConfigVideoBitrate: return "ConfigVideoBitrate"; // case OMX_IndexConfigVideoFramerate: return "ConfigVideoFramerate"; case OMX_IndexConfigVideoIntraVOPRefresh: return "ConfigVideoIntraVOPRefresh"; // case OMX_IndexConfigVideoIntraMBRefresh: return "ConfigVideoIntraMBRefresh"; // case OMX_IndexConfigVideoMBErrorReporting: return "ConfigVideoMBErrorReporting"; // case OMX_IndexParamVideoMacroblocksPerFrame: return "ParamVideoMacroblocksPerFrame"; // case OMX_IndexConfigVideoMacroBlockErrorMap: return "ConfigVideoMacroBlockErrorMap"; // case OMX_IndexParamVideoSliceFMO: return "ParamVideoSliceFMO"; // case OMX_IndexConfigVideoAVCIntraPeriod: return "ConfigVideoAVCIntraPeriod"; // case OMX_IndexConfigVideoNalSize: return "ConfigVideoNalSize"; // case OMX_IndexParamCommonDeblocking: return "ParamCommonDeblocking"; // case OMX_IndexParamCommonSensorMode: return "ParamCommonSensorMode"; // case OMX_IndexParamCommonInterleave: return "ParamCommonInterleave"; // case OMX_IndexConfigCommonColorFormatConversion: // return "ConfigCommonColorFormatConversion"; case OMX_IndexConfigCommonScale: return "ConfigCommonScale"; // case OMX_IndexConfigCommonImageFilter: return "ConfigCommonImageFilter"; // case OMX_IndexConfigCommonColorEnhancement: return "ConfigCommonColorEnhancement"; // case OMX_IndexConfigCommonColorKey: return "ConfigCommonColorKey"; // case OMX_IndexConfigCommonColorBlend: return "ConfigCommonColorBlend"; // case OMX_IndexConfigCommonFrameStabilisation: return "ConfigCommonFrameStabilisation"; // case OMX_IndexConfigCommonRotate: return "ConfigCommonRotate"; // case OMX_IndexConfigCommonMirror: return "ConfigCommonMirror"; // case OMX_IndexConfigCommonOutputPosition: return "ConfigCommonOutputPosition"; case OMX_IndexConfigCommonInputCrop: return "ConfigCommonInputCrop"; case OMX_IndexConfigCommonOutputCrop: return "ConfigCommonOutputCrop"; // case OMX_IndexConfigCommonDigitalZoom: return "ConfigCommonDigitalZoom"; // case OMX_IndexConfigCommonOpticalZoom: return "ConfigCommonOpticalZoom"; // case OMX_IndexConfigCommonWhiteBalance: return "ConfigCommonWhiteBalance"; // case OMX_IndexConfigCommonExposure: return "ConfigCommonExposure"; // case OMX_IndexConfigCommonContrast: return "ConfigCommonContrast"; // case OMX_IndexConfigCommonBrightness: return "ConfigCommonBrightness"; // case OMX_IndexConfigCommonBacklight: return "ConfigCommonBacklight"; // case OMX_IndexConfigCommonGamma: return "ConfigCommonGamma"; // case OMX_IndexConfigCommonSaturation: return "ConfigCommonSaturation"; // case OMX_IndexConfigCommonLightness: return "ConfigCommonLightness"; // case OMX_IndexConfigCommonExclusionRect: return "ConfigCommonExclusionRect"; // case OMX_IndexConfigCommonDithering: return "ConfigCommonDithering"; // case OMX_IndexConfigCommonPlaneBlend: return "ConfigCommonPlaneBlend"; // case OMX_IndexConfigCommonExposureValue: return "ConfigCommonExposureValue"; // case OMX_IndexConfigCommonOutputSize: return "ConfigCommonOutputSize"; // case OMX_IndexParamCommonExtraQuantData: return "ParamCommonExtraQuantData"; // case OMX_IndexConfigCommonFocusRegion: return "ConfigCommonFocusRegion"; // case OMX_IndexConfigCommonFocusStatus: return "ConfigCommonFocusStatus"; // case OMX_IndexConfigCommonTransitionEffect: return "ConfigCommonTransitionEffect"; // case OMX_IndexParamOtherPortFormat: return "ParamOtherPortFormat"; // case OMX_IndexConfigOtherPower: return "ConfigOtherPower"; // case OMX_IndexConfigOtherStats: return "ConfigOtherStats"; // case OMX_IndexConfigTimeScale: return "ConfigTimeScale"; // case OMX_IndexConfigTimeClockState: return "ConfigTimeClockState"; // case OMX_IndexConfigTimeActiveRefClock: return "ConfigTimeActiveRefClock"; // case OMX_IndexConfigTimeCurrentMediaTime: return "ConfigTimeCurrentMediaTime"; // case OMX_IndexConfigTimeCurrentWallTime: return "ConfigTimeCurrentWallTime"; // case OMX_IndexConfigTimeCurrentAudioReference: // return "ConfigTimeCurrentAudioReference"; // case OMX_IndexConfigTimeCurrentVideoReference: // return "ConfigTimeCurrentVideoReference"; // case OMX_IndexConfigTimeMediaTimeRequest: return "ConfigTimeMediaTimeRequest"; // case OMX_IndexConfigTimeClientStartTime: return "ConfigTimeClientStartTime"; // case OMX_IndexConfigTimePosition: return "ConfigTimePosition"; // case OMX_IndexConfigTimeSeekMode: return "ConfigTimeSeekMode"; default: return def; } } #endif // AS_STRING_FOR_OMX_INDEX_H #endif // OMX_Index_h #ifdef OMX_IndexExt_h /* asString definitions if media/openmax/OMX_IndexExt.h was included */ #ifndef AS_STRING_FOR_OMX_INDEXEXT_H #define AS_STRING_FOR_OMX_INDEXEXT_H inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { switch (i) { // case OMX_IndexConfigCallbackRequest: return "ConfigCallbackRequest"; // case OMX_IndexConfigCommitMode: return "ConfigCommitMode"; // case OMX_IndexConfigCommit: return "ConfigCommit"; case OMX_IndexParamAudioAndroidAc3: return "ParamAudioAndroidAc3"; case OMX_IndexParamAudioAndroidOpus: return "ParamAudioAndroidOpus"; case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation"; // case OMX_IndexParamNalStreamFormatSupported: return "ParamNalStreamFormatSupported"; // case OMX_IndexParamNalStreamFormat: return "ParamNalStreamFormat"; // case OMX_IndexParamNalStreamFormatSelect: return "ParamNalStreamFormatSelect"; case OMX_IndexParamVideoVp8: return "ParamVideoVp8"; // case OMX_IndexConfigVideoVp8ReferenceFrame: return "ConfigVideoVp8ReferenceFrame"; // case OMX_IndexConfigVideoVp8ReferenceFrameType: return "ConfigVideoVp8ReferenceFrameType"; case OMX_IndexParamVideoAndroidVp8Encoder: return "ParamVideoAndroidVp8Encoder"; case OMX_IndexParamVideoHevc: return "ParamVideoHevc"; // case OMX_IndexParamSliceSegments: return "ParamSliceSegments"; case OMX_IndexConfigAndroidIntraRefresh: return "ConfigAndroidIntraRefresh"; case OMX_IndexConfigAutoFramerateConversion: return "ConfigAutoFramerateConversion"; case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; default: return asString((OMX_INDEXTYPE)i, def); } } #endif // AS_STRING_FOR_OMX_INDEXEXT_H #endif // OMX_IndexExt_h #ifdef OMX_IVCommon_h /* asString definitions if media/openmax/OMX_IVCommon.h was included */ #ifndef AS_STRING_FOR_OMX_IVCOMMON_H #define AS_STRING_FOR_OMX_IVCOMMON_H inline static const char *asString(OMX_COLOR_FORMATTYPE i, const char *def = "??") { switch (i) { case OMX_COLOR_FormatUnused: return "COLOR_FormatUnused"; case OMX_COLOR_FormatMonochrome: return "COLOR_FormatMonochrome"; case OMX_COLOR_Format8bitRGB332: return "COLOR_Format8bitRGB332"; case OMX_COLOR_Format12bitRGB444: return "COLOR_Format12bitRGB444"; case OMX_COLOR_Format16bitARGB4444: return "COLOR_Format16bitARGB4444"; case OMX_COLOR_Format16bitARGB1555: return "COLOR_Format16bitARGB1555"; case OMX_COLOR_Format16bitRGB565: return "COLOR_Format16bitRGB565"; case OMX_COLOR_Format16bitBGR565: return "COLOR_Format16bitBGR565"; case OMX_COLOR_Format18bitRGB666: return "COLOR_Format18bitRGB666"; case OMX_COLOR_Format18bitARGB1665: return "COLOR_Format18bitARGB1665"; case OMX_COLOR_Format19bitARGB1666: return "COLOR_Format19bitARGB1666"; case OMX_COLOR_Format24bitRGB888: return "COLOR_Format24bitRGB888"; case OMX_COLOR_Format24bitBGR888: return "COLOR_Format24bitBGR888"; case OMX_COLOR_Format24bitARGB1887: return "COLOR_Format24bitARGB1887"; case OMX_COLOR_Format25bitARGB1888: return "COLOR_Format25bitARGB1888"; case OMX_COLOR_Format32bitBGRA8888: return "COLOR_Format32bitBGRA8888"; case OMX_COLOR_Format32bitARGB8888: return "COLOR_Format32bitARGB8888"; case OMX_COLOR_FormatYUV411Planar: return "COLOR_FormatYUV411Planar"; case OMX_COLOR_FormatYUV411PackedPlanar: return "COLOR_FormatYUV411PackedPlanar"; case OMX_COLOR_FormatYUV420Planar: return "COLOR_FormatYUV420Planar"; case OMX_COLOR_FormatYUV420PackedPlanar: return "COLOR_FormatYUV420PackedPlanar"; case OMX_COLOR_FormatYUV420SemiPlanar: return "COLOR_FormatYUV420SemiPlanar"; case OMX_COLOR_FormatYUV422Planar: return "COLOR_FormatYUV422Planar"; case OMX_COLOR_FormatYUV422PackedPlanar: return "COLOR_FormatYUV422PackedPlanar"; case OMX_COLOR_FormatYUV422SemiPlanar: return "COLOR_FormatYUV422SemiPlanar"; case OMX_COLOR_FormatYCbYCr: return "COLOR_FormatYCbYCr"; case OMX_COLOR_FormatYCrYCb: return "COLOR_FormatYCrYCb"; case OMX_COLOR_FormatCbYCrY: return "COLOR_FormatCbYCrY"; case OMX_COLOR_FormatCrYCbY: return "COLOR_FormatCrYCbY"; case OMX_COLOR_FormatYUV444Interleaved: return "COLOR_FormatYUV444Interleaved"; case OMX_COLOR_FormatRawBayer8bit: return "COLOR_FormatRawBayer8bit"; case OMX_COLOR_FormatRawBayer10bit: return "COLOR_FormatRawBayer10bit"; case OMX_COLOR_FormatRawBayer8bitcompressed: return "COLOR_FormatRawBayer8bitcompressed"; case OMX_COLOR_FormatL2: return "COLOR_FormatL2"; case OMX_COLOR_FormatL4: return "COLOR_FormatL4"; case OMX_COLOR_FormatL8: return "COLOR_FormatL8"; case OMX_COLOR_FormatL16: return "COLOR_FormatL16"; case OMX_COLOR_FormatL24: return "COLOR_FormatL24"; case OMX_COLOR_FormatL32: return "COLOR_FormatL32"; case OMX_COLOR_FormatYUV420PackedSemiPlanar: return "COLOR_FormatYUV420PackedSemiPlanar"; case OMX_COLOR_FormatYUV422PackedSemiPlanar: return "COLOR_FormatYUV422PackedSemiPlanar"; case OMX_COLOR_Format18BitBGR666: return "COLOR_Format18BitBGR666"; case OMX_COLOR_Format24BitARGB6666: return "COLOR_Format24BitARGB6666"; case OMX_COLOR_Format24BitABGR6666: return "COLOR_Format24BitABGR6666"; case OMX_COLOR_FormatAndroidOpaque: return "COLOR_FormatAndroidOpaque"; case OMX_COLOR_FormatYUV420Flexible: return "COLOR_FormatYUV420Flexible"; case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: return "TI_COLOR_FormatYUV420PackedSemiPlanar"; case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: return "QCOM_COLOR_FormatYVU420SemiPlanar"; // case OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka: // return "QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka"; // case OMX_SEC_COLOR_FormatNV12Tiled: // return "SEC_COLOR_FormatNV12Tiled"; // case OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m: // return "QCOM_COLOR_FormatYUV420PackedSemiPlanar32m"; default: return def; } } #endif // AS_STRING_FOR_OMX_IVCOMMON_H #endif // OMX_IVCommon_h #ifdef OMX_Types_h /* asString definitions if media/openmax/OMX_Types.h was included */ #ifndef AS_STRING_FOR_OMX_TYPES_H #define AS_STRING_FOR_OMX_TYPES_H inline static const char *asString(OMX_BOOL i, const char *def = "??") { switch (i) { case OMX_FALSE: return "FALSE"; case OMX_TRUE: return "TRUE"; default: return def; } } inline static const char *asString(OMX_DIRTYPE i, const char *def = "??") { switch (i) { case OMX_DirInput: return "Input"; case OMX_DirOutput: return "Output"; default: return def; } } inline static const char *asString(OMX_ENDIANTYPE i, const char *def = "??") { switch (i) { case OMX_EndianBig: return "Big"; // case OMX_EndianLittle: return "Little"; default: return def; } } inline static const char *asString(OMX_NUMERICALDATATYPE i, const char *def = "??") { switch (i) { case OMX_NumericalDataSigned: return "Signed"; // case OMX_NumericalDataUnsigned: return "Unsigned"; default: return def; } } #endif // AS_STRING_FOR_OMX_TYPES_H #endif // OMX_Types_h #ifdef OMX_Video_h /* asString definitions if media/openmax/OMX_Video.h was included */ #ifndef AS_STRING_FOR_OMX_VIDEO_H #define AS_STRING_FOR_OMX_VIDEO_H inline static const char *asString(OMX_VIDEO_CODINGTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_CodingUnused: return "Unused"; case OMX_VIDEO_CodingAutoDetect: return "AutoDetect"; // unused case OMX_VIDEO_CodingMPEG2: return "MPEG2"; case OMX_VIDEO_CodingH263: return "H263"; case OMX_VIDEO_CodingMPEG4: return "MPEG4"; case OMX_VIDEO_CodingWMV: return "WMV"; // unused case OMX_VIDEO_CodingRV: return "RV"; // unused case OMX_VIDEO_CodingAVC: return "AVC"; case OMX_VIDEO_CodingMJPEG: return "MJPEG"; // unused case OMX_VIDEO_CodingVP8: return "VP8"; case OMX_VIDEO_CodingVP9: return "VP9"; case OMX_VIDEO_CodingHEVC: return "HEVC"; case OMX_VIDEO_CodingDolbyVision:return "DolbyVision"; default: return def; } } inline static const char *asString(OMX_VIDEO_CONTROLRATETYPE i, const char *def = "??") { switch (i) { // case OMX_Video_ControlRateDisable: return "Disable"; case OMX_Video_ControlRateVariable: return "Variable"; case OMX_Video_ControlRateConstant: return "Constant"; // case OMX_Video_ControlRateVariableSkipFrames: return "VariableSkipFrames"; // case OMX_Video_ControlRateConstantSkipFrames: return "ConstantSkipFrames"; default: return def; } } inline static const char *asString(OMX_VIDEO_INTRAREFRESHTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_IntraRefreshCyclic: return "Cyclic"; case OMX_VIDEO_IntraRefreshAdaptive: return "Adaptive"; case OMX_VIDEO_IntraRefreshBoth: return "Both"; default: return def; } } inline static const char *asString(OMX_VIDEO_H263PROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_H263ProfileBaseline: return "Baseline"; case OMX_VIDEO_H263ProfileH320Coding: return "H320Coding"; case OMX_VIDEO_H263ProfileBackwardCompatible: return "BackwardCompatible"; case OMX_VIDEO_H263ProfileISWV2: return "ISWV2"; case OMX_VIDEO_H263ProfileISWV3: return "ISWV3"; case OMX_VIDEO_H263ProfileHighCompression: return "HighCompression"; case OMX_VIDEO_H263ProfileInternet: return "Internet"; case OMX_VIDEO_H263ProfileInterlace: return "Interlace"; case OMX_VIDEO_H263ProfileHighLatency: return "HighLatency"; default: return def; } } inline static const char *asString(OMX_VIDEO_H263LEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_H263Level10: return "Level10"; case OMX_VIDEO_H263Level20: return "Level20"; case OMX_VIDEO_H263Level30: return "Level30"; case OMX_VIDEO_H263Level40: return "Level40"; case OMX_VIDEO_H263Level45: return "Level45"; case OMX_VIDEO_H263Level50: return "Level50"; case OMX_VIDEO_H263Level60: return "Level60"; case OMX_VIDEO_H263Level70: return "Level70"; default: return def; } } inline static const char *asString(OMX_VIDEO_PICTURETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_PictureTypeI: return "I"; case OMX_VIDEO_PictureTypeP: return "P"; case OMX_VIDEO_PictureTypeB: return "B"; // case OMX_VIDEO_PictureTypeSI: return "SI"; // case OMX_VIDEO_PictureTypeSP: return "SP"; // case OMX_VIDEO_PictureTypeEI: return "EI"; // case OMX_VIDEO_PictureTypeEP: return "EP"; // case OMX_VIDEO_PictureTypeS: return "S"; default: return def; } } inline static const char *asString(OMX_VIDEO_MPEG4PROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_MPEG4ProfileSimple: return "Simple"; case OMX_VIDEO_MPEG4ProfileSimpleScalable: return "SimpleScalable"; case OMX_VIDEO_MPEG4ProfileCore: return "Core"; case OMX_VIDEO_MPEG4ProfileMain: return "Main"; case OMX_VIDEO_MPEG4ProfileNbit: return "Nbit"; case OMX_VIDEO_MPEG4ProfileScalableTexture: return "ScalableTexture"; case OMX_VIDEO_MPEG4ProfileSimpleFace: return "SimpleFace"; case OMX_VIDEO_MPEG4ProfileSimpleFBA: return "SimpleFBA"; case OMX_VIDEO_MPEG4ProfileBasicAnimated: return "BasicAnimated"; case OMX_VIDEO_MPEG4ProfileHybrid: return "Hybrid"; case OMX_VIDEO_MPEG4ProfileAdvancedRealTime: return "AdvancedRealTime"; case OMX_VIDEO_MPEG4ProfileCoreScalable: return "CoreScalable"; case OMX_VIDEO_MPEG4ProfileAdvancedCoding: return "AdvancedCoding"; case OMX_VIDEO_MPEG4ProfileAdvancedCore: return "AdvancedCore"; case OMX_VIDEO_MPEG4ProfileAdvancedScalable: return "AdvancedScalable"; case OMX_VIDEO_MPEG4ProfileAdvancedSimple: return "AdvancedSimple"; default: return def; } } inline static const char *asString(OMX_VIDEO_MPEG4LEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_MPEG4Level0: return "Level0"; case OMX_VIDEO_MPEG4Level0b: return "Level0b"; case OMX_VIDEO_MPEG4Level1: return "Level1"; case OMX_VIDEO_MPEG4Level2: return "Level2"; case OMX_VIDEO_MPEG4Level3: return "Level3"; case OMX_VIDEO_MPEG4Level3b: return "Level3b"; case OMX_VIDEO_MPEG4Level4: return "Level4"; case OMX_VIDEO_MPEG4Level4a: return "Level4a"; case OMX_VIDEO_MPEG4Level5: return "Level5"; case OMX_VIDEO_MPEG4Level6: return "Level6"; default: return def; } } inline static const char *asString(OMX_VIDEO_MPEG2PROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_MPEG2ProfileSimple: return "Simple"; case OMX_VIDEO_MPEG2ProfileMain: return "Main"; case OMX_VIDEO_MPEG2Profile422: return "4:2:2"; case OMX_VIDEO_MPEG2ProfileSNR: return "SNR"; case OMX_VIDEO_MPEG2ProfileSpatial: return "Spatial"; case OMX_VIDEO_MPEG2ProfileHigh: return "High"; default: return def; } } inline static const char *asString(OMX_VIDEO_MPEG2LEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_MPEG2LevelLL: return "Low"; case OMX_VIDEO_MPEG2LevelML: return "Main"; case OMX_VIDEO_MPEG2LevelH14: return "High1440"; case OMX_VIDEO_MPEG2LevelHL: return "High"; default: return def; } } inline static const char *asString(OMX_VIDEO_AVCPROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_AVCProfileBaseline: return "Baseline"; case OMX_VIDEO_AVCProfileMain: return "Main"; case OMX_VIDEO_AVCProfileExtended: return "Extended"; case OMX_VIDEO_AVCProfileHigh: return "High"; case OMX_VIDEO_AVCProfileHigh10: return "High10"; case OMX_VIDEO_AVCProfileHigh422: return "High422"; case OMX_VIDEO_AVCProfileHigh444: return "High444"; default: return def; } } inline static const char *asString(OMX_VIDEO_AVCLEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_AVCLevel1: return "Level1"; case OMX_VIDEO_AVCLevel1b: return "Level1b"; case OMX_VIDEO_AVCLevel11: return "Level11"; case OMX_VIDEO_AVCLevel12: return "Level12"; case OMX_VIDEO_AVCLevel13: return "Level13"; case OMX_VIDEO_AVCLevel2: return "Level2"; case OMX_VIDEO_AVCLevel21: return "Level21"; case OMX_VIDEO_AVCLevel22: return "Level22"; case OMX_VIDEO_AVCLevel3: return "Level3"; case OMX_VIDEO_AVCLevel31: return "Level31"; case OMX_VIDEO_AVCLevel32: return "Level32"; case OMX_VIDEO_AVCLevel4: return "Level4"; case OMX_VIDEO_AVCLevel41: return "Level41"; case OMX_VIDEO_AVCLevel42: return "Level42"; case OMX_VIDEO_AVCLevel5: return "Level5"; case OMX_VIDEO_AVCLevel51: return "Level51"; case OMX_VIDEO_AVCLevel52: return "Level52"; default: return def; } } inline static const char *asString(OMX_VIDEO_AVCLOOPFILTERTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_AVCLoopFilterEnable: return "Enable"; // case OMX_VIDEO_AVCLoopFilterDisable: return "Disable"; // case OMX_VIDEO_AVCLoopFilterDisableSliceBoundary: return "DisableSliceBoundary"; default: return def; } } #endif // AS_STRING_FOR_OMX_VIDEO_H #endif // OMX_Video_h #ifdef OMX_VideoExt_h /* asString definitions if media/openmax/OMX_VideoExt.h was included */ #ifndef AS_STRING_FOR_OMX_VIDEOEXT_H #define AS_STRING_FOR_OMX_VIDEOEXT_H inline static const char *asString(OMX_VIDEO_VP8PROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_VP8ProfileMain: return "Main"; case OMX_VIDEO_VP8ProfileUnknown: return "Unknown"; // unused default: return def; } } inline static const char *asString(OMX_VIDEO_VP8LEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_VP8Level_Version0: return "_Version0"; case OMX_VIDEO_VP8Level_Version1: return "_Version1"; case OMX_VIDEO_VP8Level_Version2: return "_Version2"; case OMX_VIDEO_VP8Level_Version3: return "_Version3"; case OMX_VIDEO_VP8LevelUnknown: return "Unknown"; // unused default: return def; } } inline static const char *asString(OMX_VIDEO_VP9PROFILETYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_VP9Profile0: return "Profile0"; case OMX_VIDEO_VP9Profile1: return "Profile1"; case OMX_VIDEO_VP9Profile2: return "Profile2"; case OMX_VIDEO_VP9Profile3: return "Profile3"; case OMX_VIDEO_VP9Profile2HDR: return "Profile2HDR"; case OMX_VIDEO_VP9Profile3HDR: return "Profile3HDR"; default: return def; } } inline static const char *asString(OMX_VIDEO_VP9LEVELTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_VP9Level1: return "Level1"; case OMX_VIDEO_VP9Level11: return "Level11"; case OMX_VIDEO_VP9Level2: return "Level2"; case OMX_VIDEO_VP9Level21: return "Level21"; case OMX_VIDEO_VP9Level3: return "Level3"; case OMX_VIDEO_VP9Level31: return "Level31"; case OMX_VIDEO_VP9Level4: return "Level4"; case OMX_VIDEO_VP9Level41: return "Level41"; case OMX_VIDEO_VP9Level5: return "Level5"; case OMX_VIDEO_VP9Level51: return "Level51"; case OMX_VIDEO_VP9Level52: return "Level52"; case OMX_VIDEO_VP9Level6: return "Level6"; case OMX_VIDEO_VP9Level61: return "Level61"; case OMX_VIDEO_VP9Level62: return "Level62"; default: return def; } } inline static const char *asString( OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE i, const char *def = "??") { switch (i) { case OMX_VIDEO_VPXTemporalLayerPatternNone: return "VPXTemporalLayerPatternNone"; case OMX_VIDEO_VPXTemporalLayerPatternWebRTC: return "VPXTemporalLayerPatternWebRTC"; default: return def; } } inline static const char *asString(OMX_VIDEO_HEVCPROFILETYPE i, const char *def = "!!") { switch (i) { case OMX_VIDEO_HEVCProfileUnknown: return "Unknown"; // unused case OMX_VIDEO_HEVCProfileMain: return "Main"; case OMX_VIDEO_HEVCProfileMain10: return "Main10"; case OMX_VIDEO_HEVCProfileMain10HDR10: return "Main10HDR10"; default: return def; } } inline static const char *asString(OMX_VIDEO_HEVCLEVELTYPE i, const char *def = "!!") { switch (i) { case OMX_VIDEO_HEVCLevelUnknown: return "LevelUnknown"; // unused case OMX_VIDEO_HEVCMainTierLevel1: return "MainTierLevel1"; case OMX_VIDEO_HEVCHighTierLevel1: return "HighTierLevel1"; case OMX_VIDEO_HEVCMainTierLevel2: return "MainTierLevel2"; case OMX_VIDEO_HEVCHighTierLevel2: return "HighTierLevel2"; case OMX_VIDEO_HEVCMainTierLevel21: return "MainTierLevel21"; case OMX_VIDEO_HEVCHighTierLevel21: return "HighTierLevel21"; case OMX_VIDEO_HEVCMainTierLevel3: return "MainTierLevel3"; case OMX_VIDEO_HEVCHighTierLevel3: return "HighTierLevel3"; case OMX_VIDEO_HEVCMainTierLevel31: return "MainTierLevel31"; case OMX_VIDEO_HEVCHighTierLevel31: return "HighTierLevel31"; case OMX_VIDEO_HEVCMainTierLevel4: return "MainTierLevel4"; case OMX_VIDEO_HEVCHighTierLevel4: return "HighTierLevel4"; case OMX_VIDEO_HEVCMainTierLevel41: return "MainTierLevel41"; case OMX_VIDEO_HEVCHighTierLevel41: return "HighTierLevel41"; case OMX_VIDEO_HEVCMainTierLevel5: return "MainTierLevel5"; case OMX_VIDEO_HEVCHighTierLevel5: return "HighTierLevel5"; case OMX_VIDEO_HEVCMainTierLevel51: return "MainTierLevel51"; case OMX_VIDEO_HEVCHighTierLevel51: return "HighTierLevel51"; case OMX_VIDEO_HEVCMainTierLevel52: return "MainTierLevel52"; case OMX_VIDEO_HEVCHighTierLevel52: return "HighTierLevel52"; case OMX_VIDEO_HEVCMainTierLevel6: return "MainTierLevel6"; case OMX_VIDEO_HEVCHighTierLevel6: return "HighTierLevel6"; case OMX_VIDEO_HEVCMainTierLevel61: return "MainTierLevel61"; case OMX_VIDEO_HEVCHighTierLevel61: return "HighTierLevel61"; case OMX_VIDEO_HEVCMainTierLevel62: return "MainTierLevel62"; case OMX_VIDEO_HEVCHighTierLevel62: return "HighTierLevel62"; default: return def; } } #endif // AS_STRING_FOR_OMX_VIDEOEXT_H #endif // OMX_VideoExt_h #ifdef ANDROID } // namespace android #endif include/media/openmax/OMX_Audio.h0100644 0000000 0000000 00000231055 13077405420 015723 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** @file OMX_Audio.h - OpenMax IL version 1.1.2 * The structures needed by Audio components to exchange * parameters and configuration data with the componenmilts. */ #ifndef OMX_Audio_h #define OMX_Audio_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header must include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** @defgroup midi MIDI * @ingroup audio */ /** @defgroup effects Audio effects * @ingroup audio */ /** @defgroup audio OpenMAX IL Audio Domain * Structures for OpenMAX IL Audio domain * @{ */ /** Enumeration used to define the possible audio codings. * If "OMX_AUDIO_CodingUnused" is selected, the coding selection must * be done in a vendor specific way. Since this is for an audio * processing element this enum is relevant. However, for another * type of component other enums would be in this area. */ typedef enum OMX_AUDIO_CODINGTYPE { OMX_AUDIO_CodingUnused = 0, /**< Placeholder value when coding is N/A */ OMX_AUDIO_CodingAutoDetect, /**< auto detection of audio format */ OMX_AUDIO_CodingPCM, /**< Any variant of PCM coding */ OMX_AUDIO_CodingADPCM, /**< Any variant of ADPCM encoded data */ OMX_AUDIO_CodingAMR, /**< Any variant of AMR encoded data */ OMX_AUDIO_CodingGSMFR, /**< Any variant of GSM fullrate (i.e. GSM610) */ OMX_AUDIO_CodingGSMEFR, /**< Any variant of GSM Enhanced Fullrate encoded data*/ OMX_AUDIO_CodingGSMHR, /**< Any variant of GSM Halfrate encoded data */ OMX_AUDIO_CodingPDCFR, /**< Any variant of PDC Fullrate encoded data */ OMX_AUDIO_CodingPDCEFR, /**< Any variant of PDC Enhanced Fullrate encoded data */ OMX_AUDIO_CodingPDCHR, /**< Any variant of PDC Halfrate encoded data */ OMX_AUDIO_CodingTDMAFR, /**< Any variant of TDMA Fullrate encoded data (TIA/EIA-136-420) */ OMX_AUDIO_CodingTDMAEFR, /**< Any variant of TDMA Enhanced Fullrate encoded data (TIA/EIA-136-410) */ OMX_AUDIO_CodingQCELP8, /**< Any variant of QCELP 8kbps encoded data */ OMX_AUDIO_CodingQCELP13, /**< Any variant of QCELP 13kbps encoded data */ OMX_AUDIO_CodingEVRC, /**< Any variant of EVRC encoded data */ OMX_AUDIO_CodingSMV, /**< Any variant of SMV encoded data */ OMX_AUDIO_CodingG711, /**< Any variant of G.711 encoded data */ OMX_AUDIO_CodingG723, /**< Any variant of G.723 dot 1 encoded data */ OMX_AUDIO_CodingG726, /**< Any variant of G.726 encoded data */ OMX_AUDIO_CodingG729, /**< Any variant of G.729 encoded data */ OMX_AUDIO_CodingAAC, /**< Any variant of AAC encoded data */ OMX_AUDIO_CodingMP3, /**< Any variant of MP3 encoded data */ OMX_AUDIO_CodingSBC, /**< Any variant of SBC encoded data */ OMX_AUDIO_CodingVORBIS, /**< Any variant of VORBIS encoded data */ OMX_AUDIO_CodingWMA, /**< Any variant of WMA encoded data */ OMX_AUDIO_CodingRA, /**< Any variant of RA encoded data */ OMX_AUDIO_CodingMIDI, /**< Any variant of MIDI encoded data */ OMX_AUDIO_CodingFLAC, /**< Any variant of FLAC encoded data */ OMX_AUDIO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_CodingMax = 0x7FFFFFFF } OMX_AUDIO_CODINGTYPE; /** The PortDefinition structure is used to define all of the parameters * necessary for the compliant component to setup an input or an output audio * path. If additional information is needed to define the parameters of the * port (such as frequency), additional structures must be sent such as the * OMX_AUDIO_PARAM_PCMMODETYPE structure to supply the extra parameters for the port. */ typedef struct OMX_AUDIO_PORTDEFINITIONTYPE { OMX_STRING cMIMEType; /**< MIME type of data for the port */ OMX_NATIVE_DEVICETYPE pNativeRender; /** < platform specific reference for an output device, otherwise this field is 0 */ OMX_BOOL bFlagErrorConcealment; /**< Turns on error concealment if it is supported by the OMX component */ OMX_AUDIO_CODINGTYPE eEncoding; /**< Type of data expected for this port (e.g. PCM, AMR, MP3, etc) */ } OMX_AUDIO_PORTDEFINITIONTYPE; /** Port format parameter. This structure is used to enumerate * the various data input/output format supported by the port. */ typedef struct OMX_AUDIO_PARAM_PORTFORMATTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Indicates which port to set */ OMX_U32 nIndex; /**< Indicates the enumeration index for the format from 0x0 to N-1 */ OMX_AUDIO_CODINGTYPE eEncoding; /**< Type of data expected for this port (e.g. PCM, AMR, MP3, etc) */ } OMX_AUDIO_PARAM_PORTFORMATTYPE; /** PCM mode type */ typedef enum OMX_AUDIO_PCMMODETYPE { OMX_AUDIO_PCMModeLinear = 0, /**< Linear PCM encoded data */ OMX_AUDIO_PCMModeALaw, /**< A law PCM encoded data (G.711) */ OMX_AUDIO_PCMModeMULaw, /**< Mu law PCM encoded data (G.711) */ OMX_AUDIO_PCMModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_PCMModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_PCMModeMax = 0x7FFFFFFF } OMX_AUDIO_PCMMODETYPE; typedef enum OMX_AUDIO_CHANNELTYPE { OMX_AUDIO_ChannelNone = 0x0, /**< Unused or empty */ OMX_AUDIO_ChannelLF = 0x1, /**< Left front */ OMX_AUDIO_ChannelRF = 0x2, /**< Right front */ OMX_AUDIO_ChannelCF = 0x3, /**< Center front */ OMX_AUDIO_ChannelLS = 0x4, /**< Left surround */ OMX_AUDIO_ChannelRS = 0x5, /**< Right surround */ OMX_AUDIO_ChannelLFE = 0x6, /**< Low frequency effects */ OMX_AUDIO_ChannelCS = 0x7, /**< Back surround */ OMX_AUDIO_ChannelLR = 0x8, /**< Left rear. */ OMX_AUDIO_ChannelRR = 0x9, /**< Right rear. */ OMX_AUDIO_ChannelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_ChannelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_ChannelMax = 0x7FFFFFFF } OMX_AUDIO_CHANNELTYPE; #define OMX_AUDIO_MAXCHANNELS 16 /**< maximum number distinct audio channels that a buffer may contain */ #define OMX_MIN_PCMPAYLOAD_MSEC 5 /**< Minimum audio buffer payload size for uncompressed (PCM) audio */ /** PCM format description */ typedef struct OMX_AUDIO_PARAM_PCMMODETYPE { OMX_U32 nSize; /**< Size of this structure, in Bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels (e.g. 2 for stereo) */ OMX_NUMERICALDATATYPE eNumData; /**< indicates PCM data as signed, unsigned or floating pt. */ OMX_ENDIANTYPE eEndian; /**< indicates PCM data as little or big endian */ OMX_BOOL bInterleaved; /**< True for normal interleaved data; false for non-interleaved data (e.g. block data) */ OMX_U32 nBitPerSample; /**< Bit per sample */ OMX_U32 nSamplingRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_AUDIO_PCMMODETYPE ePCMMode; /**< PCM mode enumeration */ OMX_AUDIO_CHANNELTYPE eChannelMapping[OMX_AUDIO_MAXCHANNELS]; /**< Slot i contains channel defined by eChannelMap[i] */ } OMX_AUDIO_PARAM_PCMMODETYPE; /** Audio channel mode. This is used by both AAC and MP3, although the names are more appropriate * for the MP3. For example, JointStereo for MP3 is CouplingChannels for AAC. */ typedef enum OMX_AUDIO_CHANNELMODETYPE { OMX_AUDIO_ChannelModeStereo = 0, /**< 2 channels, the bitrate allocation between those two channels changes accordingly to each channel information */ OMX_AUDIO_ChannelModeJointStereo, /**< mode that takes advantage of what is common between 2 channels for higher compression gain */ OMX_AUDIO_ChannelModeDual, /**< 2 mono-channels, each channel is encoded with half the bitrate of the overall bitrate */ OMX_AUDIO_ChannelModeMono, /**< Mono channel mode */ OMX_AUDIO_ChannelModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_ChannelModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_ChannelModeMax = 0x7FFFFFFF } OMX_AUDIO_CHANNELMODETYPE; typedef enum OMX_AUDIO_MP3STREAMFORMATTYPE { OMX_AUDIO_MP3StreamFormatMP1Layer3 = 0, /**< MP3 Audio MPEG 1 Layer 3 Stream format */ OMX_AUDIO_MP3StreamFormatMP2Layer3, /**< MP3 Audio MPEG 2 Layer 3 Stream format */ OMX_AUDIO_MP3StreamFormatMP2_5Layer3, /**< MP3 Audio MPEG2.5 Layer 3 Stream format */ OMX_AUDIO_MP3StreamFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_MP3StreamFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_MP3StreamFormatMax = 0x7FFFFFFF } OMX_AUDIO_MP3STREAMFORMATTYPE; /** MP3 params */ typedef struct OMX_AUDIO_PARAM_MP3TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate of the input data. Use 0 for variable rate or unknown bit rates */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_U32 nAudioBandWidth; /**< Audio band width (in Hz) to which an encoder should limit the audio signal. Use 0 to let encoder decide */ OMX_AUDIO_CHANNELMODETYPE eChannelMode; /**< Channel mode enumeration */ OMX_AUDIO_MP3STREAMFORMATTYPE eFormat; /**< MP3 stream format */ } OMX_AUDIO_PARAM_MP3TYPE; typedef enum OMX_AUDIO_AACSTREAMFORMATTYPE { OMX_AUDIO_AACStreamFormatMP2ADTS = 0, /**< AAC Audio Data Transport Stream 2 format */ OMX_AUDIO_AACStreamFormatMP4ADTS, /**< AAC Audio Data Transport Stream 4 format */ OMX_AUDIO_AACStreamFormatMP4LOAS, /**< AAC Low Overhead Audio Stream format */ OMX_AUDIO_AACStreamFormatMP4LATM, /**< AAC Low overhead Audio Transport Multiplex */ OMX_AUDIO_AACStreamFormatADIF, /**< AAC Audio Data Interchange Format */ OMX_AUDIO_AACStreamFormatMP4FF, /**< AAC inside MPEG-4/ISO File Format */ OMX_AUDIO_AACStreamFormatRAW, /**< AAC Raw Format */ OMX_AUDIO_AACStreamFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AACStreamFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AACStreamFormatMax = 0x7FFFFFFF } OMX_AUDIO_AACSTREAMFORMATTYPE; /** AAC mode type. Note that the term profile is used with the MPEG-2 * standard and the term object type and profile is used with MPEG-4 */ typedef enum OMX_AUDIO_AACPROFILETYPE{ OMX_AUDIO_AACObjectNull = 0, /**< Null, not used */ OMX_AUDIO_AACObjectMain = 1, /**< AAC Main object */ OMX_AUDIO_AACObjectLC, /**< AAC Low Complexity object (AAC profile) */ OMX_AUDIO_AACObjectSSR, /**< AAC Scalable Sample Rate object */ OMX_AUDIO_AACObjectLTP, /**< AAC Long Term Prediction object */ OMX_AUDIO_AACObjectHE, /**< AAC High Efficiency (object type SBR, HE-AAC profile) */ OMX_AUDIO_AACObjectScalable, /**< AAC Scalable object */ OMX_AUDIO_AACObjectERLC = 17, /**< ER AAC Low Complexity object (Error Resilient AAC-LC) */ OMX_AUDIO_AACObjectLD = 23, /**< AAC Low Delay object (Error Resilient) */ OMX_AUDIO_AACObjectHE_PS = 29, /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */ OMX_AUDIO_AACObjectELD = 39, /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/ OMX_AUDIO_AACObjectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AACObjectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AACObjectMax = 0x7FFFFFFF } OMX_AUDIO_AACPROFILETYPE; /** AAC tool usage (for nAACtools in OMX_AUDIO_PARAM_AACPROFILETYPE). * Required for encoder configuration and optional as decoder info output. * For MP3, OMX_AUDIO_CHANNELMODETYPE is sufficient. */ #define OMX_AUDIO_AACToolNone 0x00000000 /**< no AAC tools allowed (encoder config) or active (decoder info output) */ #define OMX_AUDIO_AACToolMS 0x00000001 /**< MS: Mid/side joint coding tool allowed or active */ #define OMX_AUDIO_AACToolIS 0x00000002 /**< IS: Intensity stereo tool allowed or active */ #define OMX_AUDIO_AACToolTNS 0x00000004 /**< TNS: Temporal Noise Shaping tool allowed or active */ #define OMX_AUDIO_AACToolPNS 0x00000008 /**< PNS: MPEG-4 Perceptual Noise substitution tool allowed or active */ #define OMX_AUDIO_AACToolLTP 0x00000010 /**< LTP: MPEG-4 Long Term Prediction tool allowed or active */ #define OMX_AUDIO_AACToolVendor 0x00010000 /**< NOT A KHRONOS VALUE, offset for vendor-specific additions */ #define OMX_AUDIO_AACToolAll 0x7FFFFFFF /**< all AAC tools allowed or active (*/ /** MPEG-4 AAC error resilience (ER) tool usage (for nAACERtools in OMX_AUDIO_PARAM_AACPROFILETYPE). * Required for ER encoder configuration and optional as decoder info output */ #define OMX_AUDIO_AACERNone 0x00000000 /**< no AAC ER tools allowed/used */ #define OMX_AUDIO_AACERVCB11 0x00000001 /**< VCB11: Virtual Code Books for AAC section data */ #define OMX_AUDIO_AACERRVLC 0x00000002 /**< RVLC: Reversible Variable Length Coding */ #define OMX_AUDIO_AACERHCR 0x00000004 /**< HCR: Huffman Codeword Reordering */ #define OMX_AUDIO_AACERAll 0x7FFFFFFF /**< all AAC ER tools allowed/used */ /** AAC params */ typedef struct OMX_AUDIO_PARAM_AACPROFILETYPE { OMX_U32 nSize; /**< Size of this structure, in Bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_U32 nBitRate; /**< Bit rate of the input data. Use 0 for variable rate or unknown bit rates */ OMX_U32 nAudioBandWidth; /**< Audio band width (in Hz) to which an encoder should limit the audio signal. Use 0 to let encoder decide */ OMX_U32 nFrameLength; /**< Frame length (in audio samples per channel) of the codec. Can be 1024 or 960 (AAC-LC), 2048 (HE-AAC), 480 or 512 (AAC-LD). Use 0 to let encoder decide */ OMX_U32 nAACtools; /**< AAC tool usage */ OMX_U32 nAACERtools; /**< MPEG-4 AAC error resilience tool usage */ OMX_AUDIO_AACPROFILETYPE eAACProfile; /**< AAC profile enumeration */ OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat; /**< AAC stream format enumeration */ OMX_AUDIO_CHANNELMODETYPE eChannelMode; /**< Channel mode enumeration */ } OMX_AUDIO_PARAM_AACPROFILETYPE; /** VORBIS params */ typedef struct OMX_AUDIO_PARAM_VORBISTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate of the encoded data data. Use 0 for variable rate or unknown bit rates. Encoding is set to the bitrate closest to specified value (in bps) */ OMX_U32 nMinBitRate; /**< Sets minimum bitrate (in bps). */ OMX_U32 nMaxBitRate; /**< Sets maximum bitrate (in bps). */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_U32 nAudioBandWidth; /**< Audio band width (in Hz) to which an encoder should limit the audio signal. Use 0 to let encoder decide */ OMX_S32 nQuality; /**< Sets encoding quality to n, between -1 (low) and 10 (high). In the default mode of operation, teh quality level is 3. Normal quality range is 0 - 10. */ OMX_BOOL bManaged; /**< Set bitrate management mode. This turns off the normal VBR encoding, but allows hard or soft bitrate constraints to be enforced by the encoder. This mode can be slower, and may also be lower quality. It is primarily useful for streaming. */ OMX_BOOL bDownmix; /**< Downmix input from stereo to mono (has no effect on non-stereo streams). Useful for lower-bitrate encoding. */ } OMX_AUDIO_PARAM_VORBISTYPE; /** FLAC params */ typedef struct OMX_AUDIO_PARAM_FLACTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for unknown sampling rate. */ OMX_U32 nCompressionLevel;/**< FLAC compression level, from 0 (fastest compression) to 8 (highest compression */ } OMX_AUDIO_PARAM_FLACTYPE; /** WMA Version */ typedef enum OMX_AUDIO_WMAFORMATTYPE { OMX_AUDIO_WMAFormatUnused = 0, /**< format unused or unknown */ OMX_AUDIO_WMAFormat7, /**< Windows Media Audio format 7 */ OMX_AUDIO_WMAFormat8, /**< Windows Media Audio format 8 */ OMX_AUDIO_WMAFormat9, /**< Windows Media Audio format 9 */ OMX_AUDIO_WMAFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_WMAFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_WMAFormatMax = 0x7FFFFFFF } OMX_AUDIO_WMAFORMATTYPE; /** WMA Profile */ typedef enum OMX_AUDIO_WMAPROFILETYPE { OMX_AUDIO_WMAProfileUnused = 0, /**< profile unused or unknown */ OMX_AUDIO_WMAProfileL1, /**< Windows Media audio version 9 profile L1 */ OMX_AUDIO_WMAProfileL2, /**< Windows Media audio version 9 profile L2 */ OMX_AUDIO_WMAProfileL3, /**< Windows Media audio version 9 profile L3 */ OMX_AUDIO_WMAProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_WMAProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_WMAProfileMax = 0x7FFFFFFF } OMX_AUDIO_WMAPROFILETYPE; /** WMA params */ typedef struct OMX_AUDIO_PARAM_WMATYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U16 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate of the input data. Use 0 for variable rate or unknown bit rates */ OMX_AUDIO_WMAFORMATTYPE eFormat; /**< Version of WMA stream / data */ OMX_AUDIO_WMAPROFILETYPE eProfile; /**< Profile of WMA stream / data */ OMX_U32 nSamplingRate; /**< Sampling rate of the source data */ OMX_U16 nBlockAlign; /**< is the block alignment, or block size, in bytes of the audio codec */ OMX_U16 nEncodeOptions; /**< WMA Type-specific data */ OMX_U32 nSuperBlockAlign; /**< WMA Type-specific data */ } OMX_AUDIO_PARAM_WMATYPE; /** * RealAudio format */ typedef enum OMX_AUDIO_RAFORMATTYPE { OMX_AUDIO_RAFormatUnused = 0, /**< Format unused or unknown */ OMX_AUDIO_RA8, /**< RealAudio 8 codec */ OMX_AUDIO_RA9, /**< RealAudio 9 codec */ OMX_AUDIO_RA10_AAC, /**< MPEG-4 AAC codec for bitrates of more than 128kbps */ OMX_AUDIO_RA10_CODEC, /**< RealAudio codec for bitrates less than 128 kbps */ OMX_AUDIO_RA10_LOSSLESS, /**< RealAudio Lossless */ OMX_AUDIO_RA10_MULTICHANNEL, /**< RealAudio Multichannel */ OMX_AUDIO_RA10_VOICE, /**< RealAudio Voice for bitrates below 15 kbps */ OMX_AUDIO_RAFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_RAFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_RAFormatMax = 0x7FFFFFFF } OMX_AUDIO_RAFORMATTYPE; /** RA (Real Audio) params */ typedef struct OMX_AUDIO_PARAM_RATYPE { OMX_U32 nSize; /**< Size of this structure, in Bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nSamplingRate; /**< is the sampling rate of the source data */ OMX_U32 nBitsPerFrame; /**< is the value for bits per frame */ OMX_U32 nSamplePerFrame; /**< is the value for samples per frame */ OMX_U32 nCouplingQuantBits; /**< is the number of coupling quantization bits in the stream */ OMX_U32 nCouplingStartRegion; /**< is the coupling start region in the stream */ OMX_U32 nNumRegions; /**< is the number of regions value */ OMX_AUDIO_RAFORMATTYPE eFormat; /**< is the RealAudio audio format */ } OMX_AUDIO_PARAM_RATYPE; /** SBC Allocation Method Type */ typedef enum OMX_AUDIO_SBCALLOCMETHODTYPE { OMX_AUDIO_SBCAllocMethodLoudness, /**< Loudness allocation method */ OMX_AUDIO_SBCAllocMethodSNR, /**< SNR allocation method */ OMX_AUDIO_SBCAllocMethodKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_SBCAllocMethodVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_SBCAllocMethodMax = 0x7FFFFFFF } OMX_AUDIO_SBCALLOCMETHODTYPE; /** SBC params */ typedef struct OMX_AUDIO_PARAM_SBCTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate of the input data. Use 0 for variable rate or unknown bit rates */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_U32 nBlocks; /**< Number of blocks */ OMX_U32 nSubbands; /**< Number of subbands */ OMX_U32 nBitPool; /**< Bitpool value */ OMX_BOOL bEnableBitrate; /**< Use bitrate value instead of bitpool */ OMX_AUDIO_CHANNELMODETYPE eChannelMode; /**< Channel mode enumeration */ OMX_AUDIO_SBCALLOCMETHODTYPE eSBCAllocType; /**< SBC Allocation method type */ } OMX_AUDIO_PARAM_SBCTYPE; /** ADPCM stream format parameters */ typedef struct OMX_AUDIO_PARAM_ADPCMTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_U32 nBitsPerSample; /**< Number of bits in each sample */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ } OMX_AUDIO_PARAM_ADPCMTYPE; /** G723 rate */ typedef enum OMX_AUDIO_G723RATE { OMX_AUDIO_G723ModeUnused = 0, /**< AMRNB Mode unused / unknown */ OMX_AUDIO_G723ModeLow, /**< 5300 bps */ OMX_AUDIO_G723ModeHigh, /**< 6300 bps */ OMX_AUDIO_G723ModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_G723ModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_G723ModeMax = 0x7FFFFFFF } OMX_AUDIO_G723RATE; /** G723 - Sample rate must be 8 KHz */ typedef struct OMX_AUDIO_PARAM_G723TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_AUDIO_G723RATE eBitRate; /**< todo: Should this be moved to a config? */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ OMX_BOOL bPostFilter; /**< Enable Post Filter */ } OMX_AUDIO_PARAM_G723TYPE; /** ITU G726 (ADPCM) rate */ typedef enum OMX_AUDIO_G726MODE { OMX_AUDIO_G726ModeUnused = 0, /**< G726 Mode unused / unknown */ OMX_AUDIO_G726Mode16, /**< 16 kbps */ OMX_AUDIO_G726Mode24, /**< 24 kbps */ OMX_AUDIO_G726Mode32, /**< 32 kbps, most common rate, also G721 */ OMX_AUDIO_G726Mode40, /**< 40 kbps */ OMX_AUDIO_G726ModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_G726ModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_G726ModeMax = 0x7FFFFFFF } OMX_AUDIO_G726MODE; /** G.726 stream format parameters - must be at 8KHz */ typedef struct OMX_AUDIO_PARAM_G726TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_AUDIO_G726MODE eG726Mode; } OMX_AUDIO_PARAM_G726TYPE; /** G729 coder type */ typedef enum OMX_AUDIO_G729TYPE { OMX_AUDIO_G729 = 0, /**< ITU G.729 encoded data */ OMX_AUDIO_G729A, /**< ITU G.729 annex A encoded data */ OMX_AUDIO_G729B, /**< ITU G.729 with annex B encoded data */ OMX_AUDIO_G729AB, /**< ITU G.729 annexes A and B encoded data */ OMX_AUDIO_G729KhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_G729VendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_G729Max = 0x7FFFFFFF } OMX_AUDIO_G729TYPE; /** G729 stream format parameters - fixed 6KHz sample rate */ typedef struct OMX_AUDIO_PARAM_G729TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_AUDIO_G729TYPE eBitType; } OMX_AUDIO_PARAM_G729TYPE; /** AMR Frame format */ typedef enum OMX_AUDIO_AMRFRAMEFORMATTYPE { OMX_AUDIO_AMRFrameFormatConformance = 0, /**< Frame Format is AMR Conformance (Standard) Format */ OMX_AUDIO_AMRFrameFormatIF1, /**< Frame Format is AMR Interface Format 1 */ OMX_AUDIO_AMRFrameFormatIF2, /**< Frame Format is AMR Interface Format 2*/ OMX_AUDIO_AMRFrameFormatFSF, /**< Frame Format is AMR File Storage Format */ OMX_AUDIO_AMRFrameFormatRTPPayload, /**< Frame Format is AMR Real-Time Transport Protocol Payload Format */ OMX_AUDIO_AMRFrameFormatITU, /**< Frame Format is ITU Format (added at Motorola request) */ OMX_AUDIO_AMRFrameFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AMRFrameFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AMRFrameFormatMax = 0x7FFFFFFF } OMX_AUDIO_AMRFRAMEFORMATTYPE; /** AMR band mode */ typedef enum OMX_AUDIO_AMRBANDMODETYPE { OMX_AUDIO_AMRBandModeUnused = 0, /**< AMRNB Mode unused / unknown */ OMX_AUDIO_AMRBandModeNB0, /**< AMRNB Mode 0 = 4750 bps */ OMX_AUDIO_AMRBandModeNB1, /**< AMRNB Mode 1 = 5150 bps */ OMX_AUDIO_AMRBandModeNB2, /**< AMRNB Mode 2 = 5900 bps */ OMX_AUDIO_AMRBandModeNB3, /**< AMRNB Mode 3 = 6700 bps */ OMX_AUDIO_AMRBandModeNB4, /**< AMRNB Mode 4 = 7400 bps */ OMX_AUDIO_AMRBandModeNB5, /**< AMRNB Mode 5 = 7950 bps */ OMX_AUDIO_AMRBandModeNB6, /**< AMRNB Mode 6 = 10200 bps */ OMX_AUDIO_AMRBandModeNB7, /**< AMRNB Mode 7 = 12200 bps */ OMX_AUDIO_AMRBandModeWB0, /**< AMRWB Mode 0 = 6600 bps */ OMX_AUDIO_AMRBandModeWB1, /**< AMRWB Mode 1 = 8850 bps */ OMX_AUDIO_AMRBandModeWB2, /**< AMRWB Mode 2 = 12650 bps */ OMX_AUDIO_AMRBandModeWB3, /**< AMRWB Mode 3 = 14250 bps */ OMX_AUDIO_AMRBandModeWB4, /**< AMRWB Mode 4 = 15850 bps */ OMX_AUDIO_AMRBandModeWB5, /**< AMRWB Mode 5 = 18250 bps */ OMX_AUDIO_AMRBandModeWB6, /**< AMRWB Mode 6 = 19850 bps */ OMX_AUDIO_AMRBandModeWB7, /**< AMRWB Mode 7 = 23050 bps */ OMX_AUDIO_AMRBandModeWB8, /**< AMRWB Mode 8 = 23850 bps */ OMX_AUDIO_AMRBandModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AMRBandModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AMRBandModeMax = 0x7FFFFFFF } OMX_AUDIO_AMRBANDMODETYPE; /** AMR Discontinuous Transmission mode */ typedef enum OMX_AUDIO_AMRDTXMODETYPE { OMX_AUDIO_AMRDTXModeOff = 0, /**< AMR Discontinuous Transmission Mode is disabled */ OMX_AUDIO_AMRDTXModeOnVAD1, /**< AMR Discontinuous Transmission Mode using Voice Activity Detector 1 (VAD1) is enabled */ OMX_AUDIO_AMRDTXModeOnVAD2, /**< AMR Discontinuous Transmission Mode using Voice Activity Detector 2 (VAD2) is enabled */ OMX_AUDIO_AMRDTXModeOnAuto, /**< The codec will automatically select between Off, VAD1 or VAD2 modes */ OMX_AUDIO_AMRDTXasEFR, /**< DTX as EFR instead of AMR standard (3GPP 26.101, frame type =8,9,10) */ OMX_AUDIO_AMRDTXModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AMRDTXModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AMRDTXModeMax = 0x7FFFFFFF } OMX_AUDIO_AMRDTXMODETYPE; /** AMR params */ typedef struct OMX_AUDIO_PARAM_AMRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate read only field */ OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode; /**< AMR Band Mode enumeration */ OMX_AUDIO_AMRDTXMODETYPE eAMRDTXMode; /**< AMR DTX Mode enumeration */ OMX_AUDIO_AMRFRAMEFORMATTYPE eAMRFrameFormat; /**< AMR frame format enumeration */ } OMX_AUDIO_PARAM_AMRTYPE; /** GSM_FR (ETSI 06.10, 3GPP 46.010) stream format parameters */ typedef struct OMX_AUDIO_PARAM_GSMFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_GSMFRTYPE; /** GSM-HR (ETSI 06.20, 3GPP 46.020) stream format parameters */ typedef struct OMX_AUDIO_PARAM_GSMHRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_GSMHRTYPE; /** GSM-EFR (ETSI 06.60, 3GPP 46.060) stream format parameters */ typedef struct OMX_AUDIO_PARAM_GSMEFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_GSMEFRTYPE; /** TDMA FR (TIA/EIA-136-420, VSELP 7.95kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_TDMAFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_TDMAFRTYPE; /** TDMA EFR (TIA/EIA-136-410, ACELP 7.4kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_TDMAEFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_TDMAEFRTYPE; /** PDC FR ( RCR-27, VSELP 6.7kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_PDCFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_PDCFRTYPE; /** PDC EFR ( RCR-27, ACELP 6.7kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_PDCEFRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_PDCEFRTYPE; /** PDC HR ( RCR-27, PSI-CELP 3.45kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_PDCHRTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_BOOL bDTX; /**< Enable Discontinuous Transmisssion */ OMX_BOOL bHiPassFilter; /**< Enable High Pass Filter */ } OMX_AUDIO_PARAM_PDCHRTYPE; /** CDMA Rate types */ typedef enum OMX_AUDIO_CDMARATETYPE { OMX_AUDIO_CDMARateBlank = 0, /**< CDMA encoded frame is blank */ OMX_AUDIO_CDMARateFull, /**< CDMA encoded frame in full rate */ OMX_AUDIO_CDMARateHalf, /**< CDMA encoded frame in half rate */ OMX_AUDIO_CDMARateQuarter, /**< CDMA encoded frame in quarter rate */ OMX_AUDIO_CDMARateEighth, /**< CDMA encoded frame in eighth rate (DTX)*/ OMX_AUDIO_CDMARateErasure, /**< CDMA erasure frame */ OMX_AUDIO_CDMARateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_CDMARateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_CDMARateMax = 0x7FFFFFFF } OMX_AUDIO_CDMARATETYPE; /** QCELP8 (TIA/EIA-96, up to 8kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_QCELP8TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_U32 nBitRate; /**< Bit rate of the input data. Use 0 for variable rate or unknown bit rates */ OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */ OMX_U32 nMinBitRate; /**< minmal rate for the encoder = 1,2,3,4, default = 1 */ OMX_U32 nMaxBitRate; /**< maximal rate for the encoder = 1,2,3,4, default = 4 */ } OMX_AUDIO_PARAM_QCELP8TYPE; /** QCELP13 ( CDMA, EIA/TIA-733, 13.3kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_QCELP13TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */ OMX_U32 nMinBitRate; /**< minmal rate for the encoder = 1,2,3,4, default = 1 */ OMX_U32 nMaxBitRate; /**< maximal rate for the encoder = 1,2,3,4, default = 4 */ } OMX_AUDIO_PARAM_QCELP13TYPE; /** EVRC ( CDMA, EIA/TIA-127, RCELP up to 8.55kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_EVRCTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_AUDIO_CDMARATETYPE eCDMARate; /**< actual Frame rate */ OMX_BOOL bRATE_REDUCon; /**< RATE_REDUCtion is requested for this frame */ OMX_U32 nMinBitRate; /**< minmal rate for the encoder = 1,2,3,4, default = 1 */ OMX_U32 nMaxBitRate; /**< maximal rate for the encoder = 1,2,3,4, default = 4 */ OMX_BOOL bHiPassFilter; /**< Enable encoder's High Pass Filter */ OMX_BOOL bNoiseSuppressor; /**< Enable encoder's noise suppressor pre-processing */ OMX_BOOL bPostFilter; /**< Enable decoder's post Filter */ } OMX_AUDIO_PARAM_EVRCTYPE; /** SMV ( up to 8.55kbps coder) stream format parameters */ typedef struct OMX_AUDIO_PARAM_SMVTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels in the data stream (not necessarily the same as the number of channels to be rendered. */ OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */ OMX_BOOL bRATE_REDUCon; /**< RATE_REDUCtion is requested for this frame */ OMX_U32 nMinBitRate; /**< minmal rate for the encoder = 1,2,3,4, default = 1 ??*/ OMX_U32 nMaxBitRate; /**< maximal rate for the encoder = 1,2,3,4, default = 4 ??*/ OMX_BOOL bHiPassFilter; /**< Enable encoder's High Pass Filter ??*/ OMX_BOOL bNoiseSuppressor; /**< Enable encoder's noise suppressor pre-processing */ OMX_BOOL bPostFilter; /**< Enable decoder's post Filter ??*/ } OMX_AUDIO_PARAM_SMVTYPE; /** MIDI Format * @ingroup midi */ typedef enum OMX_AUDIO_MIDIFORMATTYPE { OMX_AUDIO_MIDIFormatUnknown = 0, /**< MIDI Format unknown or don't care */ OMX_AUDIO_MIDIFormatSMF0, /**< Standard MIDI File Type 0 */ OMX_AUDIO_MIDIFormatSMF1, /**< Standard MIDI File Type 1 */ OMX_AUDIO_MIDIFormatSMF2, /**< Standard MIDI File Type 2 */ OMX_AUDIO_MIDIFormatSPMIDI, /**< SP-MIDI */ OMX_AUDIO_MIDIFormatXMF0, /**< eXtensible Music Format type 0 */ OMX_AUDIO_MIDIFormatXMF1, /**< eXtensible Music Format type 1 */ OMX_AUDIO_MIDIFormatMobileXMF, /**< Mobile XMF (eXtensible Music Format type 2) */ OMX_AUDIO_MIDIFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_MIDIFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_MIDIFormatMax = 0x7FFFFFFF } OMX_AUDIO_MIDIFORMATTYPE; /** MIDI params * @ingroup midi */ typedef struct OMX_AUDIO_PARAM_MIDITYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nFileSize; /**< size of the MIDI file in bytes, where the entire MIDI file passed in, otherwise if 0x0, the MIDI data is merged and streamed (instead of passed as an entire MIDI file) */ OMX_BU32 sMaxPolyphony; /**< Specifies the maximum simultaneous polyphonic voices. A value of zero indicates that the default polyphony of the device is used */ OMX_BOOL bLoadDefaultSound; /**< Whether to load default sound bank at initialization */ OMX_AUDIO_MIDIFORMATTYPE eMidiFormat; /**< Version of the MIDI file */ } OMX_AUDIO_PARAM_MIDITYPE; /** Type of the MIDI sound bank * @ingroup midi */ typedef enum OMX_AUDIO_MIDISOUNDBANKTYPE { OMX_AUDIO_MIDISoundBankUnused = 0, /**< unused/unknown soundbank type */ OMX_AUDIO_MIDISoundBankDLS1, /**< DLS version 1 */ OMX_AUDIO_MIDISoundBankDLS2, /**< DLS version 2 */ OMX_AUDIO_MIDISoundBankMobileDLSBase, /**< Mobile DLS, using the base functionality */ OMX_AUDIO_MIDISoundBankMobileDLSPlusOptions, /**< Mobile DLS, using the specification-defined optional feature set */ OMX_AUDIO_MIDISoundBankKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_MIDISoundBankVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_MIDISoundBankMax = 0x7FFFFFFF } OMX_AUDIO_MIDISOUNDBANKTYPE; /** Bank Layout describes how bank MSB & LSB are used in the DLS instrument definitions sound bank * @ingroup midi */ typedef enum OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE { OMX_AUDIO_MIDISoundBankLayoutUnused = 0, /**< unused/unknown soundbank type */ OMX_AUDIO_MIDISoundBankLayoutGM, /**< GS layout (based on bank MSB 0x00) */ OMX_AUDIO_MIDISoundBankLayoutGM2, /**< General MIDI 2 layout (using MSB 0x78/0x79, LSB 0x00) */ OMX_AUDIO_MIDISoundBankLayoutUser, /**< Does not conform to any bank numbering standards */ OMX_AUDIO_MIDISoundBankLayoutKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_MIDISoundBankLayoutVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_MIDISoundBankLayoutMax = 0x7FFFFFFF } OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE; /** MIDI params to load/unload user soundbank * @ingroup midi */ typedef struct OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nDLSIndex; /**< DLS file index to be loaded */ OMX_U32 nDLSSize; /**< Size in bytes */ OMX_PTR pDLSData; /**< Pointer to DLS file data */ OMX_AUDIO_MIDISOUNDBANKTYPE eMidiSoundBank; /**< Midi sound bank type enumeration */ OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE eMidiSoundBankLayout; /**< Midi sound bank layout enumeration */ } OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE; /** Structure for Live MIDI events and MIP messages. * (MIP = Maximum Instantaneous Polyphony; part of the SP-MIDI standard.) * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_U32 nMidiEventSize; /**< Size of immediate MIDI events or MIP message in bytes */ OMX_U8 nMidiEvents[1]; /**< MIDI event array to be rendered immediately, or an array for the MIP message buffer, where the size is indicated by nMidiEventSize */ } OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE; /** MIDI sound bank/ program pair in a given channel * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port that this structure applies to */ OMX_U32 nChannel; /**< Valid channel values range from 1 to 16 */ OMX_U16 nIDProgram; /**< Valid program ID range is 1 to 128 */ OMX_U16 nIDSoundBank; /**< Sound bank ID */ OMX_U32 nUserSoundBankIndex;/**< User soundbank index, easier to access soundbanks by index if multiple banks are present */ } OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE; /** MIDI control * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDICONTROLTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BS32 sPitchTransposition; /**< Pitch transposition in semitones, stored as Q22.10 format based on JAVA MMAPI (JSR-135) requirement */ OMX_BU32 sPlayBackRate; /**< Relative playback rate, stored as Q14.17 fixed-point number based on JSR-135 requirement */ OMX_BU32 sTempo ; /**< Tempo in beats per minute (BPM), stored as Q22.10 fixed-point number based on JSR-135 requirement */ OMX_U32 nMaxPolyphony; /**< Specifies the maximum simultaneous polyphonic voices. A value of zero indicates that the default polyphony of the device is used */ OMX_U32 nNumRepeat; /**< Number of times to repeat playback */ OMX_U32 nStopTime; /**< Time in milliseconds to indicate when playback will stop automatically. Set to zero if not used */ OMX_U16 nChannelMuteMask; /**< 16 bit mask for channel mute status */ OMX_U16 nChannelSoloMask; /**< 16 bit mask for channel solo status */ OMX_U32 nTrack0031MuteMask; /**< 32 bit mask for track mute status. Note: This is for tracks 0-31 */ OMX_U32 nTrack3263MuteMask; /**< 32 bit mask for track mute status. Note: This is for tracks 32-63 */ OMX_U32 nTrack0031SoloMask; /**< 32 bit mask for track solo status. Note: This is for tracks 0-31 */ OMX_U32 nTrack3263SoloMask; /**< 32 bit mask for track solo status. Note: This is for tracks 32-63 */ } OMX_AUDIO_CONFIG_MIDICONTROLTYPE; /** MIDI Playback States * @ingroup midi */ typedef enum OMX_AUDIO_MIDIPLAYBACKSTATETYPE { OMX_AUDIO_MIDIPlayBackStateUnknown = 0, /**< Unknown state or state does not map to other defined states */ OMX_AUDIO_MIDIPlayBackStateClosedEngaged, /**< No MIDI resource is currently open. The MIDI engine is currently processing MIDI events. */ OMX_AUDIO_MIDIPlayBackStateParsing, /**< A MIDI resource is open and is being primed. The MIDI engine is currently processing MIDI events. */ OMX_AUDIO_MIDIPlayBackStateOpenEngaged, /**< A MIDI resource is open and primed but not playing. The MIDI engine is currently processing MIDI events. The transition to this state is only possible from the OMX_AUDIO_MIDIPlayBackStatePlaying state, when the 'playback head' reaches the end of media data or the playback stops due to stop time set.*/ OMX_AUDIO_MIDIPlayBackStatePlaying, /**< A MIDI resource is open and currently playing. The MIDI engine is currently processing MIDI events.*/ OMX_AUDIO_MIDIPlayBackStatePlayingPartially, /**< Best-effort playback due to SP-MIDI/DLS resource constraints */ OMX_AUDIO_MIDIPlayBackStatePlayingSilently, /**< Due to system resource constraints and SP-MIDI content constraints, there is no audible MIDI content during playback currently. The situation may change if resources are freed later.*/ OMX_AUDIO_MIDIPlayBackStateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_MIDIPlayBackStateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_MIDIPlayBackStateMax = 0x7FFFFFFF } OMX_AUDIO_MIDIPLAYBACKSTATETYPE; /** MIDI status * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDISTATUSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U16 nNumTracks; /**< Number of MIDI tracks in the file, read only field. NOTE: May not return a meaningful value until the entire file is parsed and buffered. */ OMX_U32 nDuration; /**< The length of the currently open MIDI resource in milliseconds. NOTE: May not return a meaningful value until the entire file is parsed and buffered. */ OMX_U32 nPosition; /**< Current Position of the MIDI resource being played in milliseconds */ OMX_BOOL bVibra; /**< Does Vibra track exist? NOTE: May not return a meaningful value until the entire file is parsed and buffered. */ OMX_U32 nNumMetaEvents; /**< Total number of MIDI Meta Events in the currently open MIDI resource. NOTE: May not return a meaningful value until the entire file is parsed and buffered. */ OMX_U32 nNumActiveVoices; /**< Number of active voices in the currently playing MIDI resource. NOTE: May not return a meaningful value until the entire file is parsed and buffered. */ OMX_AUDIO_MIDIPLAYBACKSTATETYPE eMIDIPlayBackState; /**< MIDI playback state enumeration, read only field */ } OMX_AUDIO_CONFIG_MIDISTATUSTYPE; /** MIDI Meta Event structure one per Meta Event. * MIDI Meta Events are like audio metadata, except that they are interspersed * with the MIDI content throughout the file and are not localized in the header. * As such, it is necessary to retrieve information about these Meta Events from * the engine, as it encounters these Meta Events within the MIDI content. * For example, SMF files can have up to 14 types of MIDI Meta Events (copyright, * author, default tempo, etc.) scattered throughout the file. * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE{ OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nIndex; /**< Index of Meta Event */ OMX_U8 nMetaEventType; /**< Meta Event Type, 7bits (i.e. 0 - 127) */ OMX_U32 nMetaEventSize; /**< size of the Meta Event in bytes */ OMX_U32 nTrack; /**< track number for the meta event */ OMX_U32 nPosition; /**< Position of the meta-event in milliseconds */ } OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE; /** MIDI Meta Event Data structure - one per Meta Event. * @ingroup midi */ typedef struct OMX_AUDIO_CONFIG_MIDIMETAEVENTDATATYPE{ OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nIndex; /**< Index of Meta Event */ OMX_U32 nMetaEventSize; /**< size of the Meta Event in bytes */ OMX_U8 nData[1]; /**< array of one or more bytes of meta data as indicated by the nMetaEventSize field */ } OMX_AUDIO_CONFIG__MIDIMETAEVENTDATATYPE; /** Audio Volume adjustment for a port */ typedef struct OMX_AUDIO_CONFIG_VOLUMETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port index indicating which port to set. Select the input port to set just that port's volume. Select the output port to adjust the master volume. */ OMX_BOOL bLinear; /**< Is the volume to be set in linear (0.100) or logarithmic scale (mB) */ OMX_BS32 sVolume; /**< Volume linear setting in the 0..100 range, OR Volume logarithmic setting for this port. The values for volume are in mB (millibels = 1/100 dB) relative to a gain of 1 (e.g. the output is the same as the input level). Values are in mB from nMax (maximum volume) to nMin mB (typically negative). Since the volume is "voltage" and not a "power", it takes a setting of -600 mB to decrease the volume by 1/2. If a component cannot accurately set the volume to the requested value, it must set the volume to the closest value BELOW the requested value. When getting the volume setting, the current actual volume must be returned. */ } OMX_AUDIO_CONFIG_VOLUMETYPE; /** Audio Volume adjustment for a channel */ typedef struct OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port index indicating which port to set. Select the input port to set just that port's volume. Select the output port to adjust the master volume. */ OMX_U32 nChannel; /**< channel to select from 0 to N-1, using OMX_ALL to apply volume settings to all channels */ OMX_BOOL bLinear; /**< Is the volume to be set in linear (0.100) or logarithmic scale (mB) */ OMX_BS32 sVolume; /**< Volume linear setting in the 0..100 range, OR Volume logarithmic setting for this port. The values for volume are in mB (millibels = 1/100 dB) relative to a gain of 1 (e.g. the output is the same as the input level). Values are in mB from nMax (maximum volume) to nMin mB (typically negative). Since the volume is "voltage" and not a "power", it takes a setting of -600 mB to decrease the volume by 1/2. If a component cannot accurately set the volume to the requested value, it must set the volume to the closest value BELOW the requested value. When getting the volume setting, the current actual volume must be returned. */ OMX_BOOL bIsMIDI; /**< TRUE if nChannel refers to a MIDI channel, FALSE otherwise */ } OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE; /** Audio balance setting */ typedef struct OMX_AUDIO_CONFIG_BALANCETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port index indicating which port to set. Select the input port to set just that port's balance. Select the output port to adjust the master balance. */ OMX_S32 nBalance; /**< balance setting for this port (-100 to 100, where -100 indicates all left, and no right */ } OMX_AUDIO_CONFIG_BALANCETYPE; /** Audio Port mute */ typedef struct OMX_AUDIO_CONFIG_MUTETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port index indicating which port to set. Select the input port to set just that port's mute. Select the output port to adjust the master mute. */ OMX_BOOL bMute; /**< Mute setting for this port */ } OMX_AUDIO_CONFIG_MUTETYPE; /** Audio Channel mute */ typedef struct OMX_AUDIO_CONFIG_CHANNELMUTETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannel; /**< channel to select from 0 to N-1, using OMX_ALL to apply mute settings to all channels */ OMX_BOOL bMute; /**< Mute setting for this channel */ OMX_BOOL bIsMIDI; /**< TRUE if nChannel refers to a MIDI channel, FALSE otherwise */ } OMX_AUDIO_CONFIG_CHANNELMUTETYPE; /** Enable / Disable for loudness control, which boosts bass and to a * smaller extent high end frequencies to compensate for hearing * ability at the extreme ends of the audio spectrum */ typedef struct OMX_AUDIO_CONFIG_LOUDNESSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bLoudness; /**< Enable/disable for loudness */ } OMX_AUDIO_CONFIG_LOUDNESSTYPE; /** Enable / Disable for bass, which controls low frequencies */ typedef struct OMX_AUDIO_CONFIG_BASSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for bass control */ OMX_S32 nBass; /**< bass setting for the port, as a continuous value from -100 to 100 (0 means no change in bass level)*/ } OMX_AUDIO_CONFIG_BASSTYPE; /** Enable / Disable for treble, which controls high frequencies tones */ typedef struct OMX_AUDIO_CONFIG_TREBLETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for treble control */ OMX_S32 nTreble; /**< treble setting for the port, as a continuous value from -100 to 100 (0 means no change in treble level) */ } OMX_AUDIO_CONFIG_TREBLETYPE; /** An equalizer is typically used for two reasons: to compensate for an * sub-optimal frequency response of a system to make it sound more natural * or to create intentionally some unnatural coloring to the sound to create * an effect. * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_EQUALIZERTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for equalizer */ OMX_BU32 sBandIndex; /**< Band number to be set. Upper Limit is N-1, where N is the number of bands, lower limit is 0 */ OMX_BU32 sCenterFreq; /**< Center frequecies in Hz. This is a read only element and is used to determine the lower, center and upper frequency of this band. */ OMX_BS32 sBandLevel; /**< band level in millibels */ } OMX_AUDIO_CONFIG_EQUALIZERTYPE; /** Stereo widening mode type * @ingroup effects */ typedef enum OMX_AUDIO_STEREOWIDENINGTYPE { OMX_AUDIO_StereoWideningHeadphones, /**< Stereo widening for loudspeakers */ OMX_AUDIO_StereoWideningLoudspeakers, /**< Stereo widening for closely spaced loudspeakers */ OMX_AUDIO_StereoWideningKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_StereoWideningVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_StereoWideningMax = 0x7FFFFFFF } OMX_AUDIO_STEREOWIDENINGTYPE; /** Control for stereo widening, which is a special 2-channel * case of the audio virtualizer effect. For example, for 5.1-channel * output, it translates to virtual surround sound. * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for stereo widening control */ OMX_AUDIO_STEREOWIDENINGTYPE eWideningType; /**< Stereo widening algorithm type */ OMX_U32 nStereoWidening; /**< stereo widening setting for the port, as a continuous value from 0 to 100 */ } OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE; /** The chorus effect (or ``choralizer'') is any signal processor which makes * one sound source (such as a voice) sound like many such sources singing * (or playing) in unison. Since performance in unison is never exact, chorus * effects simulate this by making independently modified copies of the input * signal. Modifications may include (1) delay, (2) frequency shift, and * (3) amplitude modulation. * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_CHORUSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for chorus */ OMX_BU32 sDelay; /**< average delay in milliseconds */ OMX_BU32 sModulationRate; /**< rate of modulation in millihertz */ OMX_U32 nModulationDepth; /**< depth of modulation as a percentage of delay (i.e. 0 to 100) */ OMX_BU32 nFeedback; /**< Feedback from chorus output to input in percentage */ } OMX_AUDIO_CONFIG_CHORUSTYPE; /** Reverberation is part of the reflected sound that follows the early * reflections. In a typical room, this consists of a dense succession of * echoes whose energy decays exponentially. The reverberation effect structure * as defined here includes both (early) reflections as well as (late) reverberations. * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_REVERBERATIONTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bEnable; /**< Enable/disable for reverberation control */ OMX_BS32 sRoomLevel; /**< Intensity level for the whole room effect (i.e. both early reflections and late reverberation) in millibels */ OMX_BS32 sRoomHighFreqLevel; /**< Attenuation at high frequencies relative to the intensity at low frequencies in millibels */ OMX_BS32 sReflectionsLevel; /**< Intensity level of early reflections (relative to room value), in millibels */ OMX_BU32 sReflectionsDelay; /**< Delay time of the first reflection relative to the direct path, in milliseconds */ OMX_BS32 sReverbLevel; /**< Intensity level of late reverberation relative to room level, in millibels */ OMX_BU32 sReverbDelay; /**< Time delay from the first early reflection to the beginning of the late reverberation section, in milliseconds */ OMX_BU32 sDecayTime; /**< Late reverberation decay time at low frequencies, in milliseconds */ OMX_BU32 nDecayHighFreqRatio; /**< Ratio of high frequency decay time relative to low frequency decay time in percent */ OMX_U32 nDensity; /**< Modal density in the late reverberation decay, in percent (i.e. 0 - 100) */ OMX_U32 nDiffusion; /**< Echo density in the late reverberation decay, in percent (i.e. 0 - 100) */ OMX_BU32 sReferenceHighFreq; /**< Reference high frequency in Hertz. This is the frequency used as the reference for all the high-frequency settings above */ } OMX_AUDIO_CONFIG_REVERBERATIONTYPE; /** Possible settings for the Echo Cancelation structure to use * @ingroup effects */ typedef enum OMX_AUDIO_ECHOCANTYPE { OMX_AUDIO_EchoCanOff = 0, /**< Echo Cancellation is disabled */ OMX_AUDIO_EchoCanNormal, /**< Echo Cancellation normal operation - echo from plastics and face */ OMX_AUDIO_EchoCanHFree, /**< Echo Cancellation optimized for Hands Free operation */ OMX_AUDIO_EchoCanCarKit, /**< Echo Cancellation optimized for Car Kit (longer echo) */ OMX_AUDIO_EchoCanKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_EchoCanVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_EchoCanMax = 0x7FFFFFFF } OMX_AUDIO_ECHOCANTYPE; /** Enable / Disable for echo cancelation, which removes undesired echo's * from the audio * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_AUDIO_ECHOCANTYPE eEchoCancelation; /**< Echo cancelation settings */ } OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE; /** Enable / Disable for noise reduction, which undesired noise from * the audio * @ingroup effects */ typedef struct OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BOOL bNoiseReduction; /**< Enable/disable for noise reduction */ } OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE; /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_AudioExt.h0100644 0000000 0000000 00000013410 13077405420 016375 0ustar000000000 0000000 /* * Copyright (c) 2010 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_AudioExt.h - OpenMax IL version 1.1.2 * The OMX_AudioExt header file contains extensions to the * definitions used by both the application and the component to * access video items. */ #ifndef OMX_AudioExt_h #define OMX_AudioExt_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header shall include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include #define OMX_AUDIO_AACToolAndroidSSBR (OMX_AUDIO_AACToolVendor << 0) /**< SSBR: MPEG-4 Single-rate (downsampled) Spectral Band Replication tool allowed or active */ #define OMX_AUDIO_AACToolAndroidDSBR (OMX_AUDIO_AACToolVendor << 1) /**< DSBR: MPEG-4 Dual-rate Spectral Band Replication tool allowed or active */ typedef enum OMX_AUDIO_CODINGEXTTYPE { OMX_AUDIO_CodingAndroidUnused = OMX_AUDIO_CodingKhronosExtensions + 0x00100000, OMX_AUDIO_CodingAndroidAC3, /**< AC3 encoded data */ OMX_AUDIO_CodingAndroidOPUS, /**< OPUS encoded data */ OMX_AUDIO_CodingAndroidEAC3, /**< EAC3 encoded data */ } OMX_AUDIO_CODINGEXTTYPE; typedef struct OMX_AUDIO_PARAM_ANDROID_AC3TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ } OMX_AUDIO_PARAM_ANDROID_AC3TYPE; typedef struct OMX_AUDIO_PARAM_ANDROID_EAC3TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ } OMX_AUDIO_PARAM_ANDROID_EAC3TYPE; typedef struct OMX_AUDIO_PARAM_ANDROID_OPUSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nChannels; /**< Number of channels */ OMX_U32 nBitRate; /**< Bit rate of the encoded data data. Use 0 for variable rate or unknown bit rates. Encoding is set to the bitrate closest to specified value (in bps) */ OMX_U32 nSampleRate; /**< Sampling rate of the source data. Use 0 for variable or unknown sampling rate. */ OMX_U32 nAudioBandWidth; /**< Audio band width (in Hz) to which an encoder should limit the audio signal. Use 0 to let encoder decide */ } OMX_AUDIO_PARAM_ANDROID_OPUSTYPE; typedef struct OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_S32 nMaxOutputChannels; /**< Maximum channel count to be output, -1 if unspecified, 0 if downmixing disabled */ OMX_S32 nDrcCut; /**< The DRC attenuation factor, between 0 and 127, -1 if unspecified */ OMX_S32 nDrcBoost; /**< The DRC amplification factor, between 0 and 127, -1 if unspecified */ OMX_S32 nHeavyCompression; /**< 0 for light compression, 1 for heavy compression, -1 if unspecified */ OMX_S32 nTargetReferenceLevel; /**< Target reference level, between 0 and 127, -1 if unspecified */ OMX_S32 nEncodedTargetLevel; /**< Target reference level assumed at the encoder, between 0 and 127, -1 if unspecified */ OMX_S32 nPCMLimiterEnable; /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */ } OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE; typedef struct OMX_AUDIO_PARAM_ANDROID_PROFILETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 eProfile; /**< type is OMX_AUDIO_AACPROFILETYPE or OMX_AUDIO_WMAPROFILETYPE depending on context */ OMX_U32 nProfileIndex; /**< Used to query for individual profile support information */ } OMX_AUDIO_PARAM_ANDROID_PROFILETYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* OMX_AudioExt_h */ /* File EOF */ include/media/openmax/OMX_Component.h0100644 0000000 0000000 00000057557 13077405420 016641 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_Component.h - OpenMax IL version 1.1.2 * The OMX_Component header file contains the definitions used to define * the public interface of a component. This header file is intended to * be used by both the application and the component. */ #ifndef OMX_Component_h #define OMX_Component_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header must include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include #include #include #include /** @ingroup comp */ typedef enum OMX_PORTDOMAINTYPE { OMX_PortDomainAudio, OMX_PortDomainVideo, OMX_PortDomainImage, OMX_PortDomainOther, OMX_PortDomainKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_PortDomainVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_PortDomainMax = 0x7ffffff } OMX_PORTDOMAINTYPE; /** @ingroup comp */ typedef struct OMX_PARAM_PORTDEFINITIONTYPE { OMX_U32 nSize; /**< Size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Port number the structure applies to */ OMX_DIRTYPE eDir; /**< Direction (input or output) of this port */ OMX_U32 nBufferCountActual; /**< The actual number of buffers allocated on this port */ OMX_U32 nBufferCountMin; /**< The minimum number of buffers this port requires */ OMX_U32 nBufferSize; /**< Size, in bytes, for buffers to be used for this channel */ OMX_BOOL bEnabled; /**< Ports default to enabled and are enabled/disabled by OMX_CommandPortEnable/OMX_CommandPortDisable. When disabled a port is unpopulated. A disabled port is not populated with buffers on a transition to IDLE. */ OMX_BOOL bPopulated; /**< Port is populated with all of its buffers as indicated by nBufferCountActual. A disabled port is always unpopulated. An enabled port is populated on a transition to OMX_StateIdle and unpopulated on a transition to loaded. */ OMX_PORTDOMAINTYPE eDomain; /**< Domain of the port. Determines the contents of metadata below. */ union { OMX_AUDIO_PORTDEFINITIONTYPE audio; OMX_VIDEO_PORTDEFINITIONTYPE video; OMX_IMAGE_PORTDEFINITIONTYPE image; OMX_OTHER_PORTDEFINITIONTYPE other; } format; OMX_BOOL bBuffersContiguous; OMX_U32 nBufferAlignment; } OMX_PARAM_PORTDEFINITIONTYPE; /** @ingroup comp */ typedef struct OMX_PARAM_U32TYPE { OMX_U32 nSize; /**< Size of this structure, in Bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_U32 nU32; /**< U32 value */ } OMX_PARAM_U32TYPE; /** @ingroup rpm */ typedef enum OMX_SUSPENSIONPOLICYTYPE { OMX_SuspensionDisabled, /**< No suspension; v1.0 behavior */ OMX_SuspensionEnabled, /**< Suspension allowed */ OMX_SuspensionPolicyKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_SuspensionPolicyStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_SuspensionPolicyMax = 0x7fffffff } OMX_SUSPENSIONPOLICYTYPE; /** @ingroup rpm */ typedef struct OMX_PARAM_SUSPENSIONPOLICYTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_SUSPENSIONPOLICYTYPE ePolicy; } OMX_PARAM_SUSPENSIONPOLICYTYPE; /** @ingroup rpm */ typedef enum OMX_SUSPENSIONTYPE { OMX_NotSuspended, /**< component is not suspended */ OMX_Suspended, /**< component is suspended */ OMX_SuspensionKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_SuspensionVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_SuspendMax = 0x7FFFFFFF } OMX_SUSPENSIONTYPE; /** @ingroup rpm */ typedef struct OMX_PARAM_SUSPENSIONTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_SUSPENSIONTYPE eType; } OMX_PARAM_SUSPENSIONTYPE ; typedef struct OMX_CONFIG_BOOLEANTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_BOOL bEnabled; } OMX_CONFIG_BOOLEANTYPE; /* Parameter specifying the content uri to use. */ /** @ingroup cp */ typedef struct OMX_PARAM_CONTENTURITYPE { OMX_U32 nSize; /**< size of the structure in bytes, including actual URI name */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U8 contentURI[1]; /**< The URI name */ } OMX_PARAM_CONTENTURITYPE; /* Parameter specifying the pipe to use. */ /** @ingroup cp */ typedef struct OMX_PARAM_CONTENTPIPETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_HANDLETYPE hPipe; /**< The pipe handle*/ } OMX_PARAM_CONTENTPIPETYPE; /** @ingroup rpm */ typedef struct OMX_RESOURCECONCEALMENTTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_BOOL bResourceConcealmentForbidden; /**< disallow the use of resource concealment methods (like degrading algorithm quality to lower resource consumption or functional bypass) on a component as a resolution to resource conflicts. */ } OMX_RESOURCECONCEALMENTTYPE; /** @ingroup metadata */ typedef enum OMX_METADATACHARSETTYPE { OMX_MetadataCharsetUnknown = 0, OMX_MetadataCharsetASCII, OMX_MetadataCharsetBinary, OMX_MetadataCharsetCodePage1252, OMX_MetadataCharsetUTF8, OMX_MetadataCharsetJavaConformantUTF8, OMX_MetadataCharsetUTF7, OMX_MetadataCharsetImapUTF7, OMX_MetadataCharsetUTF16LE, OMX_MetadataCharsetUTF16BE, OMX_MetadataCharsetGB12345, OMX_MetadataCharsetHZGB2312, OMX_MetadataCharsetGB2312, OMX_MetadataCharsetGB18030, OMX_MetadataCharsetGBK, OMX_MetadataCharsetBig5, OMX_MetadataCharsetISO88591, OMX_MetadataCharsetISO88592, OMX_MetadataCharsetISO88593, OMX_MetadataCharsetISO88594, OMX_MetadataCharsetISO88595, OMX_MetadataCharsetISO88596, OMX_MetadataCharsetISO88597, OMX_MetadataCharsetISO88598, OMX_MetadataCharsetISO88599, OMX_MetadataCharsetISO885910, OMX_MetadataCharsetISO885913, OMX_MetadataCharsetISO885914, OMX_MetadataCharsetISO885915, OMX_MetadataCharsetShiftJIS, OMX_MetadataCharsetISO2022JP, OMX_MetadataCharsetISO2022JP1, OMX_MetadataCharsetISOEUCJP, OMX_MetadataCharsetSMS7Bit, OMX_MetadataCharsetKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_MetadataCharsetVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_MetadataCharsetTypeMax= 0x7FFFFFFF } OMX_METADATACHARSETTYPE; /** @ingroup metadata */ typedef enum OMX_METADATASCOPETYPE { OMX_MetadataScopeAllLevels, OMX_MetadataScopeTopLevel, OMX_MetadataScopePortLevel, OMX_MetadataScopeNodeLevel, OMX_MetadataScopeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_MetadataScopeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_MetadataScopeTypeMax = 0x7fffffff } OMX_METADATASCOPETYPE; /** @ingroup metadata */ typedef enum OMX_METADATASEARCHMODETYPE { OMX_MetadataSearchValueSizeByIndex, OMX_MetadataSearchItemByIndex, OMX_MetadataSearchNextItemByKey, OMX_MetadataSearchKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_MetadataSearchVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_MetadataSearchTypeMax = 0x7fffffff } OMX_METADATASEARCHMODETYPE; /** @ingroup metadata */ typedef struct OMX_CONFIG_METADATAITEMCOUNTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_METADATASCOPETYPE eScopeMode; OMX_U32 nScopeSpecifier; OMX_U32 nMetadataItemCount; } OMX_CONFIG_METADATAITEMCOUNTTYPE; /** @ingroup metadata */ typedef struct OMX_CONFIG_METADATAITEMTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_METADATASCOPETYPE eScopeMode; OMX_U32 nScopeSpecifier; OMX_U32 nMetadataItemIndex; OMX_METADATASEARCHMODETYPE eSearchMode; OMX_METADATACHARSETTYPE eKeyCharset; OMX_U8 nKeySizeUsed; OMX_U8 nKey[128]; OMX_METADATACHARSETTYPE eValueCharset; OMX_STRING sLanguageCountry; OMX_U32 nValueMaxSize; OMX_U32 nValueSizeUsed; OMX_U8 nValue[1]; } OMX_CONFIG_METADATAITEMTYPE; /* @ingroup metadata */ typedef struct OMX_CONFIG_CONTAINERNODECOUNTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_BOOL bAllKeys; OMX_U32 nParentNodeID; OMX_U32 nNumNodes; } OMX_CONFIG_CONTAINERNODECOUNTTYPE; /** @ingroup metadata */ typedef struct OMX_CONFIG_CONTAINERNODEIDTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_BOOL bAllKeys; OMX_U32 nParentNodeID; OMX_U32 nNodeIndex; OMX_U32 nNodeID; OMX_STRING cNodeName; OMX_BOOL bIsLeafType; } OMX_CONFIG_CONTAINERNODEIDTYPE; /** @ingroup metadata */ typedef struct OMX_PARAM_METADATAFILTERTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_BOOL bAllKeys; /* if true then this structure refers to all keys and * the three key fields below are ignored */ OMX_METADATACHARSETTYPE eKeyCharset; OMX_U32 nKeySizeUsed; OMX_U8 nKey [128]; OMX_U32 nLanguageCountrySizeUsed; OMX_U8 nLanguageCountry[128]; OMX_BOOL bEnabled; /* if true then key is part of filter (e.g. * retained for query later). If false then * key is not part of filter */ } OMX_PARAM_METADATAFILTERTYPE; /** The OMX_HANDLETYPE structure defines the component handle. The component * handle is used to access all of the component's public methods and also * contains pointers to the component's private data area. The component * handle is initialized by the OMX core (with help from the component) * during the process of loading the component. After the component is * successfully loaded, the application can safely access any of the * component's public functions (although some may return an error because * the state is inappropriate for the access). * * @ingroup comp */ typedef struct OMX_COMPONENTTYPE { /** The size of this structure, in bytes. It is the responsibility of the allocator of this structure to fill in this value. Since this structure is allocated by the GetHandle function, this function will fill in this value. */ OMX_U32 nSize; /** nVersion is the version of the OMX specification that the structure is built against. It is the responsibility of the creator of this structure to initialize this value and every user of this structure should verify that it knows how to use the exact version of this structure found herein. */ OMX_VERSIONTYPE nVersion; /** pComponentPrivate is a pointer to the component private data area. This member is allocated and initialized by the component when the component is first loaded. The application should not access this data area. */ OMX_PTR pComponentPrivate; /** pApplicationPrivate is a pointer that is a parameter to the OMX_GetHandle method, and contains an application private value provided by the IL client. This application private data is returned to the IL Client by OMX in all callbacks */ OMX_PTR pApplicationPrivate; /** refer to OMX_GetComponentVersion in OMX_core.h or the OMX IL specification for details on the GetComponentVersion method. */ OMX_ERRORTYPE (*GetComponentVersion)( OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_STRING pComponentName, OMX_OUT OMX_VERSIONTYPE* pComponentVersion, OMX_OUT OMX_VERSIONTYPE* pSpecVersion, OMX_OUT OMX_UUIDTYPE* pComponentUUID); /** refer to OMX_SendCommand in OMX_core.h or the OMX IL specification for details on the SendCommand method. */ OMX_ERRORTYPE (*SendCommand)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_COMMANDTYPE Cmd, OMX_IN OMX_U32 nParam1, OMX_IN OMX_PTR pCmdData); /** refer to OMX_GetParameter in OMX_core.h or the OMX IL specification for details on the GetParameter method. */ OMX_ERRORTYPE (*GetParameter)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nParamIndex, OMX_INOUT OMX_PTR pComponentParameterStructure); /** refer to OMX_SetParameter in OMX_core.h or the OMX IL specification for details on the SetParameter method. */ OMX_ERRORTYPE (*SetParameter)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentParameterStructure); /** refer to OMX_GetConfig in OMX_core.h or the OMX IL specification for details on the GetConfig method. */ OMX_ERRORTYPE (*GetConfig)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_INOUT OMX_PTR pComponentConfigStructure); /** refer to OMX_SetConfig in OMX_core.h or the OMX IL specification for details on the SetConfig method. */ OMX_ERRORTYPE (*SetConfig)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentConfigStructure); /** refer to OMX_GetExtensionIndex in OMX_core.h or the OMX IL specification for details on the GetExtensionIndex method. */ OMX_ERRORTYPE (*GetExtensionIndex)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_STRING cParameterName, OMX_OUT OMX_INDEXTYPE* pIndexType); /** refer to OMX_GetState in OMX_core.h or the OMX IL specification for details on the GetState method. */ OMX_ERRORTYPE (*GetState)( OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_STATETYPE* pState); /** The ComponentTunnelRequest method will interact with another OMX component to determine if tunneling is possible and to setup the tunneling. The return codes for this method can be used to determine if tunneling is not possible, or if tunneling is not supported. Base profile components (i.e. non-interop) do not support this method and should return OMX_ErrorNotImplemented The interop profile component MUST support tunneling to another interop profile component with a compatible port parameters. A component may also support proprietary communication. If proprietary communication is supported the negotiation of proprietary communication is done outside of OMX in a vendor specific way. It is only required that the proper result be returned and the details of how the setup is done is left to the component implementation. When this method is invoked when nPort in an output port, the component will: 1. Populate the pTunnelSetup structure with the output port's requirements and constraints for the tunnel. When this method is invoked when nPort in an input port, the component will: 1. Query the necessary parameters from the output port to determine if the ports are compatible for tunneling 2. If the ports are compatible, the component should store the tunnel step provided by the output port 3. Determine which port (either input or output) is the buffer supplier, and call OMX_SetParameter on the output port to indicate this selection. The component will return from this call within 5 msec. @param [in] hComp Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle method. @param [in] nPort nPort is used to select the port on the component to be used for tunneling. @param [in] hTunneledComp Handle of the component to tunnel with. This is the component handle returned by the call to the OMX_GetHandle method. When this parameter is 0x0 the component should setup the port for communication with the application / IL Client. @param [in] nPortOutput nPortOutput is used indicate the port the component should tunnel with. @param [in] pTunnelSetup Pointer to the tunnel setup structure. When nPort is an output port the component should populate the fields of this structure. When When nPort is an input port the component should review the setup provided by the component with the output port. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup tun */ OMX_ERRORTYPE (*ComponentTunnelRequest)( OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_U32 nPort, OMX_IN OMX_HANDLETYPE hTunneledComp, OMX_IN OMX_U32 nTunneledPort, OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup); /** refer to OMX_UseBuffer in OMX_core.h or the OMX IL specification for details on the UseBuffer method. @ingroup buf */ OMX_ERRORTYPE (*UseBuffer)( OMX_IN OMX_HANDLETYPE hComponent, OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes, OMX_IN OMX_U8* pBuffer); /** refer to OMX_AllocateBuffer in OMX_core.h or the OMX IL specification for details on the AllocateBuffer method. @ingroup buf */ OMX_ERRORTYPE (*AllocateBuffer)( OMX_IN OMX_HANDLETYPE hComponent, OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes); /** refer to OMX_FreeBuffer in OMX_core.h or the OMX IL specification for details on the FreeBuffer method. @ingroup buf */ OMX_ERRORTYPE (*FreeBuffer)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); /** refer to OMX_EmptyThisBuffer in OMX_core.h or the OMX IL specification for details on the EmptyThisBuffer method. @ingroup buf */ OMX_ERRORTYPE (*EmptyThisBuffer)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); /** refer to OMX_FillThisBuffer in OMX_core.h or the OMX IL specification for details on the FillThisBuffer method. @ingroup buf */ OMX_ERRORTYPE (*FillThisBuffer)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); /** The SetCallbacks method is used by the core to specify the callback structure from the application to the component. This is a blocking call. The component will return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the GetHandle function. @param [in] pCallbacks pointer to an OMX_CALLBACKTYPE structure used to provide the callback information to the component @param [in] pAppData pointer to an application defined value. It is anticipated that the application will pass a pointer to a data structure or a "this pointer" in this area to allow the callback (in the application) to determine the context of the call @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. */ OMX_ERRORTYPE (*SetCallbacks)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_CALLBACKTYPE* pCallbacks, OMX_IN OMX_PTR pAppData); /** ComponentDeInit method is used to deinitialize the component providing a means to free any resources allocated at component initialization. NOTE: After this call the component handle is not valid for further use. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the GetHandle function. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. */ OMX_ERRORTYPE (*ComponentDeInit)( OMX_IN OMX_HANDLETYPE hComponent); /** @ingroup buf */ OMX_ERRORTYPE (*UseEGLImage)( OMX_IN OMX_HANDLETYPE hComponent, OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN void* eglImage); OMX_ERRORTYPE (*ComponentRoleEnum)( OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_U8 *cRole, OMX_IN OMX_U32 nIndex); } OMX_COMPONENTTYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_ContentPipe.h0100644 0000000 0000000 00000023313 13077405420 017106 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_ContentPipe.h - OpenMax IL version 1.1.2 * The OMX_ContentPipe header file contains the definitions used to define * the public interface for content piples. This header file is intended to * be used by the component. */ #ifndef OMX_CONTENTPIPE_H #define OMX_CONTENTPIPE_H #ifndef KD_EACCES /* OpenKODE error codes. CPResult values may be zero (indicating success or one of the following values) */ #define KD_EACCES (1) #define KD_EADDRINUSE (2) #define KD_EAGAIN (5) #define KD_EBADF (7) #define KD_EBUSY (8) #define KD_ECONNREFUSED (9) #define KD_ECONNRESET (10) #define KD_EDEADLK (11) #define KD_EDESTADDRREQ (12) #define KD_ERANGE (35) #define KD_EEXIST (13) #define KD_EFBIG (14) #define KD_EHOSTUNREACH (15) #define KD_EINVAL (17) #define KD_EIO (18) #define KD_EISCONN (20) #define KD_EISDIR (21) #define KD_EMFILE (22) #define KD_ENAMETOOLONG (23) #define KD_ENOENT (24) #define KD_ENOMEM (25) #define KD_ENOSPC (26) #define KD_ENOSYS (27) #define KD_ENOTCONN (28) #define KD_EPERM (33) #define KD_ETIMEDOUT (36) #define KD_EILSEQ (19) #endif /** Map types from OMX standard types only here so interface is as generic as possible. */ typedef OMX_U32 CPresult; typedef char * CPstring; typedef void * CPhandle; typedef OMX_U32 CPuint; typedef OMX_S32 CPint; typedef char CPbyte; typedef OMX_BOOL CPbool; /** enumeration of origin types used in the CP_PIPETYPE's Seek function * @ingroup cp */ typedef enum CP_ORIGINTYPE { CP_OriginBegin, CP_OriginCur, CP_OriginEnd, CP_OriginKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ CP_OriginVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ CP_OriginMax = 0X7FFFFFFF } CP_ORIGINTYPE; /** enumeration of contact access types used in the CP_PIPETYPE's Open function * @ingroup cp */ typedef enum CP_ACCESSTYPE { CP_AccessRead, CP_AccessWrite, CP_AccessReadWrite, CP_AccessKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ CP_AccessVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ CP_AccessMax = 0X7FFFFFFF } CP_ACCESSTYPE; /** enumeration of results returned by the CP_PIPETYPE's CheckAvailableBytes function * @ingroup cp */ typedef enum CP_CHECKBYTESRESULTTYPE { CP_CheckBytesOk, /**< There are at least the request number of bytes available */ CP_CheckBytesNotReady, /**< The pipe is still retrieving bytes and presently lacks sufficient bytes. Client will be called when they are sufficient bytes are available. */ CP_CheckBytesInsufficientBytes, /**< The pipe has retrieved all bytes but those available are less than those requested */ CP_CheckBytesAtEndOfStream, /**< The pipe has reached the end of stream and no more bytes are available. */ CP_CheckBytesOutOfBuffers, /**< All read/write buffers are currently in use. */ CP_CheckBytesKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ CP_CheckBytesVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ CP_CheckBytesMax = 0X7FFFFFFF } CP_CHECKBYTESRESULTTYPE; /** enumeration of content pipe events sent to the client callback. * @ingroup cp */ typedef enum CP_EVENTTYPE{ CP_BytesAvailable, /** bytes requested in a CheckAvailableBytes call are now available*/ CP_Overflow, /** enumeration of content pipe events sent to the client callback*/ CP_PipeDisconnected, /** enumeration of content pipe events sent to the client callback*/ CP_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ CP_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ CP_EventMax = 0X7FFFFFFF } CP_EVENTTYPE; /** content pipe definition * @ingroup cp */ typedef struct CP_PIPETYPE { /** Open a content stream for reading or writing. */ CPresult (*Open)( CPhandle* hContent, CPstring szURI, CP_ACCESSTYPE eAccess ); /** Close a content stream. */ CPresult (*Close)( CPhandle hContent ); /** Create a content source and open it for writing. */ CPresult (*Create)( CPhandle *hContent, CPstring szURI ); /** Check the that specified number of bytes are available for reading or writing (depending on access type).*/ CPresult (*CheckAvailableBytes)( CPhandle hContent, CPuint nBytesRequested, CP_CHECKBYTESRESULTTYPE *eResult ); /** Seek to certain position in the content relative to the specified origin. */ CPresult (*SetPosition)( CPhandle hContent, CPint nOffset, CP_ORIGINTYPE eOrigin); /** Retrieve the current position relative to the start of the content. */ CPresult (*GetPosition)( CPhandle hContent, CPuint *pPosition); /** Retrieve data of the specified size from the content stream (advance content pointer by size of data). Note: pipe client provides pointer. This function is appropriate for small high frequency reads. */ CPresult (*Read)( CPhandle hContent, CPbyte *pData, CPuint nSize); /** Retrieve a buffer allocated by the pipe that contains the requested number of bytes. Buffer contains the next block of bytes, as specified by nSize, of the content. nSize also returns the size of the block actually read. Content pointer advances the by the returned size. Note: pipe provides pointer. This function is appropriate for large reads. The client must call ReleaseReadBuffer when done with buffer. In some cases the requested block may not reside in contiguous memory within the pipe implementation. For instance if the pipe leverages a circular buffer then the requested block may straddle the boundary of the circular buffer. By default a pipe implementation performs a copy in this case to provide the block to the pipe client in one contiguous buffer. If, however, the client sets bForbidCopy, then the pipe returns only those bytes preceding the memory boundary. Here the client may retrieve the data in segments over successive calls. */ CPresult (*ReadBuffer)( CPhandle hContent, CPbyte **ppBuffer, CPuint *nSize, CPbool bForbidCopy); /** Release a buffer obtained by ReadBuffer back to the pipe. */ CPresult (*ReleaseReadBuffer)(CPhandle hContent, CPbyte *pBuffer); /** Write data of the specified size to the content (advance content pointer by size of data). Note: pipe client provides pointer. This function is appropriate for small high frequency writes. */ CPresult (*Write)( CPhandle hContent, CPbyte *data, CPuint nSize); /** Retrieve a buffer allocated by the pipe used to write data to the content. Client will fill buffer with output data. Note: pipe provides pointer. This function is appropriate for large writes. The client must call WriteBuffer when done it has filled the buffer with data.*/ CPresult (*GetWriteBuffer)( CPhandle hContent, CPbyte **ppBuffer, CPuint nSize); /** Deliver a buffer obtained via GetWriteBuffer to the pipe. Pipe will write the the contents of the buffer to content and advance content pointer by the size of the buffer */ CPresult (*WriteBuffer)( CPhandle hContent, CPbyte *pBuffer, CPuint nFilledSize); /** Register a per-handle client callback with the content pipe. */ CPresult (*RegisterCallback)( CPhandle hContent, CPresult (*ClientCallback)(CP_EVENTTYPE eEvent, CPuint iParam)); } CP_PIPETYPE; #endif include/media/openmax/OMX_Core.h0100644 0000000 0000000 00000213523 13077405420 015552 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_Core.h - OpenMax IL version 1.1.2 * The OMX_Core header file contains the definitions used by both the * application and the component to access common items. */ #ifndef OMX_Core_h #define OMX_Core_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header shall include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** The OMX_COMMANDTYPE enumeration is used to specify the action in the * OMX_SendCommand macro. * @ingroup core */ typedef enum OMX_COMMANDTYPE { OMX_CommandStateSet, /**< Change the component state */ OMX_CommandFlush, /**< Flush the data queue(s) of a component */ OMX_CommandPortDisable, /**< Disable a port on a component. */ OMX_CommandPortEnable, /**< Enable a port on a component. */ OMX_CommandMarkBuffer, /**< Mark a component/buffer for observation */ OMX_CommandKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_CommandVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_CommandMax = 0X7FFFFFFF } OMX_COMMANDTYPE; /** The OMX_STATETYPE enumeration is used to indicate or change the component * state. This enumeration reflects the current state of the component when * used with the OMX_GetState macro or becomes the parameter in a state change * command when used with the OMX_SendCommand macro. * * The component will be in the Loaded state after the component is initially * loaded into memory. In the Loaded state, the component is not allowed to * allocate or hold resources other than to build it's internal parameter * and configuration tables. The application will send one or more * SetParameters/GetParameters and SetConfig/GetConfig commands to the * component and the component will record each of these parameter and * configuration changes for use later. When the application sends the * Idle command, the component will acquire the resources needed for the * specified configuration and will transition to the idle state if the * allocation is successful. If the component cannot successfully * transition to the idle state for any reason, the state of the component * shall be fully rolled back to the Loaded state (e.g. all allocated * resources shall be released). When the component receives the command * to go to the Executing state, it shall begin processing buffers by * sending all input buffers it holds to the application. While * the component is in the Idle state, the application may also send the * Pause command. If the component receives the pause command while in the * Idle state, the component shall send all input buffers it holds to the * application, but shall not begin processing buffers. This will allow the * application to prefill buffers. * * @ingroup comp */ typedef enum OMX_STATETYPE { OMX_StateInvalid, /**< component has detected that it's internal data structures are corrupted to the point that it cannot determine it's state properly */ OMX_StateLoaded, /**< component has been loaded but has not completed initialization. The OMX_SetParameter macro and the OMX_GetParameter macro are the only valid macros allowed to be sent to the component in this state. */ OMX_StateIdle, /**< component initialization has been completed successfully and the component is ready to to start. */ OMX_StateExecuting, /**< component has accepted the start command and is processing data (if data is available) */ OMX_StatePause, /**< component has received pause command */ OMX_StateWaitForResources, /**< component is waiting for resources, either after preemption or before it gets the resources requested. See specification for complete details. */ OMX_StateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_StateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_StateMax = 0X7FFFFFFF } OMX_STATETYPE; /** The OMX_ERRORTYPE enumeration defines the standard OMX Errors. These * errors should cover most of the common failure cases. However, * vendors are free to add additional error messages of their own as * long as they follow these rules: * 1. Vendor error messages shall be in the range of 0x90000000 to * 0x9000FFFF. * 2. Vendor error messages shall be defined in a header file provided * with the component. No error messages are allowed that are * not defined. */ typedef enum OMX_ERRORTYPE { OMX_ErrorNone = 0, /** There were insufficient resources to perform the requested operation */ OMX_ErrorInsufficientResources = (OMX_S32) 0x80001000, /** There was an error, but the cause of the error could not be determined */ OMX_ErrorUndefined = (OMX_S32) 0x80001001, /** The component name string was not valid */ OMX_ErrorInvalidComponentName = (OMX_S32) 0x80001002, /** No component with the specified name string was found */ OMX_ErrorComponentNotFound = (OMX_S32) 0x80001003, /** The component specified did not have a "OMX_ComponentInit" or "OMX_ComponentDeInit entry point */ OMX_ErrorInvalidComponent = (OMX_S32) 0x80001004, /** One or more parameters were not valid */ OMX_ErrorBadParameter = (OMX_S32) 0x80001005, /** The requested function is not implemented */ OMX_ErrorNotImplemented = (OMX_S32) 0x80001006, /** The buffer was emptied before the next buffer was ready */ OMX_ErrorUnderflow = (OMX_S32) 0x80001007, /** The buffer was not available when it was needed */ OMX_ErrorOverflow = (OMX_S32) 0x80001008, /** The hardware failed to respond as expected */ OMX_ErrorHardware = (OMX_S32) 0x80001009, /** The component is in the state OMX_StateInvalid */ OMX_ErrorInvalidState = (OMX_S32) 0x8000100A, /** Stream is found to be corrupt */ OMX_ErrorStreamCorrupt = (OMX_S32) 0x8000100B, /** Ports being connected are not compatible */ OMX_ErrorPortsNotCompatible = (OMX_S32) 0x8000100C, /** Resources allocated to an idle component have been lost resulting in the component returning to the loaded state */ OMX_ErrorResourcesLost = (OMX_S32) 0x8000100D, /** No more indicies can be enumerated */ OMX_ErrorNoMore = (OMX_S32) 0x8000100E, /** The component detected a version mismatch */ OMX_ErrorVersionMismatch = (OMX_S32) 0x8000100F, /** The component is not ready to return data at this time */ OMX_ErrorNotReady = (OMX_S32) 0x80001010, /** There was a timeout that occurred */ OMX_ErrorTimeout = (OMX_S32) 0x80001011, /** This error occurs when trying to transition into the state you are already in */ OMX_ErrorSameState = (OMX_S32) 0x80001012, /** Resources allocated to an executing or paused component have been preempted, causing the component to return to the idle state */ OMX_ErrorResourcesPreempted = (OMX_S32) 0x80001013, /** A non-supplier port sends this error to the IL client (via the EventHandler callback) during the allocation of buffers (on a transition from the LOADED to the IDLE state or on a port restart) when it deems that it has waited an unusually long time for the supplier to send it an allocated buffer via a UseBuffer call. */ OMX_ErrorPortUnresponsiveDuringAllocation = (OMX_S32) 0x80001014, /** A non-supplier port sends this error to the IL client (via the EventHandler callback) during the deallocation of buffers (on a transition from the IDLE to LOADED state or on a port stop) when it deems that it has waited an unusually long time for the supplier to request the deallocation of a buffer header via a FreeBuffer call. */ OMX_ErrorPortUnresponsiveDuringDeallocation = (OMX_S32) 0x80001015, /** A supplier port sends this error to the IL client (via the EventHandler callback) during the stopping of a port (either on a transition from the IDLE to LOADED state or a port stop) when it deems that it has waited an unusually long time for the non-supplier to return a buffer via an EmptyThisBuffer or FillThisBuffer call. */ OMX_ErrorPortUnresponsiveDuringStop = (OMX_S32) 0x80001016, /** Attempting a state transtion that is not allowed */ OMX_ErrorIncorrectStateTransition = (OMX_S32) 0x80001017, /* Attempting a command that is not allowed during the present state. */ OMX_ErrorIncorrectStateOperation = (OMX_S32) 0x80001018, /** The values encapsulated in the parameter or config structure are not supported. */ OMX_ErrorUnsupportedSetting = (OMX_S32) 0x80001019, /** The parameter or config indicated by the given index is not supported. */ OMX_ErrorUnsupportedIndex = (OMX_S32) 0x8000101A, /** The port index supplied is incorrect. */ OMX_ErrorBadPortIndex = (OMX_S32) 0x8000101B, /** The port has lost one or more of its buffers and it thus unpopulated. */ OMX_ErrorPortUnpopulated = (OMX_S32) 0x8000101C, /** Component suspended due to temporary loss of resources */ OMX_ErrorComponentSuspended = (OMX_S32) 0x8000101D, /** Component suspended due to an inability to acquire dynamic resources */ OMX_ErrorDynamicResourcesUnavailable = (OMX_S32) 0x8000101E, /** When the macroblock error reporting is enabled the component returns new error for every frame that has errors */ OMX_ErrorMbErrorsInFrame = (OMX_S32) 0x8000101F, /** A component reports this error when it cannot parse or determine the format of an input stream. */ OMX_ErrorFormatNotDetected = (OMX_S32) 0x80001020, /** The content open operation failed. */ OMX_ErrorContentPipeOpenFailed = (OMX_S32) 0x80001021, /** The content creation operation failed. */ OMX_ErrorContentPipeCreationFailed = (OMX_S32) 0x80001022, /** Separate table information is being used */ OMX_ErrorSeperateTablesUsed = (OMX_S32) 0x80001023, /** Tunneling is unsupported by the component*/ OMX_ErrorTunnelingUnsupported = (OMX_S32) 0x80001024, OMX_ErrorKhronosExtensions = (OMX_S32)0x8F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_ErrorVendorStartUnused = (OMX_S32)0x90000000, /**< Reserved region for introducing Vendor Extensions */ OMX_ErrorMax = 0x7FFFFFFF } OMX_ERRORTYPE; /** @ingroup core */ typedef OMX_ERRORTYPE (* OMX_COMPONENTINITTYPE)(OMX_IN OMX_HANDLETYPE hComponent); /** @ingroup core */ typedef struct OMX_COMPONENTREGISTERTYPE { const char * pName; /* Component name, 128 byte limit (including '\0') applies */ OMX_COMPONENTINITTYPE pInitialize; /* Component instance initialization function */ } OMX_COMPONENTREGISTERTYPE; /** @ingroup core */ extern OMX_COMPONENTREGISTERTYPE OMX_ComponentRegistered[]; /** @ingroup rpm */ typedef struct OMX_PRIORITYMGMTTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nGroupPriority; /**< Priority of the component group */ OMX_U32 nGroupID; /**< ID of the component group */ } OMX_PRIORITYMGMTTYPE; /* Component name and Role names are limited to 128 characters including the terminating '\0'. */ #define OMX_MAX_STRINGNAME_SIZE 128 /** @ingroup comp */ typedef struct OMX_PARAM_COMPONENTROLETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U8 cRole[OMX_MAX_STRINGNAME_SIZE]; /**< name of standard component which defines component role */ } OMX_PARAM_COMPONENTROLETYPE; /** End of Stream Buffer Flag: * * A component sets EOS when it has no more data to emit on a particular * output port. Thus an output port shall set EOS on the last buffer it * emits. A component's determination of when an output port should * cease sending data is implemenation specific. * @ingroup buf */ #define OMX_BUFFERFLAG_EOS 0x00000001 /** Start Time Buffer Flag: * * The source of a stream (e.g. a demux component) sets the STARTTIME * flag on the buffer that contains the starting timestamp for the * stream. The starting timestamp corresponds to the first data that * should be displayed at startup or after a seek. * The first timestamp of the stream is not necessarily the start time. * For instance, in the case of a seek to a particular video frame, * the target frame may be an interframe. Thus the first buffer of * the stream will be the intra-frame preceding the target frame and * the starttime will occur with the target frame (with any other * required frames required to reconstruct the target intervening). * * The STARTTIME flag is directly associated with the buffer's * timestamp ' thus its association to buffer data and its * propagation is identical to the timestamp's. * * When a Sync Component client receives a buffer with the * STARTTIME flag it shall perform a SetConfig on its sync port * using OMX_ConfigTimeClientStartTime and passing the buffer's * timestamp. * * @ingroup buf */ #define OMX_BUFFERFLAG_STARTTIME 0x00000002 /** Decode Only Buffer Flag: * * The source of a stream (e.g. a demux component) sets the DECODEONLY * flag on any buffer that should shall be decoded but should not be * displayed. This flag is used, for instance, when a source seeks to * a target interframe that requires the decode of frames preceding the * target to facilitate the target's reconstruction. In this case the * source would emit the frames preceding the target downstream * but mark them as decode only. * * The DECODEONLY is associated with buffer data and propagated in a * manner identical to the buffer timestamp. * * A component that renders data should ignore all buffers with * the DECODEONLY flag set. * * @ingroup buf */ #define OMX_BUFFERFLAG_DECODEONLY 0x00000004 /* Data Corrupt Flag: This flag is set when the IL client believes the data in the associated buffer is corrupt * @ingroup buf */ #define OMX_BUFFERFLAG_DATACORRUPT 0x00000008 /* End of Frame: The buffer contains exactly one end of frame and no data * occurs after the end of frame. This flag is an optional hint. The absence * of this flag does not imply the absence of an end of frame within the buffer. * @ingroup buf */ #define OMX_BUFFERFLAG_ENDOFFRAME 0x00000010 /* Sync Frame Flag: This flag is set when the buffer content contains a coded sync frame ' * a frame that has no dependency on any other frame information * @ingroup buf */ #define OMX_BUFFERFLAG_SYNCFRAME 0x00000020 /* Extra data present flag: there is extra data appended to the data stream * residing in the buffer * @ingroup buf */ #define OMX_BUFFERFLAG_EXTRADATA 0x00000040 /** Codec Config Buffer Flag: * OMX_BUFFERFLAG_CODECCONFIG is an optional flag that is set by an * output port when all bytes in the buffer form part or all of a set of * codec specific configuration data. Examples include SPS/PPS nal units * for OMX_VIDEO_CodingAVC or AudioSpecificConfig data for * OMX_AUDIO_CodingAAC. Any component that for a given stream sets * OMX_BUFFERFLAG_CODECCONFIG shall not mix codec configuration bytes * with frame data in the same buffer, and shall send all buffers * containing codec configuration bytes before any buffers containing * frame data that those configurations bytes describe. * If the stream format for a particular codec has a frame specific * header at the start of each frame, for example OMX_AUDIO_CodingMP3 or * OMX_AUDIO_CodingAAC in ADTS mode, then these shall be presented as * normal without setting OMX_BUFFERFLAG_CODECCONFIG. * @ingroup buf */ #define OMX_BUFFERFLAG_CODECCONFIG 0x00000080 /** @ingroup buf */ typedef struct OMX_BUFFERHEADERTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U8* pBuffer; /**< Pointer to actual block of memory that is acting as the buffer */ OMX_U32 nAllocLen; /**< size of the buffer allocated, in bytes */ OMX_U32 nFilledLen; /**< number of bytes currently in the buffer */ OMX_U32 nOffset; /**< start offset of valid data in bytes from the start of the buffer */ OMX_PTR pAppPrivate; /**< pointer to any data the application wants to associate with this buffer */ OMX_PTR pPlatformPrivate; /**< pointer to any data the platform wants to associate with this buffer */ OMX_PTR pInputPortPrivate; /**< pointer to any data the input port wants to associate with this buffer */ OMX_PTR pOutputPortPrivate; /**< pointer to any data the output port wants to associate with this buffer */ OMX_HANDLETYPE hMarkTargetComponent; /**< The component that will generate a mark event upon processing this buffer. */ OMX_PTR pMarkData; /**< Application specific data associated with the mark sent on a mark event to disambiguate this mark from others. */ OMX_U32 nTickCount; /**< Optional entry that the component and application can update with a tick count when they access the component. This value should be in microseconds. Since this is a value relative to an arbitrary starting point, this value cannot be used to determine absolute time. This is an optional entry and not all components will update it.*/ OMX_TICKS nTimeStamp; /**< Timestamp corresponding to the sample starting at the first logical sample boundary in the buffer. Timestamps of successive samples within the buffer may be inferred by adding the duration of the of the preceding buffer to the timestamp of the preceding buffer.*/ OMX_U32 nFlags; /**< buffer specific flags */ OMX_U32 nOutputPortIndex; /**< The index of the output port (if any) using this buffer */ OMX_U32 nInputPortIndex; /**< The index of the input port (if any) using this buffer */ } OMX_BUFFERHEADERTYPE; /** The OMX_EXTRADATATYPE enumeration is used to define the * possible extra data payload types. * NB: this enum is binary backwards compatible with the previous * OMX_EXTRADATA_QUANT define. This should be replaced with * OMX_ExtraDataQuantization. */ typedef enum OMX_EXTRADATATYPE { OMX_ExtraDataNone = 0, /**< Indicates that no more extra data sections follow */ OMX_ExtraDataQuantization, /**< The data payload contains quantization data */ OMX_ExtraDataKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_ExtraDataVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_ExtraDataMax = 0x7FFFFFFF } OMX_EXTRADATATYPE; typedef struct OMX_OTHER_EXTRADATATYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_EXTRADATATYPE eType; /* Extra Data type */ OMX_U32 nDataSize; /* Size of the supporting data to follow */ OMX_U8 data[1]; /* Supporting data hint */ } OMX_OTHER_EXTRADATATYPE; /** @ingroup comp */ typedef struct OMX_PORT_PARAM_TYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPorts; /**< The number of ports for this component */ OMX_U32 nStartPortNumber; /** first port number for this type of port */ } OMX_PORT_PARAM_TYPE; /** @ingroup comp */ typedef enum OMX_EVENTTYPE { OMX_EventCmdComplete, /**< component has sucessfully completed a command */ OMX_EventError, /**< component has detected an error condition */ OMX_EventMark, /**< component has detected a buffer mark */ OMX_EventPortSettingsChanged, /**< component is reported a port settings change */ OMX_EventBufferFlag, /**< component has detected an EOS */ OMX_EventResourcesAcquired, /**< component has been granted resources and is automatically starting the state change from OMX_StateWaitForResources to OMX_StateIdle. */ OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */ OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */ OMX_EventPortFormatDetected, /**< Component has detected a supported format. */ OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ /** Event when tunneled decoder has rendered an output or reached EOS * nData1 must contain the number of timestamps returned * pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the * render-timestamps of each frame. Component may batch rendered timestamps using this event, * but must signal the event no more than 40ms after the first frame in the batch. The frames * must be ordered by system timestamp inside and across batches. * * If component is doing frame-rate conversion, it must signal the render time of each * converted frame, and must interpolate media timestamps for in-between frames. * * When the component reached EOS, it must signal an EOS timestamp using the same mechanism. * This is in addition to the timestamp of the last rendered frame, and should follow that * frame. */ OMX_EventOutputRendered = 0x7F000001, /** For framework internal use only: event sent by OMXNodeInstance when it receives a graphic * input buffer with a new dataspace for encoding. |arg1| will contain the dataspace. |arg2| * will contain the ColorAspects requested by the component (or framework defaults) using * the following bitfield layout: * * +----------+-------------+----------------+------------+ * | Range | Primaries | MatrixCoeffs | Transfer | * +----------+-------------+----------------+------------+ * bits: 31....24 23.......16 15...........8 7........0 * * TODO: We would really need to tie this to an output buffer, but OMX does not provide a * fool-proof way to do that for video encoders. */ OMX_EventDataSpaceChanged, OMX_EventMax = 0x7FFFFFFF } OMX_EVENTTYPE; typedef struct OMX_CALLBACKTYPE { /** The EventHandler method is used to notify the application when an event of interest occurs. Events are defined in the OMX_EVENTTYPE enumeration. Please see that enumeration for details of what will be returned for each type of event. Callbacks should not return an error to the component, so if an error occurs, the application shall handle it internally. This is a blocking call. The application should return from this call within 5 msec to avoid blocking the component for an excessively long period of time. @param hComponent handle of the component to access. This is the component handle returned by the call to the GetHandle function. @param pAppData pointer to an application defined value that was provided in the pAppData parameter to the OMX_GetHandle method for the component. This application defined value is provided so that the application can have a component specific context when receiving the callback. @param eEvent Event that the component wants to notify the application about. @param nData1 nData will be the OMX_ERRORTYPE for an error event and will be an OMX_COMMANDTYPE for a command complete event and OMX_INDEXTYPE for a OMX_PortSettingsChanged event. @param nData2 nData2 will hold further information related to the event. Can be OMX_STATETYPE for a OMX_CommandStateSet command or port index for a OMX_PortSettingsChanged event. Default value is 0 if not used. ) @param pEventData Pointer to additional event-specific data (see spec for meaning). */ OMX_ERRORTYPE (*EventHandler)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData); /** The EmptyBufferDone method is used to return emptied buffers from an input port back to the application for reuse. This is a blocking call so the application should not attempt to refill the buffers during this call, but should queue them and refill them in another thread. There is no error return, so the application shall handle any errors generated internally. The application should return from this call within 5 msec. @param hComponent handle of the component to access. This is the component handle returned by the call to the GetHandle function. @param pAppData pointer to an application defined value that was provided in the pAppData parameter to the OMX_GetHandle method for the component. This application defined value is provided so that the application can have a component specific context when receiving the callback. @param pBuffer pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer or AllocateBuffer indicating the buffer that was emptied. @ingroup buf */ OMX_ERRORTYPE (*EmptyBufferDone)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); /** The FillBufferDone method is used to return filled buffers from an output port back to the application for emptying and then reuse. This is a blocking call so the application should not attempt to empty the buffers during this call, but should queue the buffers and empty them in another thread. There is no error return, so the application shall handle any errors generated internally. The application shall also update the buffer header to indicate the number of bytes placed into the buffer. The application should return from this call within 5 msec. @param hComponent handle of the component to access. This is the component handle returned by the call to the GetHandle function. @param pAppData pointer to an application defined value that was provided in the pAppData parameter to the OMX_GetHandle method for the component. This application defined value is provided so that the application can have a component specific context when receiving the callback. @param pBuffer pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer or AllocateBuffer indicating the buffer that was filled. @ingroup buf */ OMX_ERRORTYPE (*FillBufferDone)( OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer); } OMX_CALLBACKTYPE; /** The OMX_BUFFERSUPPLIERTYPE enumeration is used to dictate port supplier preference when tunneling between two ports. @ingroup tun buf */ typedef enum OMX_BUFFERSUPPLIERTYPE { OMX_BufferSupplyUnspecified = 0x0, /**< port supplying the buffers is unspecified, or don't care */ OMX_BufferSupplyInput, /**< input port supplies the buffers */ OMX_BufferSupplyOutput, /**< output port supplies the buffers */ OMX_BufferSupplyKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_BufferSupplyVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_BufferSupplyMax = 0x7FFFFFFF } OMX_BUFFERSUPPLIERTYPE; /** buffer supplier parameter * @ingroup tun */ typedef struct OMX_PARAM_BUFFERSUPPLIERTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_BUFFERSUPPLIERTYPE eBufferSupplier; /**< buffer supplier */ } OMX_PARAM_BUFFERSUPPLIERTYPE; /**< indicates that buffers received by an input port of a tunnel may not modify the data in the buffers @ingroup tun */ #define OMX_PORTTUNNELFLAG_READONLY 0x00000001 /** The OMX_TUNNELSETUPTYPE structure is used to pass data from an output port to an input port as part the two ComponentTunnelRequest calls resulting from a OMX_SetupTunnel call from the IL Client. @ingroup tun */ typedef struct OMX_TUNNELSETUPTYPE { OMX_U32 nTunnelFlags; /**< bit flags for tunneling */ OMX_BUFFERSUPPLIERTYPE eSupplier; /**< supplier preference */ } OMX_TUNNELSETUPTYPE; /* OMX Component headers is included to enable the core to use macros for functions into the component for OMX release 1.0. Developers should not access any structures or data from within the component header directly */ /* TO BE REMOVED - #include */ /** GetComponentVersion will return information about the component. This is a blocking call. This macro will go directly from the application to the component (via a core macro). The component will return from this call within 5 msec. @param [in] hComponent handle of component to execute the command @param [out] pComponentName pointer to an empty string of length 128 bytes. The component will write its name into this string. The name will be terminated by a single zero byte. The name of a component will be 127 bytes or less to leave room for the trailing zero byte. An example of a valid component name is "OMX.ABC.ChannelMixer\0". @param [out] pComponentVersion pointer to an OMX Version structure that the component will fill in. The component will fill in a value that indicates the component version. NOTE: the component version is NOT the same as the OMX Specification version (found in all structures). The component version is defined by the vendor of the component and its value is entirely up to the component vendor. @param [out] pSpecVersion pointer to an OMX Version structure that the component will fill in. The SpecVersion is the version of the specification that the component was built against. Please note that this value may or may not match the structure's version. For example, if the component was built against the 2.0 specification, but the application (which creates the structure is built against the 1.0 specification the versions would be different. @param [out] pComponentUUID pointer to the UUID of the component which will be filled in by the component. The UUID is a unique identifier that is set at RUN time for the component and is unique to each instantion of the component. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_GetComponentVersion( \ hComponent, \ pComponentName, \ pComponentVersion, \ pSpecVersion, \ pComponentUUID) \ ((OMX_COMPONENTTYPE*)hComponent)->GetComponentVersion( \ hComponent, \ pComponentName, \ pComponentVersion, \ pSpecVersion, \ pComponentUUID) /* Macro End */ /** Send a command to the component. This call is a non-blocking call. The component should check the parameters and then queue the command to the component thread to be executed. The component thread shall send the EventHandler() callback at the conclusion of the command. This macro will go directly from the application to the component (via a core macro). The component will return from this call within 5 msec. When the command is "OMX_CommandStateSet" the component will queue a state transition to the new state idenfied in nParam. When the command is "OMX_CommandFlush", to flush a port's buffer queues, the command will force the component to return all buffers NOT CURRENTLY BEING PROCESSED to the application, in the order in which the buffers were received. When the command is "OMX_CommandPortDisable" or "OMX_CommandPortEnable", the component's port (given by the value of nParam) will be stopped or restarted. When the command "OMX_CommandMarkBuffer" is used to mark a buffer, the pCmdData will point to a OMX_MARKTYPE structure containing the component handle of the component to examine the buffer chain for the mark. nParam1 contains the index of the port on which the buffer mark is applied. Specification text for more details. @param [in] hComponent handle of component to execute the command @param [in] Cmd Command for the component to execute @param [in] nParam Parameter for the command to be executed. When Cmd has the value OMX_CommandStateSet, value is a member of OMX_STATETYPE. When Cmd has the value OMX_CommandFlush, value of nParam indicates which port(s) to flush. -1 is used to flush all ports a single port index will only flush that port. When Cmd has the value "OMX_CommandPortDisable" or "OMX_CommandPortEnable", the component's port is given by the value of nParam. When Cmd has the value "OMX_CommandMarkBuffer" the components pot is given by the value of nParam. @param [in] pCmdData Parameter pointing to the OMX_MARKTYPE structure when Cmd has the value "OMX_CommandMarkBuffer". @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_SendCommand( \ hComponent, \ Cmd, \ nParam, \ pCmdData) \ ((OMX_COMPONENTTYPE*)hComponent)->SendCommand( \ hComponent, \ Cmd, \ nParam, \ pCmdData) /* Macro End */ /** The OMX_GetParameter macro will get one of the current parameter settings from the component. This macro cannot only be invoked when the component is in the OMX_StateInvalid state. The nParamIndex parameter is used to indicate which structure is being requested from the component. The application shall allocate the correct structure and shall fill in the structure size and version information before invoking this macro. When the parameter applies to a port, the caller shall fill in the appropriate nPortIndex value indicating the port on which the parameter applies. If the component has not had any settings changed, then the component should return a set of valid DEFAULT parameters for the component. This is a blocking call. The component should return from this call within 20 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] nParamIndex Index of the structure to be filled. This value is from the OMX_INDEXTYPE enumeration. @param [in,out] pComponentParameterStructure Pointer to application allocated structure to be filled by the component. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_GetParameter( \ hComponent, \ nParamIndex, \ pComponentParameterStructure) \ ((OMX_COMPONENTTYPE*)hComponent)->GetParameter( \ hComponent, \ nParamIndex, \ pComponentParameterStructure) /* Macro End */ /** The OMX_SetParameter macro will send an initialization parameter structure to a component. Each structure shall be sent one at a time, in a separate invocation of the macro. This macro can only be invoked when the component is in the OMX_StateLoaded state, or the port is disabled (when the parameter applies to a port). The nParamIndex parameter is used to indicate which structure is being passed to the component. The application shall allocate the correct structure and shall fill in the structure size and version information (as well as the actual data) before invoking this macro. The application is free to dispose of this structure after the call as the component is required to copy any data it shall retain. This is a blocking call. The component should return from this call within 20 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] nIndex Index of the structure to be sent. This value is from the OMX_INDEXTYPE enumeration. @param [in] pComponentParameterStructure pointer to application allocated structure to be used for initialization by the component. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_SetParameter( \ hComponent, \ nParamIndex, \ pComponentParameterStructure) \ ((OMX_COMPONENTTYPE*)hComponent)->SetParameter( \ hComponent, \ nParamIndex, \ pComponentParameterStructure) /* Macro End */ /** The OMX_GetConfig macro will get one of the configuration structures from a component. This macro can be invoked anytime after the component has been loaded. The nParamIndex call parameter is used to indicate which structure is being requested from the component. The application shall allocate the correct structure and shall fill in the structure size and version information before invoking this macro. If the component has not had this configuration parameter sent before, then the component should return a set of valid DEFAULT values for the component. This is a blocking call. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] nIndex Index of the structure to be filled. This value is from the OMX_INDEXTYPE enumeration. @param [in,out] pComponentConfigStructure pointer to application allocated structure to be filled by the component. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_GetConfig( \ hComponent, \ nConfigIndex, \ pComponentConfigStructure) \ ((OMX_COMPONENTTYPE*)hComponent)->GetConfig( \ hComponent, \ nConfigIndex, \ pComponentConfigStructure) /* Macro End */ /** The OMX_SetConfig macro will send one of the configuration structures to a component. Each structure shall be sent one at a time, each in a separate invocation of the macro. This macro can be invoked anytime after the component has been loaded. The application shall allocate the correct structure and shall fill in the structure size and version information (as well as the actual data) before invoking this macro. The application is free to dispose of this structure after the call as the component is required to copy any data it shall retain. This is a blocking call. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] nConfigIndex Index of the structure to be sent. This value is from the OMX_INDEXTYPE enumeration above. @param [in] pComponentConfigStructure pointer to application allocated structure to be used for initialization by the component. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_SetConfig( \ hComponent, \ nConfigIndex, \ pComponentConfigStructure) \ ((OMX_COMPONENTTYPE*)hComponent)->SetConfig( \ hComponent, \ nConfigIndex, \ pComponentConfigStructure) /* Macro End */ /** The OMX_GetExtensionIndex macro will invoke a component to translate a vendor specific configuration or parameter string into an OMX structure index. There is no requirement for the vendor to support this command for the indexes already found in the OMX_INDEXTYPE enumeration (this is done to save space in small components). The component shall support all vendor supplied extension indexes not found in the master OMX_INDEXTYPE enumeration. This is a blocking call. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the GetHandle function. @param [in] cParameterName OMX_STRING that shall be less than 128 characters long including the trailing null byte. This is the string that will get translated by the component into a configuration index. @param [out] pIndexType a pointer to a OMX_INDEXTYPE to receive the index value. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_GetExtensionIndex( \ hComponent, \ cParameterName, \ pIndexType) \ ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex( \ hComponent, \ cParameterName, \ pIndexType) /* Macro End */ /** The OMX_GetState macro will invoke the component to get the current state of the component and place the state value into the location pointed to by pState. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [out] pState pointer to the location to receive the state. The value returned is one of the OMX_STATETYPE members @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp */ #define OMX_GetState( \ hComponent, \ pState) \ ((OMX_COMPONENTTYPE*)hComponent)->GetState( \ hComponent, \ pState) /* Macro End */ /** The OMX_UseBuffer macro will request that the component use a buffer (and allocate its own buffer header) already allocated by another component, or by the IL Client. This is a blocking call. The component should return from this call within 20 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [out] ppBuffer pointer to an OMX_BUFFERHEADERTYPE structure used to receive the pointer to the buffer header @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_UseBuffer( \ hComponent, \ ppBufferHdr, \ nPortIndex, \ pAppPrivate, \ nSizeBytes, \ pBuffer) \ ((OMX_COMPONENTTYPE*)hComponent)->UseBuffer( \ hComponent, \ ppBufferHdr, \ nPortIndex, \ pAppPrivate, \ nSizeBytes, \ pBuffer) /** The OMX_AllocateBuffer macro will request that the component allocate a new buffer and buffer header. The component will allocate the buffer and the buffer header and return a pointer to the buffer header. This is a blocking call. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [out] ppBuffer pointer to an OMX_BUFFERHEADERTYPE structure used to receive the pointer to the buffer header @param [in] nPortIndex nPortIndex is used to select the port on the component the buffer will be used with. The port can be found by using the nPortIndex value as an index into the Port Definition array of the component. @param [in] pAppPrivate pAppPrivate is used to initialize the pAppPrivate member of the buffer header structure. @param [in] nSizeBytes size of the buffer to allocate. Used when bAllocateNew is true. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_AllocateBuffer( \ hComponent, \ ppBuffer, \ nPortIndex, \ pAppPrivate, \ nSizeBytes) \ ((OMX_COMPONENTTYPE*)hComponent)->AllocateBuffer( \ hComponent, \ ppBuffer, \ nPortIndex, \ pAppPrivate, \ nSizeBytes) /* Macro End */ /** The OMX_FreeBuffer macro will release a buffer header from the component which was allocated using either OMX_AllocateBuffer or OMX_UseBuffer. If the component allocated the buffer (see the OMX_UseBuffer macro) then the component shall free the buffer and buffer header. This is a blocking call. The component should return from this call within 20 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] nPortIndex nPortIndex is used to select the port on the component the buffer will be used with. @param [in] pBuffer pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer or AllocateBuffer. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_FreeBuffer( \ hComponent, \ nPortIndex, \ pBuffer) \ ((OMX_COMPONENTTYPE*)hComponent)->FreeBuffer( \ hComponent, \ nPortIndex, \ pBuffer) /* Macro End */ /** The OMX_EmptyThisBuffer macro will send a buffer full of data to an input port of a component. The buffer will be emptied by the component and returned to the application via the EmptyBufferDone call back. This is a non-blocking call in that the component will record the buffer and return immediately and then empty the buffer, later, at the proper time. As expected, this macro may be invoked only while the component is in the OMX_StateExecuting. If nPortIndex does not specify an input port, the component shall return an error. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] pBuffer pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer or AllocateBuffer. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_EmptyThisBuffer( \ hComponent, \ pBuffer) \ ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer( \ hComponent, \ pBuffer) /* Macro End */ /** The OMX_FillThisBuffer macro will send an empty buffer to an output port of a component. The buffer will be filled by the component and returned to the application via the FillBufferDone call back. This is a non-blocking call in that the component will record the buffer and return immediately and then fill the buffer, later, at the proper time. As expected, this macro may be invoked only while the component is in the OMX_ExecutingState. If nPortIndex does not specify an output port, the component shall return an error. The component should return from this call within 5 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [in] pBuffer pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer or AllocateBuffer. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_FillThisBuffer( \ hComponent, \ pBuffer) \ ((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer( \ hComponent, \ pBuffer) /* Macro End */ /** The OMX_UseEGLImage macro will request that the component use a EGLImage provided by EGL (and allocate its own buffer header) This is a blocking call. The component should return from this call within 20 msec. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the OMX_GetHandle function. @param [out] ppBuffer pointer to an OMX_BUFFERHEADERTYPE structure used to receive the pointer to the buffer header. Note that the memory location used for this buffer is NOT visible to the IL Client. @param [in] nPortIndex nPortIndex is used to select the port on the component the buffer will be used with. The port can be found by using the nPortIndex value as an index into the Port Definition array of the component. @param [in] pAppPrivate pAppPrivate is used to initialize the pAppPrivate member of the buffer header structure. @param [in] eglImage eglImage contains the handle of the EGLImage to use as a buffer on the specified port. The component is expected to validate properties of the EGLImage against the configuration of the port to ensure the component can use the EGLImage as a buffer. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup comp buf */ #define OMX_UseEGLImage( \ hComponent, \ ppBufferHdr, \ nPortIndex, \ pAppPrivate, \ eglImage) \ ((OMX_COMPONENTTYPE*)hComponent)->UseEGLImage( \ hComponent, \ ppBufferHdr, \ nPortIndex, \ pAppPrivate, \ eglImage) /** The OMX_Init method is used to initialize the OMX core. It shall be the first call made into OMX and it should only be executed one time without an interviening OMX_Deinit call. The core should return from this call within 20 msec. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void); /** The OMX_Deinit method is used to deinitialize the OMX core. It shall be the last call made into OMX. In the event that the core determines that thare are components loaded when this call is made, the core may return with an error rather than try to unload the components. The core should return from this call within 20 msec. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void); /** The OMX_ComponentNameEnum method will enumerate through all the names of recognised valid components in the system. This function is provided as a means to detect all the components in the system run-time. There is no strict ordering to the enumeration order of component names, although each name will only be enumerated once. If the OMX core supports run-time installation of new components, it is only requried to detect newly installed components when the first call to enumerate component names is made (i.e. when nIndex is 0x0). The core should return from this call in 20 msec. @param [out] cComponentName pointer to a null terminated string with the component name. The names of the components are strings less than 127 bytes in length plus the trailing null for a maximum size of 128 bytes. An example of a valid component name is "OMX.TI.AUDIO.DSP.MIXER\0". Names are assigned by the vendor, but shall start with "OMX." and then have the Vendor designation next. @param [in] nNameLength number of characters in the cComponentName string. With all component name strings restricted to less than 128 characters (including the trailing null) it is recomended that the caller provide a input string for the cComponentName of 128 characters. @param [in] nIndex number containing the enumeration index for the component. Multiple calls to OMX_ComponentNameEnum with increasing values of nIndex will enumerate through the component names in the system until OMX_ErrorNoMore is returned. The value of nIndex is 0 to (N-1), where N is the number of valid installed components in the system. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. When the value of nIndex exceeds the number of components in the system minus 1, OMX_ErrorNoMore will be returned. Otherwise the appropriate OMX error will be returned. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum( OMX_OUT OMX_STRING cComponentName, OMX_IN OMX_U32 nNameLength, OMX_IN OMX_U32 nIndex); /** The OMX_GetHandle method will locate the component specified by the component name given, load that component into memory and then invoke the component's methods to create an instance of the component. The core should return from this call within 20 msec. @param [out] pHandle pointer to an OMX_HANDLETYPE pointer to be filled in by this method. @param [in] cComponentName pointer to a null terminated string with the component name. The names of the components are strings less than 127 bytes in length plus the trailing null for a maximum size of 128 bytes. An example of a valid component name is "OMX.TI.AUDIO.DSP.MIXER\0". Names are assigned by the vendor, but shall start with "OMX." and then have the Vendor designation next. @param [in] pAppData pointer to an application defined value that will be returned during callbacks so that the application can identify the source of the callback. @param [in] pCallBacks pointer to a OMX_CALLBACKTYPE structure that will be passed to the component to initialize it with. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle( OMX_OUT OMX_HANDLETYPE* pHandle, OMX_IN OMX_STRING cComponentName, OMX_IN OMX_PTR pAppData, OMX_IN OMX_CALLBACKTYPE* pCallBacks); /** The OMX_FreeHandle method will free a handle allocated by the OMX_GetHandle method. If the component reference count goes to zero, the component will be unloaded from memory. The core should return from this call within 20 msec when the component is in the OMX_StateLoaded state. @param [in] hComponent Handle of the component to be accessed. This is the component handle returned by the call to the GetHandle function. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle( OMX_IN OMX_HANDLETYPE hComponent); /** The OMX_SetupTunnel method will handle the necessary calls to the components to setup the specified tunnel the two components. NOTE: This is an actual method (not a #define macro). This method will make calls into the component ComponentTunnelRequest method to do the actual tunnel connection. The ComponentTunnelRequest method on both components will be called. This method shall not be called unless the component is in the OMX_StateLoaded state except when the ports used for the tunnel are disabled. In this case, the component may be in the OMX_StateExecuting, OMX_StatePause, or OMX_StateIdle states. The core should return from this call within 20 msec. @param [in] hOutput Handle of the component to be accessed. Also this is the handle of the component whose port, specified in the nPortOutput parameter will be used the source for the tunnel. This is the component handle returned by the call to the OMX_GetHandle function. There is a requirement that hOutput be the source for the data when tunelling (i.e. nPortOutput is an output port). If 0x0, the component specified in hInput will have it's port specified in nPortInput setup for communication with the application / IL client. @param [in] nPortOutput nPortOutput is used to select the source port on component to be used in the tunnel. @param [in] hInput This is the component to setup the tunnel with. This is the handle of the component whose port, specified in the nPortInput parameter will be used the destination for the tunnel. This is the component handle returned by the call to the OMX_GetHandle function. There is a requirement that hInput be the destination for the data when tunelling (i.e. nPortInut is an input port). If 0x0, the component specified in hOutput will have it's port specified in nPortPOutput setup for communication with the application / IL client. @param [in] nPortInput nPortInput is used to select the destination port on component to be used in the tunnel. @return OMX_ERRORTYPE If the command successfully executes, the return code will be OMX_ErrorNone. Otherwise the appropriate OMX error will be returned. When OMX_ErrorNotImplemented is returned, one or both components is a non-interop component and does not support tunneling. On failure, the ports of both components are setup for communication with the application / IL Client. @ingroup core tun */ OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel( OMX_IN OMX_HANDLETYPE hOutput, OMX_IN OMX_U32 nPortOutput, OMX_IN OMX_HANDLETYPE hInput, OMX_IN OMX_U32 nPortInput); /** @ingroup cp */ OMX_API OMX_ERRORTYPE OMX_GetContentPipe( OMX_OUT OMX_HANDLETYPE *hPipe, OMX_IN OMX_STRING szURI); /** The OMX_GetComponentsOfRole method will return the number of components that support the given role and (if the compNames field is non-NULL) the names of those components. The call will fail if an insufficiently sized array of names is supplied. To ensure the array is sufficiently sized the client should: * first call this function with the compNames field NULL to determine the number of component names * second call this function with the compNames field pointing to an array of names allocated according to the number returned by the first call. The core should return from this call within 5 msec. @param [in] role This is generic standard component name consisting only of component class name and the type within that class (e.g. 'audio_decoder.aac'). @param [inout] pNumComps This is used both as input and output. If compNames is NULL, the input is ignored and the output specifies how many components support the given role. If compNames is not NULL, on input it bounds the size of the input structure and on output, it specifies the number of components string names listed within the compNames parameter. @param [inout] compNames If NULL this field is ignored. If non-NULL this points to an array of 128-byte strings which accepts a list of the names of all physical components that implement the specified standard component name. Each name is NULL terminated. numComps indicates the number of names. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_GetComponentsOfRole ( OMX_IN OMX_STRING role, OMX_INOUT OMX_U32 *pNumComps, OMX_INOUT OMX_U8 **compNames); /** The OMX_GetRolesOfComponent method will return the number of roles supported by the given component and (if the roles field is non-NULL) the names of those roles. The call will fail if an insufficiently sized array of names is supplied. To ensure the array is sufficiently sized the client should: * first call this function with the roles field NULL to determine the number of role names * second call this function with the roles field pointing to an array of names allocated according to the number returned by the first call. The core should return from this call within 5 msec. @param [in] compName This is the name of the component being queried about. @param [inout] pNumRoles This is used both as input and output. If roles is NULL, the input is ignored and the output specifies how many roles the component supports. If compNames is not NULL, on input it bounds the size of the input structure and on output, it specifies the number of roles string names listed within the roles parameter. @param [out] roles If NULL this field is ignored. If non-NULL this points to an array of 128-byte strings which accepts a list of the names of all standard components roles implemented on the specified component name. numComps indicates the number of names. @ingroup core */ OMX_API OMX_ERRORTYPE OMX_GetRolesOfComponent ( OMX_IN OMX_STRING compName, OMX_INOUT OMX_U32 *pNumRoles, OMX_OUT OMX_U8 **roles); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_IVCommon.h0100644 0000000 0000000 00000101361 13077405420 016345 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /** * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** * @file OMX_IVCommon.h - OpenMax IL version 1.1.2 * The structures needed by Video and Image components to exchange * parameters and configuration data with the components. */ #ifndef OMX_IVCommon_h #define OMX_IVCommon_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Each OMX header must include all required header files to allow the header * to compile without errors. The includes below are required for this header * file to compile successfully */ #include /** @defgroup iv OpenMAX IL Imaging and Video Domain * Common structures for OpenMAX IL Imaging and Video domains * @{ */ /** * Enumeration defining possible uncompressed image/video formats. * * ENUMS: * Unused : Placeholder value when format is N/A * Monochrome : black and white * 8bitRGB332 : Red 7:5, Green 4:2, Blue 1:0 * 12bitRGB444 : Red 11:8, Green 7:4, Blue 3:0 * 16bitARGB4444 : Alpha 15:12, Red 11:8, Green 7:4, Blue 3:0 * 16bitARGB1555 : Alpha 15, Red 14:10, Green 9:5, Blue 4:0 * 16bitRGB565 : Red 15:11, Green 10:5, Blue 4:0 * 16bitBGR565 : Blue 15:11, Green 10:5, Red 4:0 * 18bitRGB666 : Red 17:12, Green 11:6, Blue 5:0 * 18bitARGB1665 : Alpha 17, Red 16:11, Green 10:5, Blue 4:0 * 19bitARGB1666 : Alpha 18, Red 17:12, Green 11:6, Blue 5:0 * 24bitRGB888 : Red 24:16, Green 15:8, Blue 7:0 * 24bitBGR888 : Blue 24:16, Green 15:8, Red 7:0 * 24bitARGB1887 : Alpha 23, Red 22:15, Green 14:7, Blue 6:0 * 25bitARGB1888 : Alpha 24, Red 23:16, Green 15:8, Blue 7:0 * 32bitBGRA8888 : Blue 31:24, Green 23:16, Red 15:8, Alpha 7:0 * 32bitARGB8888 : Alpha 31:24, Red 23:16, Green 15:8, Blue 7:0 * YUV411Planar : U,Y are subsampled by a factor of 4 horizontally * YUV411PackedPlanar : packed per payload in planar slices * YUV420Planar : Three arrays Y,U,V. * YUV420PackedPlanar : packed per payload in planar slices * YUV420SemiPlanar : Two arrays, one is all Y, the other is U and V * YUV422Planar : Three arrays Y,U,V. * YUV422PackedPlanar : packed per payload in planar slices * YUV422SemiPlanar : Two arrays, one is all Y, the other is U and V * YCbYCr : Organized as 16bit YUYV (i.e. YCbYCr) * YCrYCb : Organized as 16bit YVYU (i.e. YCrYCb) * CbYCrY : Organized as 16bit UYVY (i.e. CbYCrY) * CrYCbY : Organized as 16bit VYUY (i.e. CrYCbY) * YUV444Interleaved : Each pixel contains equal parts YUV * RawBayer8bit : SMIA camera output format * RawBayer10bit : SMIA camera output format * RawBayer8bitcompressed : SMIA camera output format */ typedef enum OMX_COLOR_FORMATTYPE { OMX_COLOR_FormatUnused, OMX_COLOR_FormatMonochrome, OMX_COLOR_Format8bitRGB332, OMX_COLOR_Format12bitRGB444, OMX_COLOR_Format16bitARGB4444, OMX_COLOR_Format16bitARGB1555, OMX_COLOR_Format16bitRGB565, OMX_COLOR_Format16bitBGR565, OMX_COLOR_Format18bitRGB666, OMX_COLOR_Format18bitARGB1665, OMX_COLOR_Format19bitARGB1666, OMX_COLOR_Format24bitRGB888, OMX_COLOR_Format24bitBGR888, OMX_COLOR_Format24bitARGB1887, OMX_COLOR_Format25bitARGB1888, OMX_COLOR_Format32bitBGRA8888, OMX_COLOR_Format32bitARGB8888, OMX_COLOR_FormatYUV411Planar, OMX_COLOR_FormatYUV411PackedPlanar, OMX_COLOR_FormatYUV420Planar, OMX_COLOR_FormatYUV420PackedPlanar, OMX_COLOR_FormatYUV420SemiPlanar, OMX_COLOR_FormatYUV422Planar, OMX_COLOR_FormatYUV422PackedPlanar, OMX_COLOR_FormatYUV422SemiPlanar, OMX_COLOR_FormatYCbYCr, OMX_COLOR_FormatYCrYCb, OMX_COLOR_FormatCbYCrY, OMX_COLOR_FormatCrYCbY, OMX_COLOR_FormatYUV444Interleaved, OMX_COLOR_FormatRawBayer8bit, OMX_COLOR_FormatRawBayer10bit, OMX_COLOR_FormatRawBayer8bitcompressed, OMX_COLOR_FormatL2, OMX_COLOR_FormatL4, OMX_COLOR_FormatL8, OMX_COLOR_FormatL16, OMX_COLOR_FormatL24, OMX_COLOR_FormatL32, OMX_COLOR_FormatYUV420PackedSemiPlanar, OMX_COLOR_FormatYUV422PackedSemiPlanar, OMX_COLOR_Format18BitBGR666, OMX_COLOR_Format24BitARGB6666, OMX_COLOR_Format24BitABGR6666, OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_COLOR_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ /** /** @defgroup imaging OpenMAX IL Imaging Domain * @ingroup iv * Structures for OpenMAX IL Imaging domain * @{ */ /** * Enumeration used to define the possible image compression coding. */ typedef enum OMX_IMAGE_CODINGTYPE { OMX_IMAGE_CodingUnused, /**< Value when format is N/A */ OMX_IMAGE_CodingAutoDetect, /**< Auto detection of image format */ OMX_IMAGE_CodingJPEG, /**< JPEG/JFIF image format */ OMX_IMAGE_CodingJPEG2K, /**< JPEG 2000 image format */ OMX_IMAGE_CodingEXIF, /**< EXIF image format */ OMX_IMAGE_CodingTIFF, /**< TIFF image format */ OMX_IMAGE_CodingGIF, /**< Graphics image format */ OMX_IMAGE_CodingPNG, /**< PNG image format */ OMX_IMAGE_CodingLZW, /**< LZW image format */ OMX_IMAGE_CodingBMP, /**< Windows Bitmap format */ OMX_IMAGE_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_IMAGE_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_IMAGE_CodingMax = 0x7FFFFFFF } OMX_IMAGE_CODINGTYPE; /** * Data structure used to define an image path. The number of image paths * for input and output will vary by type of the image component. * * Input (aka Source) : Zero Inputs, one Output, * Splitter : One Input, 2 or more Outputs, * Processing Element : One Input, one output, * Mixer : 2 or more inputs, one output, * Output (aka Sink) : One Input, zero outputs. * * The PortDefinition structure is used to define all of the parameters * necessary for the compliant component to setup an input or an output * image path. If additional vendor specific data is required, it should * be transmitted to the component using the CustomCommand function. * Compliant components will prepopulate this structure with optimal * values during the OMX_GetParameter() command. * * STRUCT MEMBERS: * cMIMEType : MIME type of data for the port * pNativeRender : Platform specific reference for a display if a * sync, otherwise this field is 0 * nFrameWidth : Width of frame to be used on port if * uncompressed format is used. Use 0 for * unknown, don't care or variable * nFrameHeight : Height of frame to be used on port if * uncompressed format is used. Use 0 for * unknown, don't care or variable * nStride : Number of bytes per span of an image (i.e. * indicates the number of bytes to get from * span N to span N+1, where negative stride * indicates the image is bottom up * nSliceHeight : Height used when encoding in slices * bFlagErrorConcealment : Turns on error concealment if it is supported by * the OMX component * eCompressionFormat : Compression format used in this instance of * the component. When OMX_IMAGE_CodingUnused is * specified, eColorFormat is valid * eColorFormat : Decompressed format used by this component * pNativeWindow : Platform specific reference for a window object if a * display sink , otherwise this field is 0x0. */ typedef struct OMX_IMAGE_PORTDEFINITIONTYPE { OMX_STRING cMIMEType; OMX_NATIVE_DEVICETYPE pNativeRender; OMX_U32 nFrameWidth; OMX_U32 nFrameHeight; OMX_S32 nStride; OMX_U32 nSliceHeight; OMX_BOOL bFlagErrorConcealment; OMX_IMAGE_CODINGTYPE eCompressionFormat; OMX_COLOR_FORMATTYPE eColorFormat; OMX_NATIVE_WINDOWTYPE pNativeWindow; } OMX_IMAGE_PORTDEFINITIONTYPE; /** * Port format parameter. This structure is used to enumerate the various * data input/output format supported by the port. * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Indicates which port to set * nIndex : Indicates the enumeration index for the format from * 0x0 to N-1 * eCompressionFormat : Compression format used in this instance of the * component. When OMX_IMAGE_CodingUnused is specified, * eColorFormat is valid * eColorFormat : Decompressed format used by this component */ typedef struct OMX_IMAGE_PARAM_PORTFORMATTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nIndex; OMX_IMAGE_CODINGTYPE eCompressionFormat; OMX_COLOR_FORMATTYPE eColorFormat; } OMX_IMAGE_PARAM_PORTFORMATTYPE; /** * Flash control type * * ENUMS * Torch : Flash forced constantly on */ typedef enum OMX_IMAGE_FLASHCONTROLTYPE { OMX_IMAGE_FlashControlOn = 0, OMX_IMAGE_FlashControlOff, OMX_IMAGE_FlashControlAuto, OMX_IMAGE_FlashControlRedEyeReduction, OMX_IMAGE_FlashControlFillin, OMX_IMAGE_FlashControlTorch, OMX_IMAGE_FlashControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_IMAGE_FlashControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_IMAGE_FlashControlMax = 0x7FFFFFFF } OMX_IMAGE_FLASHCONTROLTYPE; /** * Flash control configuration * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eFlashControl : Flash control type */ typedef struct OMX_IMAGE_PARAM_FLASHCONTROLTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_IMAGE_FLASHCONTROLTYPE eFlashControl; } OMX_IMAGE_PARAM_FLASHCONTROLTYPE; /** * Focus control type */ typedef enum OMX_IMAGE_FOCUSCONTROLTYPE { OMX_IMAGE_FocusControlOn = 0, OMX_IMAGE_FocusControlOff, OMX_IMAGE_FocusControlAuto, OMX_IMAGE_FocusControlAutoLock, OMX_IMAGE_FocusControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_IMAGE_FocusControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_IMAGE_FocusControlMax = 0x7FFFFFFF } OMX_IMAGE_FOCUSCONTROLTYPE; /** * Focus control configuration * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eFocusControl : Focus control * nFocusSteps : Focus can take on values from 0 mm to infinity. * Interest is only in number of steps over this range. * nFocusStepIndex : Current focus step index */ typedef struct OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_IMAGE_FOCUSCONTROLTYPE eFocusControl; OMX_U32 nFocusSteps; OMX_U32 nFocusStepIndex; } OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE; /** * Q Factor for JPEG compression, which controls the tradeoff between image * quality and size. Q Factor provides a more simple means of controlling * JPEG compression quality, without directly programming Quantization * tables for chroma and luma * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nQFactor : JPEG Q factor value in the range of 1-100. A factor of 1 * produces the smallest, worst quality images, and a factor * of 100 produces the largest, best quality images. A * typical default is 75 for small good quality images */ typedef struct OMX_IMAGE_PARAM_QFACTORTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nQFactor; } OMX_IMAGE_PARAM_QFACTORTYPE; /** * Quantization table type */ typedef enum OMX_IMAGE_QUANTIZATIONTABLETYPE { OMX_IMAGE_QuantizationTableLuma = 0, OMX_IMAGE_QuantizationTableChroma, OMX_IMAGE_QuantizationTableChromaCb, OMX_IMAGE_QuantizationTableChromaCr, OMX_IMAGE_QuantizationTableKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_IMAGE_QuantizationTableVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_IMAGE_QuantizationTableMax = 0x7FFFFFFF } OMX_IMAGE_QUANTIZATIONTABLETYPE; /** * JPEG quantization tables are used to determine DCT compression for * YUV data, as an alternative to specifying Q factor, providing exact * control of compression * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eQuantizationTable : Quantization table type * nQuantizationMatrix[64] : JPEG quantization table of coefficients stored * in increasing columns then by rows of data (i.e. * row 1, ... row 8). Quantization values are in * the range 0-255 and stored in linear order * (i.e. the component will zig-zag the * quantization table data if required internally) */ typedef struct OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_IMAGE_QUANTIZATIONTABLETYPE eQuantizationTable; OMX_U8 nQuantizationMatrix[64]; } OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE; /** * Huffman table type, the same Huffman table is applied for chroma and * luma component */ typedef enum OMX_IMAGE_HUFFMANTABLETYPE { OMX_IMAGE_HuffmanTableAC = 0, OMX_IMAGE_HuffmanTableDC, OMX_IMAGE_HuffmanTableACLuma, OMX_IMAGE_HuffmanTableACChroma, OMX_IMAGE_HuffmanTableDCLuma, OMX_IMAGE_HuffmanTableDCChroma, OMX_IMAGE_HuffmanTableKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_IMAGE_HuffmanTableVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_IMAGE_HuffmanTableMax = 0x7FFFFFFF } OMX_IMAGE_HUFFMANTABLETYPE; /** * JPEG Huffman table * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eHuffmanTable : Huffman table type * nNumberOfHuffmanCodeOfLength[16] : 0-16, number of Huffman codes of each * possible length * nHuffmanTable[256] : 0-255, the size used for AC and DC * HuffmanTable are 16 and 162 */ typedef struct OMX_IMAGE_PARAM_HUFFMANTTABLETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_IMAGE_HUFFMANTABLETYPE eHuffmanTable; OMX_U8 nNumberOfHuffmanCodeOfLength[16]; OMX_U8 nHuffmanTable[256]; }OMX_IMAGE_PARAM_HUFFMANTTABLETYPE; /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_Index.h0100644 0000000 0000000 00000044410 13077405420 015726 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** @file OMX_Index.h - OpenMax IL version 1.1.2 * The OMX_Index header file contains the definitions for both applications * and components . */ #ifndef OMX_Index_h #define OMX_Index_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header must include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** The OMX_INDEXTYPE enumeration is used to select a structure when either * getting or setting parameters and/or configuration data. Each entry in * this enumeration maps to an OMX specified structure. When the * OMX_GetParameter, OMX_SetParameter, OMX_GetConfig or OMX_SetConfig methods * are used, the second parameter will always be an entry from this enumeration * and the third entry will be the structure shown in the comments for the entry. * For example, if the application is initializing a cropping function, the * OMX_SetConfig command would have OMX_IndexConfigCommonInputCrop as the second parameter * and would send a pointer to an initialized OMX_RECTTYPE structure as the * third parameter. * * The enumeration entries named with the OMX_Config prefix are sent using * the OMX_SetConfig command and the enumeration entries named with the * OMX_PARAM_ prefix are sent using the OMX_SetParameter command. */ typedef enum OMX_INDEXTYPE { OMX_IndexComponentStartUnused = 0x01000000, OMX_IndexParamPriorityMgmt, /**< reference: OMX_PRIORITYMGMTTYPE */ OMX_IndexParamAudioInit, /**< reference: OMX_PORT_PARAM_TYPE */ OMX_IndexParamImageInit, /**< reference: OMX_PORT_PARAM_TYPE */ OMX_IndexParamVideoInit, /**< reference: OMX_PORT_PARAM_TYPE */ OMX_IndexParamOtherInit, /**< reference: OMX_PORT_PARAM_TYPE */ OMX_IndexParamNumAvailableStreams, /**< reference: OMX_PARAM_U32TYPE */ OMX_IndexParamActiveStream, /**< reference: OMX_PARAM_U32TYPE */ OMX_IndexParamSuspensionPolicy, /**< reference: OMX_PARAM_SUSPENSIONPOLICYTYPE */ OMX_IndexParamComponentSuspended, /**< reference: OMX_PARAM_SUSPENSIONTYPE */ OMX_IndexConfigCapturing, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigCaptureMode, /**< reference: OMX_CONFIG_CAPTUREMODETYPE */ OMX_IndexAutoPauseAfterCapture, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexParamContentURI, /**< reference: OMX_PARAM_CONTENTURITYPE */ OMX_IndexParamCustomContentPipe, /**< reference: OMX_PARAM_CONTENTPIPETYPE */ OMX_IndexParamDisableResourceConcealment, /**< reference: OMX_RESOURCECONCEALMENTTYPE */ OMX_IndexConfigMetadataItemCount, /**< reference: OMX_CONFIG_METADATAITEMCOUNTTYPE */ OMX_IndexConfigContainerNodeCount, /**< reference: OMX_CONFIG_CONTAINERNODECOUNTTYPE */ OMX_IndexConfigMetadataItem, /**< reference: OMX_CONFIG_METADATAITEMTYPE */ OMX_IndexConfigCounterNodeID, /**< reference: OMX_CONFIG_CONTAINERNODEIDTYPE */ OMX_IndexParamMetadataFilterType, /**< reference: OMX_PARAM_METADATAFILTERTYPE */ OMX_IndexParamMetadataKeyFilter, /**< reference: OMX_PARAM_METADATAFILTERTYPE */ OMX_IndexConfigPriorityMgmt, /**< reference: OMX_PRIORITYMGMTTYPE */ OMX_IndexParamStandardComponentRole, /**< reference: OMX_PARAM_COMPONENTROLETYPE */ OMX_IndexPortStartUnused = 0x02000000, OMX_IndexParamPortDefinition, /**< reference: OMX_PARAM_PORTDEFINITIONTYPE */ OMX_IndexParamCompBufferSupplier, /**< reference: OMX_PARAM_BUFFERSUPPLIERTYPE */ OMX_IndexReservedStartUnused = 0x03000000, /* Audio parameters and configurations */ OMX_IndexAudioStartUnused = 0x04000000, OMX_IndexParamAudioPortFormat, /**< reference: OMX_AUDIO_PARAM_PORTFORMATTYPE */ OMX_IndexParamAudioPcm, /**< reference: OMX_AUDIO_PARAM_PCMMODETYPE */ OMX_IndexParamAudioAac, /**< reference: OMX_AUDIO_PARAM_AACPROFILETYPE */ OMX_IndexParamAudioRa, /**< reference: OMX_AUDIO_PARAM_RATYPE */ OMX_IndexParamAudioMp3, /**< reference: OMX_AUDIO_PARAM_MP3TYPE */ OMX_IndexParamAudioAdpcm, /**< reference: OMX_AUDIO_PARAM_ADPCMTYPE */ OMX_IndexParamAudioG723, /**< reference: OMX_AUDIO_PARAM_G723TYPE */ OMX_IndexParamAudioG729, /**< reference: OMX_AUDIO_PARAM_G729TYPE */ OMX_IndexParamAudioAmr, /**< reference: OMX_AUDIO_PARAM_AMRTYPE */ OMX_IndexParamAudioWma, /**< reference: OMX_AUDIO_PARAM_WMATYPE */ OMX_IndexParamAudioSbc, /**< reference: OMX_AUDIO_PARAM_SBCTYPE */ OMX_IndexParamAudioMidi, /**< reference: OMX_AUDIO_PARAM_MIDITYPE */ OMX_IndexParamAudioGsm_FR, /**< reference: OMX_AUDIO_PARAM_GSMFRTYPE */ OMX_IndexParamAudioMidiLoadUserSound, /**< reference: OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE */ OMX_IndexParamAudioG726, /**< reference: OMX_AUDIO_PARAM_G726TYPE */ OMX_IndexParamAudioGsm_EFR, /**< reference: OMX_AUDIO_PARAM_GSMEFRTYPE */ OMX_IndexParamAudioGsm_HR, /**< reference: OMX_AUDIO_PARAM_GSMHRTYPE */ OMX_IndexParamAudioPdc_FR, /**< reference: OMX_AUDIO_PARAM_PDCFRTYPE */ OMX_IndexParamAudioPdc_EFR, /**< reference: OMX_AUDIO_PARAM_PDCEFRTYPE */ OMX_IndexParamAudioPdc_HR, /**< reference: OMX_AUDIO_PARAM_PDCHRTYPE */ OMX_IndexParamAudioTdma_FR, /**< reference: OMX_AUDIO_PARAM_TDMAFRTYPE */ OMX_IndexParamAudioTdma_EFR, /**< reference: OMX_AUDIO_PARAM_TDMAEFRTYPE */ OMX_IndexParamAudioQcelp8, /**< reference: OMX_AUDIO_PARAM_QCELP8TYPE */ OMX_IndexParamAudioQcelp13, /**< reference: OMX_AUDIO_PARAM_QCELP13TYPE */ OMX_IndexParamAudioEvrc, /**< reference: OMX_AUDIO_PARAM_EVRCTYPE */ OMX_IndexParamAudioSmv, /**< reference: OMX_AUDIO_PARAM_SMVTYPE */ OMX_IndexParamAudioVorbis, /**< reference: OMX_AUDIO_PARAM_VORBISTYPE */ OMX_IndexParamAudioFlac, /**< reference: OMX_AUDIO_PARAM_FLACTYPE */ OMX_IndexConfigAudioMidiImmediateEvent, /**< reference: OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE */ OMX_IndexConfigAudioMidiControl, /**< reference: OMX_AUDIO_CONFIG_MIDICONTROLTYPE */ OMX_IndexConfigAudioMidiSoundBankProgram, /**< reference: OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE */ OMX_IndexConfigAudioMidiStatus, /**< reference: OMX_AUDIO_CONFIG_MIDISTATUSTYPE */ OMX_IndexConfigAudioMidiMetaEvent, /**< reference: OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE */ OMX_IndexConfigAudioMidiMetaEventData, /**< reference: OMX_AUDIO_CONFIG_MIDIMETAEVENTDATATYPE */ OMX_IndexConfigAudioVolume, /**< reference: OMX_AUDIO_CONFIG_VOLUMETYPE */ OMX_IndexConfigAudioBalance, /**< reference: OMX_AUDIO_CONFIG_BALANCETYPE */ OMX_IndexConfigAudioChannelMute, /**< reference: OMX_AUDIO_CONFIG_CHANNELMUTETYPE */ OMX_IndexConfigAudioMute, /**< reference: OMX_AUDIO_CONFIG_MUTETYPE */ OMX_IndexConfigAudioLoudness, /**< reference: OMX_AUDIO_CONFIG_LOUDNESSTYPE */ OMX_IndexConfigAudioEchoCancelation, /**< reference: OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE */ OMX_IndexConfigAudioNoiseReduction, /**< reference: OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE */ OMX_IndexConfigAudioBass, /**< reference: OMX_AUDIO_CONFIG_BASSTYPE */ OMX_IndexConfigAudioTreble, /**< reference: OMX_AUDIO_CONFIG_TREBLETYPE */ OMX_IndexConfigAudioStereoWidening, /**< reference: OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE */ OMX_IndexConfigAudioChorus, /**< reference: OMX_AUDIO_CONFIG_CHORUSTYPE */ OMX_IndexConfigAudioEqualizer, /**< reference: OMX_AUDIO_CONFIG_EQUALIZERTYPE */ OMX_IndexConfigAudioReverberation, /**< reference: OMX_AUDIO_CONFIG_REVERBERATIONTYPE */ OMX_IndexConfigAudioChannelVolume, /**< reference: OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE */ /* Image specific parameters and configurations */ OMX_IndexImageStartUnused = 0x05000000, OMX_IndexParamImagePortFormat, /**< reference: OMX_IMAGE_PARAM_PORTFORMATTYPE */ OMX_IndexParamFlashControl, /**< reference: OMX_IMAGE_PARAM_FLASHCONTROLTYPE */ OMX_IndexConfigFocusControl, /**< reference: OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE */ OMX_IndexParamQFactor, /**< reference: OMX_IMAGE_PARAM_QFACTORTYPE */ OMX_IndexParamQuantizationTable, /**< reference: OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE */ OMX_IndexParamHuffmanTable, /**< reference: OMX_IMAGE_PARAM_HUFFMANTTABLETYPE */ OMX_IndexConfigFlashControl, /**< reference: OMX_IMAGE_PARAM_FLASHCONTROLTYPE */ /* Video specific parameters and configurations */ OMX_IndexVideoStartUnused = 0x06000000, OMX_IndexParamVideoPortFormat, /**< reference: OMX_VIDEO_PARAM_PORTFORMATTYPE */ OMX_IndexParamVideoQuantization, /**< reference: OMX_VIDEO_PARAM_QUANTIZATIONTYPE */ OMX_IndexParamVideoFastUpdate, /**< reference: OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE */ OMX_IndexParamVideoBitrate, /**< reference: OMX_VIDEO_PARAM_BITRATETYPE */ OMX_IndexParamVideoMotionVector, /**< reference: OMX_VIDEO_PARAM_MOTIONVECTORTYPE */ OMX_IndexParamVideoIntraRefresh, /**< reference: OMX_VIDEO_PARAM_INTRAREFRESHTYPE */ OMX_IndexParamVideoErrorCorrection, /**< reference: OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE */ OMX_IndexParamVideoVBSMC, /**< reference: OMX_VIDEO_PARAM_VBSMCTYPE */ OMX_IndexParamVideoMpeg2, /**< reference: OMX_VIDEO_PARAM_MPEG2TYPE */ OMX_IndexParamVideoMpeg4, /**< reference: OMX_VIDEO_PARAM_MPEG4TYPE */ OMX_IndexParamVideoWmv, /**< reference: OMX_VIDEO_PARAM_WMVTYPE */ OMX_IndexParamVideoRv, /**< reference: OMX_VIDEO_PARAM_RVTYPE */ OMX_IndexParamVideoAvc, /**< reference: OMX_VIDEO_PARAM_AVCTYPE */ OMX_IndexParamVideoH263, /**< reference: OMX_VIDEO_PARAM_H263TYPE */ OMX_IndexParamVideoProfileLevelQuerySupported, /**< reference: OMX_VIDEO_PARAM_PROFILELEVELTYPE */ OMX_IndexParamVideoProfileLevelCurrent, /**< reference: OMX_VIDEO_PARAM_PROFILELEVELTYPE */ OMX_IndexConfigVideoBitrate, /**< reference: OMX_VIDEO_CONFIG_BITRATETYPE */ OMX_IndexConfigVideoFramerate, /**< reference: OMX_CONFIG_FRAMERATETYPE */ OMX_IndexConfigVideoIntraVOPRefresh, /**< reference: OMX_CONFIG_INTRAREFRESHVOPTYPE */ OMX_IndexConfigVideoIntraMBRefresh, /**< reference: OMX_CONFIG_MACROBLOCKERRORMAPTYPE */ OMX_IndexConfigVideoMBErrorReporting, /**< reference: OMX_CONFIG_MBERRORREPORTINGTYPE */ OMX_IndexParamVideoMacroblocksPerFrame, /**< reference: OMX_PARAM_MACROBLOCKSTYPE */ OMX_IndexConfigVideoMacroBlockErrorMap, /**< reference: OMX_CONFIG_MACROBLOCKERRORMAPTYPE */ OMX_IndexParamVideoSliceFMO, /**< reference: OMX_VIDEO_PARAM_AVCSLICEFMO */ OMX_IndexConfigVideoAVCIntraPeriod, /**< reference: OMX_VIDEO_CONFIG_AVCINTRAPERIOD */ OMX_IndexConfigVideoNalSize, /**< reference: OMX_VIDEO_CONFIG_NALSIZE */ /* Image & Video common Configurations */ OMX_IndexCommonStartUnused = 0x07000000, OMX_IndexParamCommonDeblocking, /**< reference: OMX_PARAM_DEBLOCKINGTYPE */ OMX_IndexParamCommonSensorMode, /**< reference: OMX_PARAM_SENSORMODETYPE */ OMX_IndexParamCommonInterleave, /**< reference: OMX_PARAM_INTERLEAVETYPE */ OMX_IndexConfigCommonColorFormatConversion, /**< reference: OMX_CONFIG_COLORCONVERSIONTYPE */ OMX_IndexConfigCommonScale, /**< reference: OMX_CONFIG_SCALEFACTORTYPE */ OMX_IndexConfigCommonImageFilter, /**< reference: OMX_CONFIG_IMAGEFILTERTYPE */ OMX_IndexConfigCommonColorEnhancement, /**< reference: OMX_CONFIG_COLORENHANCEMENTTYPE */ OMX_IndexConfigCommonColorKey, /**< reference: OMX_CONFIG_COLORKEYTYPE */ OMX_IndexConfigCommonColorBlend, /**< reference: OMX_CONFIG_COLORBLENDTYPE */ OMX_IndexConfigCommonFrameStabilisation,/**< reference: OMX_CONFIG_FRAMESTABTYPE */ OMX_IndexConfigCommonRotate, /**< reference: OMX_CONFIG_ROTATIONTYPE */ OMX_IndexConfigCommonMirror, /**< reference: OMX_CONFIG_MIRRORTYPE */ OMX_IndexConfigCommonOutputPosition, /**< reference: OMX_CONFIG_POINTTYPE */ OMX_IndexConfigCommonInputCrop, /**< reference: OMX_CONFIG_RECTTYPE */ OMX_IndexConfigCommonOutputCrop, /**< reference: OMX_CONFIG_RECTTYPE */ OMX_IndexConfigCommonDigitalZoom, /**< reference: OMX_CONFIG_SCALEFACTORTYPE */ OMX_IndexConfigCommonOpticalZoom, /**< reference: OMX_CONFIG_SCALEFACTORTYPE*/ OMX_IndexConfigCommonWhiteBalance, /**< reference: OMX_CONFIG_WHITEBALCONTROLTYPE */ OMX_IndexConfigCommonExposure, /**< reference: OMX_CONFIG_EXPOSURECONTROLTYPE */ OMX_IndexConfigCommonContrast, /**< reference: OMX_CONFIG_CONTRASTTYPE */ OMX_IndexConfigCommonBrightness, /**< reference: OMX_CONFIG_BRIGHTNESSTYPE */ OMX_IndexConfigCommonBacklight, /**< reference: OMX_CONFIG_BACKLIGHTTYPE */ OMX_IndexConfigCommonGamma, /**< reference: OMX_CONFIG_GAMMATYPE */ OMX_IndexConfigCommonSaturation, /**< reference: OMX_CONFIG_SATURATIONTYPE */ OMX_IndexConfigCommonLightness, /**< reference: OMX_CONFIG_LIGHTNESSTYPE */ OMX_IndexConfigCommonExclusionRect, /**< reference: OMX_CONFIG_RECTTYPE */ OMX_IndexConfigCommonDithering, /**< reference: OMX_CONFIG_DITHERTYPE */ OMX_IndexConfigCommonPlaneBlend, /**< reference: OMX_CONFIG_PLANEBLENDTYPE */ OMX_IndexConfigCommonExposureValue, /**< reference: OMX_CONFIG_EXPOSUREVALUETYPE */ OMX_IndexConfigCommonOutputSize, /**< reference: OMX_FRAMESIZETYPE */ OMX_IndexParamCommonExtraQuantData, /**< reference: OMX_OTHER_EXTRADATATYPE */ OMX_IndexConfigCommonFocusRegion, /**< reference: OMX_CONFIG_FOCUSREGIONTYPE */ OMX_IndexConfigCommonFocusStatus, /**< reference: OMX_PARAM_FOCUSSTATUSTYPE */ OMX_IndexConfigCommonTransitionEffect, /**< reference: OMX_CONFIG_TRANSITIONEFFECTTYPE */ /* Reserved Configuration range */ OMX_IndexOtherStartUnused = 0x08000000, OMX_IndexParamOtherPortFormat, /**< reference: OMX_OTHER_PARAM_PORTFORMATTYPE */ OMX_IndexConfigOtherPower, /**< reference: OMX_OTHER_CONFIG_POWERTYPE */ OMX_IndexConfigOtherStats, /**< reference: OMX_OTHER_CONFIG_STATSTYPE */ /* Reserved Time range */ OMX_IndexTimeStartUnused = 0x09000000, OMX_IndexConfigTimeScale, /**< reference: OMX_TIME_CONFIG_SCALETYPE */ OMX_IndexConfigTimeClockState, /**< reference: OMX_TIME_CONFIG_CLOCKSTATETYPE */ OMX_IndexConfigTimeActiveRefClock, /**< reference: OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE */ OMX_IndexConfigTimeCurrentMediaTime, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (read only) */ OMX_IndexConfigTimeCurrentWallTime, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (read only) */ OMX_IndexConfigTimeCurrentAudioReference, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (write only) */ OMX_IndexConfigTimeCurrentVideoReference, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (write only) */ OMX_IndexConfigTimeMediaTimeRequest, /**< reference: OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE (write only) */ OMX_IndexConfigTimeClientStartTime, /** /** Khronos standard extension indices. This enum lists the current Khronos extension indices to OpenMAX IL. */ typedef enum OMX_INDEXEXTTYPE { /* Component parameters and configurations */ OMX_IndexExtComponentStartUnused = OMX_IndexKhronosExtensions + 0x00100000, OMX_IndexConfigCallbackRequest, /**< reference: OMX_CONFIG_CALLBACKREQUESTTYPE */ OMX_IndexConfigCommitMode, /**< reference: OMX_CONFIG_COMMITMODETYPE */ OMX_IndexConfigCommit, /**< reference: OMX_CONFIG_COMMITTYPE */ /* Port parameters and configurations */ OMX_IndexExtPortStartUnused = OMX_IndexKhronosExtensions + 0x00200000, /* Audio parameters and configurations */ OMX_IndexExtAudioStartUnused = OMX_IndexKhronosExtensions + 0x00400000, OMX_IndexParamAudioAndroidAc3, /**< reference: OMX_AUDIO_PARAM_ANDROID_AC3TYPE */ OMX_IndexParamAudioAndroidOpus, /**< reference: OMX_AUDIO_PARAM_ANDROID_OPUSTYPE */ OMX_IndexParamAudioAndroidAacPresentation, /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */ OMX_IndexParamAudioAndroidEac3, /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */ OMX_IndexParamAudioProfileQuerySupported, /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */ /* Image parameters and configurations */ OMX_IndexExtImageStartUnused = OMX_IndexKhronosExtensions + 0x00500000, /* Video parameters and configurations */ OMX_IndexExtVideoStartUnused = OMX_IndexKhronosExtensions + 0x00600000, OMX_IndexParamNalStreamFormatSupported, /**< reference: OMX_NALSTREAMFORMATTYPE */ OMX_IndexParamNalStreamFormat, /**< reference: OMX_NALSTREAMFORMATTYPE */ OMX_IndexParamNalStreamFormatSelect, /**< reference: OMX_NALSTREAMFORMATTYPE */ OMX_IndexParamVideoVp8, /**< reference: OMX_VIDEO_PARAM_VP8TYPE */ OMX_IndexConfigVideoVp8ReferenceFrame, /**< reference: OMX_VIDEO_VP8REFERENCEFRAMETYPE */ OMX_IndexConfigVideoVp8ReferenceFrameType, /**< reference: OMX_VIDEO_VP8REFERENCEFRAMEINFOTYPE */ OMX_IndexParamVideoAndroidVp8Encoder, /**< reference: OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE */ OMX_IndexParamVideoHevc, /**< reference: OMX_VIDEO_PARAM_HEVCTYPE */ OMX_IndexParamSliceSegments, /**< reference: OMX_VIDEO_SLICESEGMENTSTYPE */ OMX_IndexConfigAndroidIntraRefresh, /**< reference: OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE */ /* Image & Video common configurations */ OMX_IndexExtCommonStartUnused = OMX_IndexKhronosExtensions + 0x00700000, /* Other configurations */ OMX_IndexExtOtherStartUnused = OMX_IndexKhronosExtensions + 0x00800000, OMX_IndexConfigAutoFramerateConversion, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigPriority, /**< reference: OMX_PARAM_U32TYPE */ OMX_IndexConfigOperatingRate, /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */ OMX_IndexParamConsumerUsageBits, /**< reference: OMX_PARAM_U32TYPE */ /* Time configurations */ OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000, OMX_IndexExtMax = 0x7FFFFFFF } OMX_INDEXEXTTYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* OMX_IndexExt_h */ /* File EOF */ include/media/openmax/OMX_Other.h0100644 0000000 0000000 00000044204 13077405420 015741 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** @file OMX_Other.h - OpenMax IL version 1.1.2 * The structures needed by Other components to exchange * parameters and configuration data with the components. */ #ifndef OMX_Other_h #define OMX_Other_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header must include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** * Enumeration of possible data types which match to multiple domains or no * domain at all. For types which are vendor specific, a value above * OMX_OTHER_VENDORTSTART should be used. */ typedef enum OMX_OTHER_FORMATTYPE { OMX_OTHER_FormatTime = 0, /**< Transmission of various timestamps, elapsed time, time deltas, etc */ OMX_OTHER_FormatPower, /**< Perhaps used for enabling/disabling power management, setting clocks? */ OMX_OTHER_FormatStats, /**< Could be things such as frame rate, frames dropped, etc */ OMX_OTHER_FormatBinary, /**< Arbitrary binary data */ OMX_OTHER_FormatVendorReserved = 1000, /**< Starting value for vendor specific formats */ OMX_OTHER_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_OTHER_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_OTHER_FormatMax = 0x7FFFFFFF } OMX_OTHER_FORMATTYPE; /** * Enumeration of seek modes. */ typedef enum OMX_TIME_SEEKMODETYPE { OMX_TIME_SeekModeFast = 0, /**< Prefer seeking to an approximation * of the requested seek position over * the actual seek position if it * results in a faster seek. */ OMX_TIME_SeekModeAccurate, /**< Prefer seeking to the actual seek * position over an approximation * of the requested seek position even * if it results in a slower seek. */ OMX_TIME_SeekModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_TIME_SeekModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_TIME_SeekModeMax = 0x7FFFFFFF } OMX_TIME_SEEKMODETYPE; /* Structure representing the seekmode of the component */ typedef struct OMX_TIME_CONFIG_SEEKMODETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_TIME_SEEKMODETYPE eType; /**< The seek mode */ } OMX_TIME_CONFIG_SEEKMODETYPE; /** Structure representing a time stamp used with the following configs * on the Clock Component (CC): * * OMX_IndexConfigTimeCurrentWallTime: query of the CC's current wall * time * OMX_IndexConfigTimeCurrentMediaTime: query of the CC's current media * time * OMX_IndexConfigTimeCurrentAudioReference and * OMX_IndexConfigTimeCurrentVideoReference: audio/video reference * clock sending SC its reference time * OMX_IndexConfigTimeClientStartTime: a Clock Component client sends * this structure to the Clock Component via a SetConfig on its * client port when it receives a buffer with * OMX_BUFFERFLAG_STARTTIME set. It must use the timestamp * specified by that buffer for nStartTimestamp. * * It's also used with the following config on components in general: * * OMX_IndexConfigTimePosition: IL client querying component position * (GetConfig) or commanding a component to seek to the given location * (SetConfig) */ typedef struct OMX_TIME_CONFIG_TIMESTAMPTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version * information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_TICKS nTimestamp; /**< timestamp .*/ } OMX_TIME_CONFIG_TIMESTAMPTYPE; /** Enumeration of possible reference clocks to the media time. */ typedef enum OMX_TIME_UPDATETYPE { OMX_TIME_UpdateRequestFulfillment, /**< Update is the fulfillment of a media time request. */ OMX_TIME_UpdateScaleChanged, /**< Update was generated because the scale chagned. */ OMX_TIME_UpdateClockStateChanged, /**< Update was generated because the clock state changed. */ OMX_TIME_UpdateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_TIME_UpdateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_TIME_UpdateMax = 0x7FFFFFFF } OMX_TIME_UPDATETYPE; /** Enumeration of possible reference clocks to the media time. */ typedef enum OMX_TIME_REFCLOCKTYPE { OMX_TIME_RefClockNone, /**< Use no references. */ OMX_TIME_RefClockAudio, /**< Use references sent through OMX_IndexConfigTimeCurrentAudioReference */ OMX_TIME_RefClockVideo, /**< Use references sent through OMX_IndexConfigTimeCurrentVideoReference */ OMX_TIME_RefClockKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_TIME_RefClockVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_TIME_RefClockMax = 0x7FFFFFFF } OMX_TIME_REFCLOCKTYPE; /** Enumeration of clock states. */ typedef enum OMX_TIME_CLOCKSTATE { OMX_TIME_ClockStateRunning, /**< Clock running. */ OMX_TIME_ClockStateWaitingForStartTime, /**< Clock waiting until the * prescribed clients emit their * start time. */ OMX_TIME_ClockStateStopped, /**< Clock stopped. */ OMX_TIME_ClockStateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_TIME_ClockStateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_TIME_ClockStateMax = 0x7FFFFFFF } OMX_TIME_CLOCKSTATE; /** Structure representing a media time request to the clock component. * * A client component sends this structure to the Clock Component via a SetConfig * on its client port to specify a media timestamp the Clock Component * should emit. The Clock Component should fulfill the request by sending a * OMX_TIME_MEDIATIMETYPE when its media clock matches the requested * timestamp. * * The client may require a media time request be fulfilled slightly * earlier than the media time specified. In this case the client specifies * an offset which is equal to the difference between wall time corresponding * to the requested media time and the wall time when it will be * fulfilled. * * A client component may uses these requests and the OMX_TIME_MEDIATIMETYPE to * time events according to timestamps. If a client must perform an operation O at * a time T (e.g. deliver a video frame at its corresponding timestamp), it makes a * media time request at T (perhaps specifying an offset to ensure the request fulfillment * is a little early). When the clock component passes the resulting OMX_TIME_MEDIATIMETYPE * structure back to the client component, the client may perform operation O (perhaps having * to wait a slight amount more time itself as specified by the return values). */ typedef struct OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< port that this structure applies to */ OMX_PTR pClientPrivate; /**< Client private data to disabiguate this media time * from others (e.g. the number of the frame to deliver). * Duplicated in the media time structure that fulfills * this request. A value of zero is reserved for time scale * updates. */ OMX_TICKS nMediaTimestamp; /**< Media timestamp requested.*/ OMX_TICKS nOffset; /**< Amount of wall clock time by which this * request should be fulfilled early */ } OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE; /**< Structure sent from the clock component client either when fulfilling * a media time request or when the time scale has changed. * * In the former case the Clock Component fills this structure and times its emission * to a client component (via the client port) according to the corresponding media * time request sent by the client. The Clock Component should time the emission to occur * when the requested timestamp matches the Clock Component's media time but also the * prescribed offset early. * * Upon scale changes the clock component clears the nClientPrivate data, sends the current * media time and sets the nScale to the new scale via the client port. It emits a * OMX_TIME_MEDIATIMETYPE to all clients independent of any requests. This allows clients to * alter processing to accomodate scaling. For instance a video component might skip inter-frames * in the case of extreme fastforward. Likewise an audio component might add or remove samples * from an audio frame to scale audio data. * * It is expected that some clock components may not be able to fulfill requests * at exactly the prescribed time. This is acceptable so long as the request is * fulfilled at least as early as described and not later. This structure provides * fields the client may use to wait for the remaining time. * * The client may use either the nOffset or nWallTimeAtMedia fields to determine the * wall time until the nMediaTimestamp actually occurs. In the latter case the * client can get a more accurate value for offset by getting the current wall * from the cloc component and subtracting it from nWallTimeAtMedia. */ typedef struct OMX_TIME_MEDIATIMETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nClientPrivate; /**< Client private data to disabiguate this media time * from others. Copied from the media time request. * A value of zero is reserved for time scale updates. */ OMX_TIME_UPDATETYPE eUpdateType; /**< Reason for the update */ OMX_TICKS nMediaTimestamp; /**< Media time requested. If no media time was * requested then this is the current media time. */ OMX_TICKS nOffset; /**< Amount of wall clock time by which this * request was actually fulfilled early */ OMX_TICKS nWallTimeAtMediaTime; /**< Wall time corresponding to nMediaTimeStamp. * A client may compare this value to current * media time obtained from the Clock Component to determine * the wall time until the media timestamp is really * current. */ OMX_S32 xScale; /**< Current media time scale in Q16 format. */ OMX_TIME_CLOCKSTATE eState; /* Seeking Change. Added 7/12.*/ /**< State of the media time. */ } OMX_TIME_MEDIATIMETYPE; /** Structure representing the current media time scale factor. Applicable only to clock * component, other components see scale changes via OMX_TIME_MEDIATIMETYPE buffers sent via * the clock component client ports. Upon recieving this config the clock component changes * the rate by which the media time increases or decreases effectively implementing trick modes. */ typedef struct OMX_TIME_CONFIG_SCALETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_S32 xScale; /**< This is a value in Q16 format which is used for * scaling the media time */ } OMX_TIME_CONFIG_SCALETYPE; /** Bits used to identify a clock port. Used in OMX_TIME_CONFIG_CLOCKSTATETYPE's nWaitMask field */ #define OMX_CLOCKPORT0 0x00000001 #define OMX_CLOCKPORT1 0x00000002 #define OMX_CLOCKPORT2 0x00000004 #define OMX_CLOCKPORT3 0x00000008 #define OMX_CLOCKPORT4 0x00000010 #define OMX_CLOCKPORT5 0x00000020 #define OMX_CLOCKPORT6 0x00000040 #define OMX_CLOCKPORT7 0x00000080 /** Structure representing the current mode of the media clock. * IL Client uses this config to change or query the mode of the * media clock of the clock component. Applicable only to clock * component. * * On a SetConfig if eState is OMX_TIME_ClockStateRunning media time * starts immediately at the prescribed start time. If * OMX_TIME_ClockStateWaitingForStartTime the Clock Component ignores * the given nStartTime and waits for all clients specified in the * nWaitMask to send starttimes (via * OMX_IndexConfigTimeClientStartTime). The Clock Component then starts * the media clock using the earliest start time supplied. */ typedef struct OMX_TIME_CONFIG_CLOCKSTATETYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version * information */ OMX_TIME_CLOCKSTATE eState; /**< State of the media time. */ OMX_TICKS nStartTime; /**< Start time of the media time. */ OMX_TICKS nOffset; /**< Time to offset the media time by * (e.g. preroll). Media time will be * reported to be nOffset ticks earlier. */ OMX_U32 nWaitMask; /**< Mask of OMX_CLOCKPORT values. */ } OMX_TIME_CONFIG_CLOCKSTATETYPE; /** Structure representing the reference clock currently being used to * compute media time. IL client uses this config to change or query the * clock component's active reference clock */ typedef struct OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_TIME_REFCLOCKTYPE eClock; /**< Reference clock used to compute media time */ } OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE; /** Descriptor for setting specifics of power type. * Note: this structure is listed for backwards compatibility. */ typedef struct OMX_OTHER_CONFIG_POWERTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_BOOL bEnablePM; /**< Flag to enable Power Management */ } OMX_OTHER_CONFIG_POWERTYPE; /** Descriptor for setting specifics of stats type. * Note: this structure is listed for backwards compatibility. */ typedef struct OMX_OTHER_CONFIG_STATSTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ /* what goes here */ } OMX_OTHER_CONFIG_STATSTYPE; /** * The PortDefinition structure is used to define all of the parameters * necessary for the compliant component to setup an input or an output other * path. */ typedef struct OMX_OTHER_PORTDEFINITIONTYPE { OMX_OTHER_FORMATTYPE eFormat; /**< Type of data expected for this channel */ } OMX_OTHER_PORTDEFINITIONTYPE; /** Port format parameter. This structure is used to enumerate * the various data input/output format supported by the port. */ typedef struct OMX_OTHER_PARAM_PORTFORMATTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ OMX_U32 nPortIndex; /**< Indicates which port to set */ OMX_U32 nIndex; /**< Indicates the enumeration index for the format from 0x0 to N-1 */ OMX_OTHER_FORMATTYPE eFormat; /**< Type of data expected for this channel */ } OMX_OTHER_PARAM_PORTFORMATTYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_Types.h0100644 0000000 0000000 00000033376 13077405420 015774 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /* * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_Types.h - OpenMax IL version 1.1.2 * The OMX_Types header file contains the primitive type definitions used by * the core, the application and the component. This file may need to be * modified to be used on systems that do not have "char" set to 8 bits, * "short" set to 16 bits and "long" set to 32 bits. */ #ifndef OMX_Types_h #define OMX_Types_h #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** The OMX_API and OMX_APIENTRY are platform specific definitions used * to declare OMX function prototypes. They are modified to meet the * requirements for a particular platform */ #ifdef __SYMBIAN32__ # ifdef __OMX_EXPORTS # define OMX_API __declspec(dllexport) # else # ifdef _WIN32 # define OMX_API __declspec(dllexport) # else # define OMX_API __declspec(dllimport) # endif # endif #else # ifdef _WIN32 # ifdef __OMX_EXPORTS # define OMX_API __declspec(dllexport) # else //# define OMX_API __declspec(dllimport) #define OMX_API # endif # else # ifdef __OMX_EXPORTS # define OMX_API # else # define OMX_API extern # endif # endif #endif #ifndef OMX_APIENTRY #define OMX_APIENTRY #endif /** OMX_IN is used to identify inputs to an OMX function. This designation will also be used in the case of a pointer that points to a parameter that is used as an output. */ #ifndef OMX_IN #define OMX_IN #endif /** OMX_OUT is used to identify outputs from an OMX function. This designation will also be used in the case of a pointer that points to a parameter that is used as an input. */ #ifndef OMX_OUT #define OMX_OUT #endif /** OMX_INOUT is used to identify parameters that may be either inputs or outputs from an OMX function at the same time. This designation will also be used in the case of a pointer that points to a parameter that is used both as an input and an output. */ #ifndef OMX_INOUT #define OMX_INOUT #endif /** OMX_ALL is used to as a wildcard to select all entities of the same type * when specifying the index, or referring to a object by an index. (i.e. * use OMX_ALL to indicate all N channels). When used as a port index * for a config or parameter this OMX_ALL denotes that the config or * parameter applies to the entire component not just one port. */ #define OMX_ALL 0xFFFFFFFF /** In the following we define groups that help building doxygen documentation */ /** @defgroup core OpenMAX IL core * Functions and structure related to the OMX IL core */ /** @defgroup comp OpenMAX IL component * Functions and structure related to the OMX IL component */ /** @defgroup rpm Resource and Policy Management * Structures for resource and policy management of components */ /** @defgroup buf Buffer Management * Buffer handling functions and structures */ /** @defgroup tun Tunneling * @ingroup core comp * Structures and functions to manage tunnels among component ports */ /** @defgroup cp Content Pipes * @ingroup core */ /** @defgroup metadata Metadata handling * */ /** OMX_U8 is an 8 bit unsigned quantity that is byte aligned */ typedef unsigned char OMX_U8; /** OMX_S8 is an 8 bit signed quantity that is byte aligned */ typedef signed char OMX_S8; /** OMX_U16 is a 16 bit unsigned quantity that is 16 bit word aligned */ typedef unsigned short OMX_U16; /** OMX_S16 is a 16 bit signed quantity that is 16 bit word aligned */ typedef signed short OMX_S16; /** OMX_U32 is a 32 bit unsigned quantity that is 32 bit word aligned */ typedef uint32_t OMX_U32; /** OMX_S32 is a 32 bit signed quantity that is 32 bit word aligned */ typedef int32_t OMX_S32; /* Users with compilers that cannot accept the "long long" designation should define the OMX_SKIP64BIT macro. It should be noted that this may cause some components to fail to compile if the component was written to require 64 bit integral types. However, these components would NOT compile anyway since the compiler does not support the way the component was written. */ #ifndef OMX_SKIP64BIT #ifdef __SYMBIAN32__ /** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */ typedef unsigned long long OMX_U64; /** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */ typedef signed long long OMX_S64; #elif defined(WIN32) /** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */ typedef unsigned __int64 OMX_U64; /** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */ typedef signed __int64 OMX_S64; #else /* WIN32 */ /** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */ typedef unsigned long long OMX_U64; /** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */ typedef signed long long OMX_S64; #endif /* WIN32 */ #endif /** The OMX_BOOL type is intended to be used to represent a true or a false value when passing parameters to and from the OMX core and components. The OMX_BOOL is a 32 bit quantity and is aligned on a 32 bit word boundary. */ typedef enum OMX_BOOL { OMX_FALSE = 0, OMX_TRUE = !OMX_FALSE, OMX_BOOL_MAX = 0x7FFFFFFF } OMX_BOOL; /* * Temporary Android 64 bit modification * * #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS * overrides all OMX pointer types to be uint32_t. * * After this change, OMX codecs will work in 32 bit only, so 64 bit processes * must communicate to a remote 32 bit process for OMX to work. */ #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS typedef uint32_t OMX_PTR; typedef OMX_PTR OMX_STRING; typedef OMX_PTR OMX_BYTE; #else /* OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS */ /** The OMX_PTR type is intended to be used to pass pointers between the OMX applications and the OMX Core and components. This is a 32 bit pointer and is aligned on a 32 bit boundary. */ typedef void* OMX_PTR; /** The OMX_STRING type is intended to be used to pass "C" type strings between the application and the core and component. The OMX_STRING type is a 32 bit pointer to a zero terminated string. The pointer is word aligned and the string is byte aligned. */ typedef char* OMX_STRING; /** The OMX_BYTE type is intended to be used to pass arrays of bytes such as buffers between the application and the component and core. The OMX_BYTE type is a 32 bit pointer to a zero terminated string. The pointer is word aligned and the string is byte aligned. */ typedef unsigned char* OMX_BYTE; #endif /* OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS */ /** OMX_UUIDTYPE is a very long unique identifier to uniquely identify at runtime. This identifier should be generated by a component in a way that guarantees that every instance of the identifier running on the system is unique. */ typedef unsigned char OMX_UUIDTYPE[128]; /** The OMX_DIRTYPE enumeration is used to indicate if a port is an input or an output port. This enumeration is common across all component types. */ typedef enum OMX_DIRTYPE { OMX_DirInput, /**< Port is an input port */ OMX_DirOutput, /**< Port is an output port */ OMX_DirMax = 0x7FFFFFFF } OMX_DIRTYPE; /** The OMX_ENDIANTYPE enumeration is used to indicate the bit ordering for numerical data (i.e. big endian, or little endian). */ typedef enum OMX_ENDIANTYPE { OMX_EndianBig, /**< big endian */ OMX_EndianLittle, /**< little endian */ OMX_EndianMax = 0x7FFFFFFF } OMX_ENDIANTYPE; /** The OMX_NUMERICALDATATYPE enumeration is used to indicate if data is signed, unsigned or floating point (Android extension). Android floating point support policy: If component does not support floating point raw audio, it can reset configuration to signed 16-bit integer (support for which is required.) nBitsPerSample will be set to 32 for float data. */ typedef enum OMX_NUMERICALDATATYPE { OMX_NumericalDataSigned, /**< signed data */ OMX_NumericalDataUnsigned, /**< unsigned data */ OMX_NumericalDataFloat = 0x7F000001, /**< floating point data */ OMX_NumercialDataMax = 0x7FFFFFFF } OMX_NUMERICALDATATYPE; /** Unsigned bounded value type */ typedef struct OMX_BU32 { OMX_U32 nValue; /**< actual value */ OMX_U32 nMin; /**< minimum for value (i.e. nValue >= nMin) */ OMX_U32 nMax; /**< maximum for value (i.e. nValue <= nMax) */ } OMX_BU32; /** Signed bounded value type */ typedef struct OMX_BS32 { OMX_S32 nValue; /**< actual value */ OMX_S32 nMin; /**< minimum for value (i.e. nValue >= nMin) */ OMX_S32 nMax; /**< maximum for value (i.e. nValue <= nMax) */ } OMX_BS32; /** Structure representing some time or duration in microseconds. This structure * must be interpreted as a signed 64 bit value. The quantity is signed to accommodate * negative deltas and preroll scenarios. The quantity is represented in microseconds * to accomodate high resolution timestamps (e.g. DVD presentation timestamps based * on a 90kHz clock) and to allow more accurate and synchronized delivery (e.g. * individual audio samples delivered at 192 kHz). The quantity is 64 bit to * accommodate a large dynamic range (signed 32 bit values would allow only for plus * or minus 35 minutes). * * Implementations with limited precision may convert the signed 64 bit value to * a signed 32 bit value internally but risk loss of precision. */ #ifndef OMX_SKIP64BIT typedef OMX_S64 OMX_TICKS; #else typedef struct OMX_TICKS { OMX_U32 nLowPart; /** low bits of the signed 64 bit tick value */ OMX_U32 nHighPart; /** high bits of the signed 64 bit tick value */ } OMX_TICKS; #endif #define OMX_TICKS_PER_SECOND 1000000 /** Define the public interface for the OMX Handle. The core will not use this value internally, but the application should only use this value. */ typedef OMX_PTR OMX_HANDLETYPE; typedef struct OMX_MARKTYPE { OMX_HANDLETYPE hMarkTargetComponent; /**< The component that will generate a mark event upon processing the mark. */ OMX_PTR pMarkData; /**< Application specific data associated with the mark sent on a mark event to disambiguate this mark from others. */ } OMX_MARKTYPE; /** OMX_NATIVE_DEVICETYPE is used to map a OMX video port to the * platform & operating specific object used to reference the display * or can be used by a audio port for native audio rendering */ typedef OMX_PTR OMX_NATIVE_DEVICETYPE; /** OMX_NATIVE_WINDOWTYPE is used to map a OMX video port to the * platform & operating specific object used to reference the window */ typedef OMX_PTR OMX_NATIVE_WINDOWTYPE; /** The OMX_VERSIONTYPE union is used to specify the version for a structure or component. For a component, the version is entirely specified by the component vendor. Components doing the same function from different vendors may or may not have the same version. For structures, the version shall be set by the entity that allocates the structure. For structures specified in the OMX 1.1 specification, the value of the version shall be set to 1.1.0.0 in all cases. Access to the OMX_VERSIONTYPE can be by a single 32 bit access (e.g. by nVersion) or by accessing one of the structure elements to, for example, check only the Major revision. */ typedef union OMX_VERSIONTYPE { struct { OMX_U8 nVersionMajor; /**< Major version accessor element */ OMX_U8 nVersionMinor; /**< Minor version accessor element */ OMX_U8 nRevision; /**< Revision version accessor element */ OMX_U8 nStep; /**< Step version accessor element */ } s; OMX_U32 nVersion; /**< 32 bit value to make accessing the version easily done in a single word size copy/compare operation */ } OMX_VERSIONTYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_Video.h0100644 0000000 0000000 00000126725 13077405420 015737 0ustar000000000 0000000 /* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * 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. * ------------------------------------------------------------------- */ /** * Copyright (c) 2008 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** * @file OMX_Video.h - OpenMax IL version 1.1.2 * The structures is needed by Video components to exchange parameters * and configuration data with OMX components. */ #ifndef OMX_Video_h #define OMX_Video_h /** @defgroup video OpenMAX IL Video Domain * @ingroup iv * Structures for OpenMAX IL Video domain * @{ */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Each OMX header must include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** * Enumeration used to define the possible video compression codings. * NOTE: This essentially refers to file extensions. If the coding is * being used to specify the ENCODE type, then additional work * must be done to configure the exact flavor of the compression * to be used. For decode cases where the user application can * not differentiate between MPEG-4 and H.264 bit streams, it is * up to the codec to handle this. */ typedef enum OMX_VIDEO_CODINGTYPE { OMX_VIDEO_CodingUnused, /**< Value when coding is N/A */ OMX_VIDEO_CodingAutoDetect, /**< Autodetection of coding type */ OMX_VIDEO_CodingMPEG2, /**< AKA: H.262 */ OMX_VIDEO_CodingH263, /**< H.263 */ OMX_VIDEO_CodingMPEG4, /**< MPEG-4 */ OMX_VIDEO_CodingWMV, /**< all versions of Windows Media Video */ OMX_VIDEO_CodingRV, /**< all versions of Real Video */ OMX_VIDEO_CodingAVC, /**< H.264/AVC */ OMX_VIDEO_CodingMJPEG, /**< Motion JPEG */ OMX_VIDEO_CodingVP8, /**< Google VP8, formerly known as On2 VP8 */ OMX_VIDEO_CodingVP9, /**< Google VP9 */ OMX_VIDEO_CodingHEVC, /**< ITU H.265/HEVC */ OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */ OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_CodingMax = 0x7FFFFFFF } OMX_VIDEO_CODINGTYPE; /** * Data structure used to define a video path. The number of Video paths for * input and output will vary by type of the Video component. * * Input (aka Source) : zero Inputs, one Output, * Splitter : one Input, 2 or more Outputs, * Processing Element : one Input, one output, * Mixer : 2 or more inputs, one output, * Output (aka Sink) : one Input, zero outputs. * * The PortDefinition structure is used to define all of the parameters * necessary for the compliant component to setup an input or an output video * path. If additional vendor specific data is required, it should be * transmitted to the component using the CustomCommand function. Compliant * components will prepopulate this structure with optimal values during the * GetDefaultInitParams command. * * STRUCT MEMBERS: * cMIMEType : MIME type of data for the port * pNativeRender : Platform specific reference for a display if a * sync, otherwise this field is 0 * nFrameWidth : Width of frame to be used on channel if * uncompressed format is used. Use 0 for unknown, * don't care or variable * nFrameHeight : Height of frame to be used on channel if * uncompressed format is used. Use 0 for unknown, * don't care or variable * nStride : Number of bytes per span of an image * (i.e. indicates the number of bytes to get * from span N to span N+1, where negative stride * indicates the image is bottom up * nSliceHeight : Height used when encoding in slices * nBitrate : Bit rate of frame to be used on channel if * compressed format is used. Use 0 for unknown, * don't care or variable * xFramerate : Frame rate to be used on channel if uncompressed * format is used. Use 0 for unknown, don't care or * variable. Units are Q16 frames per second. * bFlagErrorConcealment : Turns on error concealment if it is supported by * the OMX component * eCompressionFormat : Compression format used in this instance of the * component. When OMX_VIDEO_CodingUnused is * specified, eColorFormat is used * eColorFormat : Decompressed format used by this component * pNativeWindow : Platform specific reference for a window object if a * display sink , otherwise this field is 0x0. */ typedef struct OMX_VIDEO_PORTDEFINITIONTYPE { OMX_STRING cMIMEType; OMX_NATIVE_DEVICETYPE pNativeRender; OMX_U32 nFrameWidth; OMX_U32 nFrameHeight; OMX_S32 nStride; OMX_U32 nSliceHeight; OMX_U32 nBitrate; OMX_U32 xFramerate; OMX_BOOL bFlagErrorConcealment; OMX_VIDEO_CODINGTYPE eCompressionFormat; OMX_COLOR_FORMATTYPE eColorFormat; OMX_NATIVE_WINDOWTYPE pNativeWindow; } OMX_VIDEO_PORTDEFINITIONTYPE; /** * Port format parameter. This structure is used to enumerate the various * data input/output format supported by the port. * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Indicates which port to set * nIndex : Indicates the enumeration index for the format from * 0x0 to N-1 * eCompressionFormat : Compression format used in this instance of the * component. When OMX_VIDEO_CodingUnused is specified, * eColorFormat is used * eColorFormat : Decompressed format used by this component * xFrameRate : Indicates the video frame rate in Q16 format */ typedef struct OMX_VIDEO_PARAM_PORTFORMATTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nIndex; OMX_VIDEO_CODINGTYPE eCompressionFormat; OMX_COLOR_FORMATTYPE eColorFormat; OMX_U32 xFramerate; } OMX_VIDEO_PARAM_PORTFORMATTYPE; /** * This is a structure for configuring video compression quantization * parameter values. Codecs may support different QP values for different * frame types. * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version info * nPortIndex : Port that this structure applies to * nQpI : QP value to use for index frames * nQpP : QP value to use for P frames * nQpB : QP values to use for bidirectional frames */ typedef struct OMX_VIDEO_PARAM_QUANTIZATIONTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nQpI; OMX_U32 nQpP; OMX_U32 nQpB; } OMX_VIDEO_PARAM_QUANTIZATIONTYPE; /** * Structure for configuration of video fast update parameters. * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version info * nPortIndex : Port that this structure applies to * bEnableVFU : Enable/Disable video fast update * nFirstGOB : Specifies the number of the first macroblock row * nFirstMB : specifies the first MB relative to the specified first GOB * nNumMBs : Specifies the number of MBs to be refreshed from nFirstGOB * and nFirstMB */ typedef struct OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bEnableVFU; OMX_U32 nFirstGOB; OMX_U32 nFirstMB; OMX_U32 nNumMBs; } OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE; /** * Enumeration of possible bitrate control types */ typedef enum OMX_VIDEO_CONTROLRATETYPE { OMX_Video_ControlRateDisable, OMX_Video_ControlRateVariable, OMX_Video_ControlRateConstant, OMX_Video_ControlRateVariableSkipFrames, OMX_Video_ControlRateConstantSkipFrames, OMX_Video_ControlRateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_Video_ControlRateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_Video_ControlRateMax = 0x7FFFFFFF } OMX_VIDEO_CONTROLRATETYPE; /** * Structure for configuring bitrate mode of a codec. * * STRUCT MEMBERS: * nSize : Size of the struct in bytes * nVersion : OMX spec version info * nPortIndex : Port that this struct applies to * eControlRate : Control rate type enum * nTargetBitrate : Target bitrate to encode with */ typedef struct OMX_VIDEO_PARAM_BITRATETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_CONTROLRATETYPE eControlRate; OMX_U32 nTargetBitrate; } OMX_VIDEO_PARAM_BITRATETYPE; /** * Enumeration of possible motion vector (MV) types */ typedef enum OMX_VIDEO_MOTIONVECTORTYPE { OMX_Video_MotionVectorPixel, OMX_Video_MotionVectorHalfPel, OMX_Video_MotionVectorQuarterPel, OMX_Video_MotionVectorEighthPel, OMX_Video_MotionVectorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_Video_MotionVectorVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_Video_MotionVectorMax = 0x7FFFFFFF } OMX_VIDEO_MOTIONVECTORTYPE; /** * Structure for configuring the number of motion vectors used as well * as their accuracy. * * STRUCT MEMBERS: * nSize : Size of the struct in bytes * nVersion : OMX spec version info * nPortIndex : port that this structure applies to * eAccuracy : Enumerated MV accuracy * bUnrestrictedMVs : Allow unrestricted MVs * bFourMV : Allow use of 4 MVs * sXSearchRange : Search range in horizontal direction for MVs * sYSearchRange : Search range in vertical direction for MVs */ typedef struct OMX_VIDEO_PARAM_MOTIONVECTORTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_MOTIONVECTORTYPE eAccuracy; OMX_BOOL bUnrestrictedMVs; OMX_BOOL bFourMV; OMX_S32 sXSearchRange; OMX_S32 sYSearchRange; } OMX_VIDEO_PARAM_MOTIONVECTORTYPE; /** * Enumeration of possible methods to use for Intra Refresh */ typedef enum OMX_VIDEO_INTRAREFRESHTYPE { OMX_VIDEO_IntraRefreshCyclic, OMX_VIDEO_IntraRefreshAdaptive, OMX_VIDEO_IntraRefreshBoth, OMX_VIDEO_IntraRefreshKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_IntraRefreshVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_IntraRefreshMax = 0x7FFFFFFF } OMX_VIDEO_INTRAREFRESHTYPE; /** * Structure for configuring intra refresh mode * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eRefreshMode : Cyclic, Adaptive, or Both * nAirMBs : Number of intra macroblocks to refresh in a frame when * AIR is enabled * nAirRef : Number of times a motion marked macroblock has to be * intra coded * nCirMBs : Number of consecutive macroblocks to be coded as "intra" * when CIR is enabled */ typedef struct OMX_VIDEO_PARAM_INTRAREFRESHTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_INTRAREFRESHTYPE eRefreshMode; OMX_U32 nAirMBs; OMX_U32 nAirRef; OMX_U32 nCirMBs; } OMX_VIDEO_PARAM_INTRAREFRESHTYPE; /** * Structure for enabling various error correction methods for video * compression. * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * bEnableHEC : Enable/disable header extension codes (HEC) * bEnableResync : Enable/disable resynchronization markers * nResynchMarkerSpacing : Resynch markers interval (in bits) to be * applied in the stream * bEnableDataPartitioning : Enable/disable data partitioning * bEnableRVLC : Enable/disable reversible variable length * coding */ typedef struct OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bEnableHEC; OMX_BOOL bEnableResync; OMX_U32 nResynchMarkerSpacing; OMX_BOOL bEnableDataPartitioning; OMX_BOOL bEnableRVLC; } OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE; /** * Configuration of variable block-size motion compensation (VBSMC) * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * b16x16 : Enable inter block search 16x16 * b16x8 : Enable inter block search 16x8 * b8x16 : Enable inter block search 8x16 * b8x8 : Enable inter block search 8x8 * b8x4 : Enable inter block search 8x4 * b4x8 : Enable inter block search 4x8 * b4x4 : Enable inter block search 4x4 */ typedef struct OMX_VIDEO_PARAM_VBSMCTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL b16x16; OMX_BOOL b16x8; OMX_BOOL b8x16; OMX_BOOL b8x8; OMX_BOOL b8x4; OMX_BOOL b4x8; OMX_BOOL b4x4; } OMX_VIDEO_PARAM_VBSMCTYPE; /** * H.263 profile types, each profile indicates support for various * performance bounds and different annexes. * * ENUMS: * Baseline : Baseline Profile: H.263 (V1), no optional modes * H320 Coding : H.320 Coding Efficiency Backward Compatibility * Profile: H.263+ (V2), includes annexes I, J, L.4 * and T * BackwardCompatible : Backward Compatibility Profile: H.263 (V1), * includes annex F * ISWV2 : Interactive Streaming Wireless Profile: H.263+ * (V2), includes annexes I, J, K and T * ISWV3 : Interactive Streaming Wireless Profile: H.263++ * (V3), includes profile 3 and annexes V and W.6.3.8 * HighCompression : Conversational High Compression Profile: H.263++ * (V3), includes profiles 1 & 2 and annexes D and U * Internet : Conversational Internet Profile: H.263++ (V3), * includes profile 5 and annex K * Interlace : Conversational Interlace Profile: H.263++ (V3), * includes profile 5 and annex W.6.3.11 * HighLatency : High Latency Profile: H.263++ (V3), includes * profile 6 and annexes O.1 and P.5 */ typedef enum OMX_VIDEO_H263PROFILETYPE { OMX_VIDEO_H263ProfileBaseline = 0x01, OMX_VIDEO_H263ProfileH320Coding = 0x02, OMX_VIDEO_H263ProfileBackwardCompatible = 0x04, OMX_VIDEO_H263ProfileISWV2 = 0x08, OMX_VIDEO_H263ProfileISWV3 = 0x10, OMX_VIDEO_H263ProfileHighCompression = 0x20, OMX_VIDEO_H263ProfileInternet = 0x40, OMX_VIDEO_H263ProfileInterlace = 0x80, OMX_VIDEO_H263ProfileHighLatency = 0x100, OMX_VIDEO_H263ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_H263ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_H263ProfileMax = 0x7FFFFFFF } OMX_VIDEO_H263PROFILETYPE; /** * H.263 level types, each level indicates support for various frame sizes, * bit rates, decoder frame rates. */ typedef enum OMX_VIDEO_H263LEVELTYPE { OMX_VIDEO_H263Level10 = 0x01, OMX_VIDEO_H263Level20 = 0x02, OMX_VIDEO_H263Level30 = 0x04, OMX_VIDEO_H263Level40 = 0x08, OMX_VIDEO_H263Level45 = 0x10, OMX_VIDEO_H263Level50 = 0x20, OMX_VIDEO_H263Level60 = 0x40, OMX_VIDEO_H263Level70 = 0x80, OMX_VIDEO_H263LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_H263LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_H263LevelMax = 0x7FFFFFFF } OMX_VIDEO_H263LEVELTYPE; /** * Specifies the picture type. These values should be OR'd to signal all * pictures types which are allowed. * * ENUMS: * Generic Picture Types: I, P and B * H.263 Specific Picture Types: SI and SP * H.264 Specific Picture Types: EI and EP * MPEG-4 Specific Picture Types: S */ typedef enum OMX_VIDEO_PICTURETYPE { OMX_VIDEO_PictureTypeI = 0x01, OMX_VIDEO_PictureTypeP = 0x02, OMX_VIDEO_PictureTypeB = 0x04, OMX_VIDEO_PictureTypeSI = 0x08, OMX_VIDEO_PictureTypeSP = 0x10, OMX_VIDEO_PictureTypeEI = 0x11, OMX_VIDEO_PictureTypeEP = 0x12, OMX_VIDEO_PictureTypeS = 0x14, OMX_VIDEO_PictureTypeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_PictureTypeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_PictureTypeMax = 0x7FFFFFFF } OMX_VIDEO_PICTURETYPE; /** * H.263 Params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nPFrames : Number of P frames between each I frame * nBFrames : Number of B frames between each I frame * eProfile : H.263 profile(s) to use * eLevel : H.263 level(s) to use * bPLUSPTYPEAllowed : Indicating that it is allowed to use PLUSPTYPE * (specified in the 1998 version of H.263) to * indicate custom picture sizes or clock * frequencies * nAllowedPictureTypes : Specifies the picture types allowed in the * bitstream * bForceRoundingTypeToZero : value of the RTYPE bit (bit 6 of MPPTYPE) is * not constrained. It is recommended to change * the value of the RTYPE bit for each reference * picture in error-free communication * nPictureHeaderRepetition : Specifies the frequency of picture header * repetition * nGOBHeaderInterval : Specifies the interval of non-empty GOB * headers in units of GOBs */ typedef struct OMX_VIDEO_PARAM_H263TYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nPFrames; OMX_U32 nBFrames; OMX_VIDEO_H263PROFILETYPE eProfile; OMX_VIDEO_H263LEVELTYPE eLevel; OMX_BOOL bPLUSPTYPEAllowed; OMX_U32 nAllowedPictureTypes; OMX_BOOL bForceRoundingTypeToZero; OMX_U32 nPictureHeaderRepetition; OMX_U32 nGOBHeaderInterval; } OMX_VIDEO_PARAM_H263TYPE; /** * MPEG-2 profile types, each profile indicates support for various * performance bounds and different annexes. */ typedef enum OMX_VIDEO_MPEG2PROFILETYPE { OMX_VIDEO_MPEG2ProfileSimple = 0, /**< Simple Profile */ OMX_VIDEO_MPEG2ProfileMain, /**< Main Profile */ OMX_VIDEO_MPEG2Profile422, /**< 4:2:2 Profile */ OMX_VIDEO_MPEG2ProfileSNR, /**< SNR Profile */ OMX_VIDEO_MPEG2ProfileSpatial, /**< Spatial Profile */ OMX_VIDEO_MPEG2ProfileHigh, /**< High Profile */ OMX_VIDEO_MPEG2ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_MPEG2ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_MPEG2ProfileMax = 0x7FFFFFFF } OMX_VIDEO_MPEG2PROFILETYPE; /** * MPEG-2 level types, each level indicates support for various frame * sizes, bit rates, decoder frame rates. No need */ typedef enum OMX_VIDEO_MPEG2LEVELTYPE { OMX_VIDEO_MPEG2LevelLL = 0, /**< Low Level */ OMX_VIDEO_MPEG2LevelML, /**< Main Level */ OMX_VIDEO_MPEG2LevelH14, /**< High 1440 */ OMX_VIDEO_MPEG2LevelHL, /**< High Level */ OMX_VIDEO_MPEG2LevelHP, /**< HighP Level */ OMX_VIDEO_MPEG2LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_MPEG2LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_MPEG2LevelMax = 0x7FFFFFFF } OMX_VIDEO_MPEG2LEVELTYPE; /** * MPEG-2 params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nPFrames : Number of P frames between each I frame * nBFrames : Number of B frames between each I frame * eProfile : MPEG-2 profile(s) to use * eLevel : MPEG-2 levels(s) to use */ typedef struct OMX_VIDEO_PARAM_MPEG2TYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nPFrames; OMX_U32 nBFrames; OMX_VIDEO_MPEG2PROFILETYPE eProfile; OMX_VIDEO_MPEG2LEVELTYPE eLevel; } OMX_VIDEO_PARAM_MPEG2TYPE; /** * MPEG-4 profile types, each profile indicates support for various * performance bounds and different annexes. * * ENUMS: * - Simple Profile, Levels 1-3 * - Simple Scalable Profile, Levels 1-2 * - Core Profile, Levels 1-2 * - Main Profile, Levels 2-4 * - N-bit Profile, Level 2 * - Scalable Texture Profile, Level 1 * - Simple Face Animation Profile, Levels 1-2 * - Simple Face and Body Animation (FBA) Profile, Levels 1-2 * - Basic Animated Texture Profile, Levels 1-2 * - Hybrid Profile, Levels 1-2 * - Advanced Real Time Simple Profiles, Levels 1-4 * - Core Scalable Profile, Levels 1-3 * - Advanced Coding Efficiency Profile, Levels 1-4 * - Advanced Core Profile, Levels 1-2 * - Advanced Scalable Texture, Levels 2-3 */ typedef enum OMX_VIDEO_MPEG4PROFILETYPE { OMX_VIDEO_MPEG4ProfileSimple = 0x01, OMX_VIDEO_MPEG4ProfileSimpleScalable = 0x02, OMX_VIDEO_MPEG4ProfileCore = 0x04, OMX_VIDEO_MPEG4ProfileMain = 0x08, OMX_VIDEO_MPEG4ProfileNbit = 0x10, OMX_VIDEO_MPEG4ProfileScalableTexture = 0x20, OMX_VIDEO_MPEG4ProfileSimpleFace = 0x40, OMX_VIDEO_MPEG4ProfileSimpleFBA = 0x80, OMX_VIDEO_MPEG4ProfileBasicAnimated = 0x100, OMX_VIDEO_MPEG4ProfileHybrid = 0x200, OMX_VIDEO_MPEG4ProfileAdvancedRealTime = 0x400, OMX_VIDEO_MPEG4ProfileCoreScalable = 0x800, OMX_VIDEO_MPEG4ProfileAdvancedCoding = 0x1000, OMX_VIDEO_MPEG4ProfileAdvancedCore = 0x2000, OMX_VIDEO_MPEG4ProfileAdvancedScalable = 0x4000, OMX_VIDEO_MPEG4ProfileAdvancedSimple = 0x8000, OMX_VIDEO_MPEG4ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_MPEG4ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_MPEG4ProfileMax = 0x7FFFFFFF } OMX_VIDEO_MPEG4PROFILETYPE; /** * MPEG-4 level types, each level indicates support for various frame * sizes, bit rates, decoder frame rates. No need */ typedef enum OMX_VIDEO_MPEG4LEVELTYPE { OMX_VIDEO_MPEG4Level0 = 0x01, /**< Level 0 */ OMX_VIDEO_MPEG4Level0b = 0x02, /**< Level 0b */ OMX_VIDEO_MPEG4Level1 = 0x04, /**< Level 1 */ OMX_VIDEO_MPEG4Level2 = 0x08, /**< Level 2 */ OMX_VIDEO_MPEG4Level3 = 0x10, /**< Level 3 */ /* normally levels are powers of 2s, but 3b was missed and levels must be properly ordered */ OMX_VIDEO_MPEG4Level3b = 0x18, /**< Level 3a */ OMX_VIDEO_MPEG4Level4 = 0x20, /**< Level 4 */ OMX_VIDEO_MPEG4Level4a = 0x40, /**< Level 4a */ OMX_VIDEO_MPEG4Level5 = 0x80, /**< Level 5 */ OMX_VIDEO_MPEG4Level6 = 0x100, /**< Level 6 */ OMX_VIDEO_MPEG4LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_MPEG4LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_MPEG4LevelMax = 0x7FFFFFFF } OMX_VIDEO_MPEG4LEVELTYPE; /** * MPEG-4 configuration. This structure handles configuration options * which are specific to MPEG4 algorithms * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nSliceHeaderSpacing : Number of macroblocks between slice header (H263+ * Annex K). Put zero if not used * bSVH : Enable Short Video Header mode * bGov : Flag to enable GOV * nPFrames : Number of P frames between each I frame (also called * GOV period) * nBFrames : Number of B frames between each I frame * nIDCVLCThreshold : Value of intra DC VLC threshold * bACPred : Flag to use ac prediction * nMaxPacketSize : Maximum size of packet in bytes. * nTimeIncRes : Used to pass VOP time increment resolution for MPEG4. * Interpreted as described in MPEG4 standard. * eProfile : MPEG-4 profile(s) to use. * eLevel : MPEG-4 level(s) to use. * nAllowedPictureTypes : Specifies the picture types allowed in the bitstream * nHeaderExtension : Specifies the number of consecutive video packet * headers within a VOP * bReversibleVLC : Specifies whether reversible variable length coding * is in use */ typedef struct OMX_VIDEO_PARAM_MPEG4TYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nSliceHeaderSpacing; OMX_BOOL bSVH; OMX_BOOL bGov; OMX_U32 nPFrames; OMX_U32 nBFrames; OMX_U32 nIDCVLCThreshold; OMX_BOOL bACPred; OMX_U32 nMaxPacketSize; OMX_U32 nTimeIncRes; OMX_VIDEO_MPEG4PROFILETYPE eProfile; OMX_VIDEO_MPEG4LEVELTYPE eLevel; OMX_U32 nAllowedPictureTypes; OMX_U32 nHeaderExtension; OMX_BOOL bReversibleVLC; } OMX_VIDEO_PARAM_MPEG4TYPE; /** * WMV Versions */ typedef enum OMX_VIDEO_WMVFORMATTYPE { OMX_VIDEO_WMVFormatUnused = 0x01, /**< Format unused or unknown */ OMX_VIDEO_WMVFormat7 = 0x02, /**< Windows Media Video format 7 */ OMX_VIDEO_WMVFormat8 = 0x04, /**< Windows Media Video format 8 */ OMX_VIDEO_WMVFormat9 = 0x08, /**< Windows Media Video format 9 */ OMX_VIDEO_WMFFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_WMFFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_WMVFormatMax = 0x7FFFFFFF } OMX_VIDEO_WMVFORMATTYPE; /** * WMV Params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eFormat : Version of WMV stream / data */ typedef struct OMX_VIDEO_PARAM_WMVTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_WMVFORMATTYPE eFormat; } OMX_VIDEO_PARAM_WMVTYPE; /** * Real Video Version */ typedef enum OMX_VIDEO_RVFORMATTYPE { OMX_VIDEO_RVFormatUnused = 0, /**< Format unused or unknown */ OMX_VIDEO_RVFormat8, /**< Real Video format 8 */ OMX_VIDEO_RVFormat9, /**< Real Video format 9 */ OMX_VIDEO_RVFormatG2, /**< Real Video Format G2 */ OMX_VIDEO_RVFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_RVFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_RVFormatMax = 0x7FFFFFFF } OMX_VIDEO_RVFORMATTYPE; /** * Real Video Params * * STUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * eFormat : Version of RV stream / data * nBitsPerPixel : Bits per pixel coded in the frame * nPaddedWidth : Padded width in pixel of a video frame * nPaddedHeight : Padded Height in pixels of a video frame * nFrameRate : Rate of video in frames per second * nBitstreamFlags : Flags which internal information about the bitstream * nBitstreamVersion : Bitstream version * nMaxEncodeFrameSize: Max encoded frame size * bEnablePostFilter : Turn on/off post filter * bEnableTemporalInterpolation : Turn on/off temporal interpolation * bEnableLatencyMode : When enabled, the decoder does not display a decoded * frame until it has detected that no enhancement layer * frames or dependent B frames will be coming. This * detection usually occurs when a subsequent non-B * frame is encountered */ typedef struct OMX_VIDEO_PARAM_RVTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_RVFORMATTYPE eFormat; OMX_U16 nBitsPerPixel; OMX_U16 nPaddedWidth; OMX_U16 nPaddedHeight; OMX_U32 nFrameRate; OMX_U32 nBitstreamFlags; OMX_U32 nBitstreamVersion; OMX_U32 nMaxEncodeFrameSize; OMX_BOOL bEnablePostFilter; OMX_BOOL bEnableTemporalInterpolation; OMX_BOOL bEnableLatencyMode; } OMX_VIDEO_PARAM_RVTYPE; /** * AVC profile types, each profile indicates support for various * performance bounds and different annexes. */ typedef enum OMX_VIDEO_AVCPROFILETYPE { OMX_VIDEO_AVCProfileBaseline = 0x01, /**< Baseline profile */ OMX_VIDEO_AVCProfileMain = 0x02, /**< Main profile */ OMX_VIDEO_AVCProfileExtended = 0x04, /**< Extended profile */ OMX_VIDEO_AVCProfileHigh = 0x08, /**< High profile */ OMX_VIDEO_AVCProfileHigh10 = 0x10, /**< High 10 profile */ OMX_VIDEO_AVCProfileHigh422 = 0x20, /**< High 4:2:2 profile */ OMX_VIDEO_AVCProfileHigh444 = 0x40, /**< High 4:4:4 profile */ OMX_VIDEO_AVCProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_AVCProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_AVCProfileMax = 0x7FFFFFFF } OMX_VIDEO_AVCPROFILETYPE; /** * AVC level types, each level indicates support for various frame sizes, * bit rates, decoder frame rates. No need */ typedef enum OMX_VIDEO_AVCLEVELTYPE { OMX_VIDEO_AVCLevel1 = 0x01, /**< Level 1 */ OMX_VIDEO_AVCLevel1b = 0x02, /**< Level 1b */ OMX_VIDEO_AVCLevel11 = 0x04, /**< Level 1.1 */ OMX_VIDEO_AVCLevel12 = 0x08, /**< Level 1.2 */ OMX_VIDEO_AVCLevel13 = 0x10, /**< Level 1.3 */ OMX_VIDEO_AVCLevel2 = 0x20, /**< Level 2 */ OMX_VIDEO_AVCLevel21 = 0x40, /**< Level 2.1 */ OMX_VIDEO_AVCLevel22 = 0x80, /**< Level 2.2 */ OMX_VIDEO_AVCLevel3 = 0x100, /**< Level 3 */ OMX_VIDEO_AVCLevel31 = 0x200, /**< Level 3.1 */ OMX_VIDEO_AVCLevel32 = 0x400, /**< Level 3.2 */ OMX_VIDEO_AVCLevel4 = 0x800, /**< Level 4 */ OMX_VIDEO_AVCLevel41 = 0x1000, /**< Level 4.1 */ OMX_VIDEO_AVCLevel42 = 0x2000, /**< Level 4.2 */ OMX_VIDEO_AVCLevel5 = 0x4000, /**< Level 5 */ OMX_VIDEO_AVCLevel51 = 0x8000, /**< Level 5.1 */ OMX_VIDEO_AVCLevel52 = 0x10000, /**< Level 5.2 */ OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF } OMX_VIDEO_AVCLEVELTYPE; /** * AVC loop filter modes * * OMX_VIDEO_AVCLoopFilterEnable : Enable * OMX_VIDEO_AVCLoopFilterDisable : Disable * OMX_VIDEO_AVCLoopFilterDisableSliceBoundary : Disabled on slice boundaries */ typedef enum OMX_VIDEO_AVCLOOPFILTERTYPE { OMX_VIDEO_AVCLoopFilterEnable = 0, OMX_VIDEO_AVCLoopFilterDisable, OMX_VIDEO_AVCLoopFilterDisableSliceBoundary, OMX_VIDEO_AVCLoopFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_AVCLoopFilterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_AVCLoopFilterMax = 0x7FFFFFFF } OMX_VIDEO_AVCLOOPFILTERTYPE; /** * AVC params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nSliceHeaderSpacing : Number of macroblocks between slice header, put * zero if not used * nPFrames : Number of P frames between each I frame * nBFrames : Number of B frames between each I frame * bUseHadamard : Enable/disable Hadamard transform * nRefFrames : Max number of reference frames to use for inter * motion search (1-16) * nRefIdxTrailing : Pic param set ref frame index (index into ref * frame buffer of trailing frames list), B frame * support * nRefIdxForward : Pic param set ref frame index (index into ref * frame buffer of forward frames list), B frame * support * bEnableUEP : Enable/disable unequal error protection. This * is only valid of data partitioning is enabled. * bEnableFMO : Enable/disable flexible macroblock ordering * bEnableASO : Enable/disable arbitrary slice ordering * bEnableRS : Enable/disable sending of redundant slices * eProfile : AVC profile(s) to use * eLevel : AVC level(s) to use * nAllowedPictureTypes : Specifies the picture types allowed in the * bitstream * bFrameMBsOnly : specifies that every coded picture of the * coded video sequence is a coded frame * containing only frame macroblocks * bMBAFF : Enable/disable switching between frame and * field macroblocks within a picture * bEntropyCodingCABAC : Entropy decoding method to be applied for the * syntax elements for which two descriptors appear * in the syntax tables * bWeightedPPrediction : Enable/disable weighted prediction shall not * be applied to P and SP slices * nWeightedBipredicitonMode : Default weighted prediction is applied to B * slices * bconstIpred : Enable/disable intra prediction * bDirect8x8Inference : Specifies the method used in the derivation * process for luma motion vectors for B_Skip, * B_Direct_16x16 and B_Direct_8x8 as specified * in subclause 8.4.1.2 of the AVC spec * bDirectSpatialTemporal : Flag indicating spatial or temporal direct * mode used in B slice coding (related to * bDirect8x8Inference) . Spatial direct mode is * more common and should be the default. * nCabacInitIdx : Index used to init CABAC contexts * eLoopFilterMode : Enable/disable loop filter */ typedef struct OMX_VIDEO_PARAM_AVCTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nSliceHeaderSpacing; OMX_U32 nPFrames; OMX_U32 nBFrames; OMX_BOOL bUseHadamard; OMX_U32 nRefFrames; OMX_U32 nRefIdx10ActiveMinus1; OMX_U32 nRefIdx11ActiveMinus1; OMX_BOOL bEnableUEP; OMX_BOOL bEnableFMO; OMX_BOOL bEnableASO; OMX_BOOL bEnableRS; OMX_VIDEO_AVCPROFILETYPE eProfile; OMX_VIDEO_AVCLEVELTYPE eLevel; OMX_U32 nAllowedPictureTypes; OMX_BOOL bFrameMBsOnly; OMX_BOOL bMBAFF; OMX_BOOL bEntropyCodingCABAC; OMX_BOOL bWeightedPPrediction; OMX_U32 nWeightedBipredicitonMode; OMX_BOOL bconstIpred ; OMX_BOOL bDirect8x8Inference; OMX_BOOL bDirectSpatialTemporal; OMX_U32 nCabacInitIdc; OMX_VIDEO_AVCLOOPFILTERTYPE eLoopFilterMode; } OMX_VIDEO_PARAM_AVCTYPE; typedef struct OMX_VIDEO_PARAM_PROFILELEVELTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 eProfile; /**< type is OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, or OMX_VIDEO_MPEG4PROFILETYPE depending on context */ OMX_U32 eLevel; /**< type is OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE, or OMX_VIDEO_MPEG4PROFILETYPE depending on context */ OMX_U32 nProfileIndex; /**< Used to query for individual profile support information, This parameter is valid only for OMX_IndexParamVideoProfileLevelQuerySupported index, For all other indices this parameter is to be ignored. */ } OMX_VIDEO_PARAM_PROFILELEVELTYPE; /** * Structure for dynamically configuring bitrate mode of a codec. * * STRUCT MEMBERS: * nSize : Size of the struct in bytes * nVersion : OMX spec version info * nPortIndex : Port that this struct applies to * nEncodeBitrate : Target average bitrate to be generated in bps */ typedef struct OMX_VIDEO_CONFIG_BITRATETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nEncodeBitrate; } OMX_VIDEO_CONFIG_BITRATETYPE; /** * Defines Encoder Frame Rate setting * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * xEncodeFramerate : Encoding framerate represented in Q16 format */ typedef struct OMX_CONFIG_FRAMERATETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 xEncodeFramerate; /* Q16 format */ } OMX_CONFIG_FRAMERATETYPE; typedef struct OMX_CONFIG_INTRAREFRESHVOPTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL IntraRefreshVOP; } OMX_CONFIG_INTRAREFRESHVOPTYPE; typedef struct OMX_CONFIG_MACROBLOCKERRORMAPTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nErrMapSize; /* Size of the Error Map in bytes */ OMX_U8 ErrMap[1]; /* Error map hint */ } OMX_CONFIG_MACROBLOCKERRORMAPTYPE; typedef struct OMX_CONFIG_MBERRORREPORTINGTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bEnabled; } OMX_CONFIG_MBERRORREPORTINGTYPE; typedef struct OMX_PARAM_MACROBLOCKSTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nMacroblocks; } OMX_PARAM_MACROBLOCKSTYPE; /** * AVC Slice Mode modes * * OMX_VIDEO_SLICEMODE_AVCDefault : Normal frame encoding, one slice per frame * OMX_VIDEO_SLICEMODE_AVCMBSlice : NAL mode, number of MBs per frame * OMX_VIDEO_SLICEMODE_AVCByteSlice : NAL mode, number of bytes per frame */ typedef enum OMX_VIDEO_AVCSLICEMODETYPE { OMX_VIDEO_SLICEMODE_AVCDefault = 0, OMX_VIDEO_SLICEMODE_AVCMBSlice, OMX_VIDEO_SLICEMODE_AVCByteSlice, OMX_VIDEO_SLICEMODE_AVCKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_SLICEMODE_AVCVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_SLICEMODE_AVCLevelMax = 0x7FFFFFFF } OMX_VIDEO_AVCSLICEMODETYPE; /** * AVC FMO Slice Mode Params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nNumSliceGroups : Specifies the number of slice groups * nSliceGroupMapType : Specifies the type of slice groups * eSliceMode : Specifies the type of slice */ typedef struct OMX_VIDEO_PARAM_AVCSLICEFMO { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U8 nNumSliceGroups; OMX_U8 nSliceGroupMapType; OMX_VIDEO_AVCSLICEMODETYPE eSliceMode; } OMX_VIDEO_PARAM_AVCSLICEFMO; /** * AVC IDR Period Configs * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nIDRPeriod : Specifies periodicity of IDR frames * nPFrames : Specifies internal of coding Intra frames */ typedef struct OMX_VIDEO_CONFIG_AVCINTRAPERIOD { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nIDRPeriod; OMX_U32 nPFrames; } OMX_VIDEO_CONFIG_AVCINTRAPERIOD; /** * AVC NAL Size Configs * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nNaluBytes : Specifies the NAL unit size */ typedef struct OMX_VIDEO_CONFIG_NALSIZE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nNaluBytes; } OMX_VIDEO_CONFIG_NALSIZE; /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* File EOF */ include/media/openmax/OMX_VideoExt.h0100644 0000000 0000000 00000026210 13077405420 016404 0ustar000000000 0000000 /* * Copyright (c) 2010 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** OMX_VideoExt.h - OpenMax IL version 1.1.2 * The OMX_VideoExt header file contains extensions to the * definitions used by both the application and the component to * access video items. */ #ifndef OMX_VideoExt_h #define OMX_VideoExt_h #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Each OMX header shall include all required header files to allow the * header to compile without errors. The includes below are required * for this header file to compile successfully */ #include /** NALU Formats */ typedef enum OMX_NALUFORMATSTYPE { OMX_NaluFormatStartCodes = 1, OMX_NaluFormatOneNaluPerBuffer = 2, OMX_NaluFormatOneByteInterleaveLength = 4, OMX_NaluFormatTwoByteInterleaveLength = 8, OMX_NaluFormatFourByteInterleaveLength = 16, OMX_NaluFormatCodingMax = 0x7FFFFFFF } OMX_NALUFORMATSTYPE; /** NAL Stream Format */ typedef struct OMX_NALSTREAMFORMATTYPE{ OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_NALUFORMATSTYPE eNaluFormat; } OMX_NALSTREAMFORMATTYPE; /** VP8 profiles */ typedef enum OMX_VIDEO_VP8PROFILETYPE { OMX_VIDEO_VP8ProfileMain = 0x01, OMX_VIDEO_VP8ProfileUnknown = 0x6EFFFFFF, OMX_VIDEO_VP8ProfileMax = 0x7FFFFFFF } OMX_VIDEO_VP8PROFILETYPE; /** VP8 levels */ typedef enum OMX_VIDEO_VP8LEVELTYPE { OMX_VIDEO_VP8Level_Version0 = 0x01, OMX_VIDEO_VP8Level_Version1 = 0x02, OMX_VIDEO_VP8Level_Version2 = 0x04, OMX_VIDEO_VP8Level_Version3 = 0x08, OMX_VIDEO_VP8LevelUnknown = 0x6EFFFFFF, OMX_VIDEO_VP8LevelMax = 0x7FFFFFFF } OMX_VIDEO_VP8LEVELTYPE; /** VP9 profiles */ typedef enum OMX_VIDEO_VP9PROFILETYPE { OMX_VIDEO_VP9Profile0 = 0x1, OMX_VIDEO_VP9Profile1 = 0x2, OMX_VIDEO_VP9Profile2 = 0x4, OMX_VIDEO_VP9Profile3 = 0x8, // HDR profiles also support passing HDR metadata OMX_VIDEO_VP9Profile2HDR = 0x1000, OMX_VIDEO_VP9Profile3HDR = 0x2000, OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF, OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF } OMX_VIDEO_VP9PROFILETYPE; /** VP9 levels */ typedef enum OMX_VIDEO_VP9LEVELTYPE { OMX_VIDEO_VP9Level1 = 0x1, OMX_VIDEO_VP9Level11 = 0x2, OMX_VIDEO_VP9Level2 = 0x4, OMX_VIDEO_VP9Level21 = 0x8, OMX_VIDEO_VP9Level3 = 0x10, OMX_VIDEO_VP9Level31 = 0x20, OMX_VIDEO_VP9Level4 = 0x40, OMX_VIDEO_VP9Level41 = 0x80, OMX_VIDEO_VP9Level5 = 0x100, OMX_VIDEO_VP9Level51 = 0x200, OMX_VIDEO_VP9Level52 = 0x400, OMX_VIDEO_VP9Level6 = 0x800, OMX_VIDEO_VP9Level61 = 0x1000, OMX_VIDEO_VP9Level62 = 0x2000, OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF, OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF } OMX_VIDEO_VP9LEVELTYPE; /** VP8 Param */ typedef struct OMX_VIDEO_PARAM_VP8TYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_VP8PROFILETYPE eProfile; OMX_VIDEO_VP8LEVELTYPE eLevel; OMX_U32 nDCTPartitions; OMX_BOOL bErrorResilientMode; } OMX_VIDEO_PARAM_VP8TYPE; /** Structure for configuring VP8 reference frames */ typedef struct OMX_VIDEO_VP8REFERENCEFRAMETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bPreviousFrameRefresh; OMX_BOOL bGoldenFrameRefresh; OMX_BOOL bAlternateFrameRefresh; OMX_BOOL bUsePreviousFrame; OMX_BOOL bUseGoldenFrame; OMX_BOOL bUseAlternateFrame; } OMX_VIDEO_VP8REFERENCEFRAMETYPE; /** Structure for querying VP8 reference frame type */ typedef struct OMX_VIDEO_VP8REFERENCEFRAMEINFOTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bIsIntraFrame; OMX_BOOL bIsGoldenOrAlternateFrame; } OMX_VIDEO_VP8REFERENCEFRAMEINFOTYPE; /** Maximum number of VP8 temporal layers */ #define OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS 3 /** VP8 temporal layer patterns */ typedef enum OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE { OMX_VIDEO_VPXTemporalLayerPatternNone = 0, OMX_VIDEO_VPXTemporalLayerPatternWebRTC = 1, OMX_VIDEO_VPXTemporalLayerPatternMax = 0x7FFFFFFF } OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE; /** * Android specific VP8 encoder params * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nKeyFrameInterval : Key frame interval in frames * eTemporalPattern : Type of temporal layer pattern * nTemporalLayerCount : Number of temporal coding layers * nTemporalLayerBitrateRatio : Bitrate ratio allocation between temporal * streams in percentage * nMinQuantizer : Minimum (best quality) quantizer * nMaxQuantizer : Maximum (worst quality) quantizer */ typedef struct OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nKeyFrameInterval; OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE eTemporalPattern; OMX_U32 nTemporalLayerCount; OMX_U32 nTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS]; OMX_U32 nMinQuantizer; OMX_U32 nMaxQuantizer; } OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE; /** HEVC Profile enum type */ typedef enum OMX_VIDEO_HEVCPROFILETYPE { OMX_VIDEO_HEVCProfileUnknown = 0x0, OMX_VIDEO_HEVCProfileMain = 0x1, OMX_VIDEO_HEVCProfileMain10 = 0x2, // Main10 profile with HDR SEI support. OMX_VIDEO_HEVCProfileMain10HDR10 = 0x1000, OMX_VIDEO_HEVCProfileMax = 0x7FFFFFFF } OMX_VIDEO_HEVCPROFILETYPE; /** HEVC Level enum type */ typedef enum OMX_VIDEO_HEVCLEVELTYPE { OMX_VIDEO_HEVCLevelUnknown = 0x0, OMX_VIDEO_HEVCMainTierLevel1 = 0x1, OMX_VIDEO_HEVCHighTierLevel1 = 0x2, OMX_VIDEO_HEVCMainTierLevel2 = 0x4, OMX_VIDEO_HEVCHighTierLevel2 = 0x8, OMX_VIDEO_HEVCMainTierLevel21 = 0x10, OMX_VIDEO_HEVCHighTierLevel21 = 0x20, OMX_VIDEO_HEVCMainTierLevel3 = 0x40, OMX_VIDEO_HEVCHighTierLevel3 = 0x80, OMX_VIDEO_HEVCMainTierLevel31 = 0x100, OMX_VIDEO_HEVCHighTierLevel31 = 0x200, OMX_VIDEO_HEVCMainTierLevel4 = 0x400, OMX_VIDEO_HEVCHighTierLevel4 = 0x800, OMX_VIDEO_HEVCMainTierLevel41 = 0x1000, OMX_VIDEO_HEVCHighTierLevel41 = 0x2000, OMX_VIDEO_HEVCMainTierLevel5 = 0x4000, OMX_VIDEO_HEVCHighTierLevel5 = 0x8000, OMX_VIDEO_HEVCMainTierLevel51 = 0x10000, OMX_VIDEO_HEVCHighTierLevel51 = 0x20000, OMX_VIDEO_HEVCMainTierLevel52 = 0x40000, OMX_VIDEO_HEVCHighTierLevel52 = 0x80000, OMX_VIDEO_HEVCMainTierLevel6 = 0x100000, OMX_VIDEO_HEVCHighTierLevel6 = 0x200000, OMX_VIDEO_HEVCMainTierLevel61 = 0x400000, OMX_VIDEO_HEVCHighTierLevel61 = 0x800000, OMX_VIDEO_HEVCMainTierLevel62 = 0x1000000, OMX_VIDEO_HEVCHighTierLevel62 = 0x2000000, OMX_VIDEO_HEVCHighTiermax = 0x7FFFFFFF } OMX_VIDEO_HEVCLEVELTYPE; /** Structure for controlling HEVC video encoding */ typedef struct OMX_VIDEO_PARAM_HEVCTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_HEVCPROFILETYPE eProfile; OMX_VIDEO_HEVCLEVELTYPE eLevel; OMX_U32 nKeyFrameInterval; } OMX_VIDEO_PARAM_HEVCTYPE; /** Structure to define if dependent slice segments should be used */ typedef struct OMX_VIDEO_SLICESEGMENTSTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BOOL bDepedentSegments; OMX_BOOL bEnableLoopFilterAcrossSlices; } OMX_VIDEO_SLICESEGMENTSTYPE; /** Structure to return timestamps of rendered output frames as well as EOS * for tunneled components. */ typedef struct OMX_VIDEO_RENDEREVENTTYPE { OMX_S64 nMediaTimeUs; // timestamp of rendered video frame OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered // Use INT64_MAX for nMediaTimeUs to signal that the EOS // has been reached. In this case, nSystemTimeNs MUST be // the system time when the last frame was rendered. // This MUST be done in addition to returning (and // following) the render information for the last frame. } OMX_VIDEO_RENDEREVENTTYPE; /** Dolby Vision Profile enum type */ typedef enum OMX_VIDEO_DOLBYVISIONPROFILETYPE { OMX_VIDEO_DolbyVisionProfileUnknown = 0x0, OMX_VIDEO_DolbyVisionProfileDvavPer = 0x1, OMX_VIDEO_DolbyVisionProfileDvavPen = 0x2, OMX_VIDEO_DolbyVisionProfileDvheDer = 0x4, OMX_VIDEO_DolbyVisionProfileDvheDen = 0x8, OMX_VIDEO_DolbyVisionProfileDvheDtr = 0x10, OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20, OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40, OMX_VIDEO_DolbyVisionProfileDvheDtb = 0x80, OMX_VIDEO_DolbyVisionProfileMax = 0x7FFFFFFF } OMX_VIDEO_DOLBYVISIONPROFILETYPE; /** Dolby Vision Level enum type */ typedef enum OMX_VIDEO_DOLBYVISIONLEVELTYPE { OMX_VIDEO_DolbyVisionLevelUnknown = 0x0, OMX_VIDEO_DolbyVisionLevelHd24 = 0x1, OMX_VIDEO_DolbyVisionLevelHd30 = 0x2, OMX_VIDEO_DolbyVisionLevelFhd24 = 0x4, OMX_VIDEO_DolbyVisionLevelFhd30 = 0x8, OMX_VIDEO_DolbyVisionLevelFhd60 = 0x10, OMX_VIDEO_DolbyVisionLevelUhd24 = 0x20, OMX_VIDEO_DolbyVisionLevelUhd30 = 0x40, OMX_VIDEO_DolbyVisionLevelUhd48 = 0x80, OMX_VIDEO_DolbyVisionLevelUhd60 = 0x100, OMX_VIDEO_DolbyVisionLevelmax = 0x7FFFFFFF } OMX_VIDEO_DOLBYVISIONLEVELTYPE; /** * Structure for configuring video compression intra refresh period * * STRUCT MEMBERS: * nSize : Size of the structure in bytes * nVersion : OMX specification version information * nPortIndex : Port that this structure applies to * nRefreshPeriod : Intra refreh period in frames. Value 0 means disable intra refresh */ typedef struct OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_U32 nRefreshPeriod; } OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* OMX_VideoExt_h */ /* File EOF */ include/powermanager/0040755 0000000 0000000 00000000000 13077405420 013724 5ustar000000000 0000000 include/powermanager/IPowerManager.h0100644 0000000 0000000 00000007137 13077405420 016602 0ustar000000000 0000000 /* * 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_IPOWERMANAGER_H #define ANDROID_IPOWERMANAGER_H #include #include #include namespace android { // ---------------------------------------------------------------------------- class IPowerManager : public IInterface { public: // These transaction IDs must be kept in sync with the method order from // IPowerManager.aidl. enum { ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION, ACQUIRE_WAKE_LOCK_UID = IBinder::FIRST_CALL_TRANSACTION + 1, RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 2, UPDATE_WAKE_LOCK_UIDS = IBinder::FIRST_CALL_TRANSACTION + 3, POWER_HINT = IBinder::FIRST_CALL_TRANSACTION + 4, UPDATE_WAKE_LOCK_SOURCE = IBinder::FIRST_CALL_TRANSACTION + 5, IS_WAKE_LOCK_LEVEL_SUPPORTED = IBinder::FIRST_CALL_TRANSACTION + 6, USER_ACTIVITY = IBinder::FIRST_CALL_TRANSACTION + 7, WAKE_UP = IBinder::FIRST_CALL_TRANSACTION + 8, GO_TO_SLEEP = IBinder::FIRST_CALL_TRANSACTION + 9, NAP = IBinder::FIRST_CALL_TRANSACTION + 10, IS_INTERACTIVE = IBinder::FIRST_CALL_TRANSACTION + 11, IS_POWER_SAVE_MODE = IBinder::FIRST_CALL_TRANSACTION + 12, SET_POWER_SAVE_MODE = IBinder::FIRST_CALL_TRANSACTION + 13, REBOOT = IBinder::FIRST_CALL_TRANSACTION + 14, SHUTDOWN = IBinder::FIRST_CALL_TRANSACTION + 15, CRASH = IBinder::FIRST_CALL_TRANSACTION + 16, }; DECLARE_META_INTERFACE(PowerManager); // The parcels created by these methods must be kept in sync with the // corresponding methods from IPowerManager.aidl. // FIXME remove the bool isOneWay parameters as they are not oneway in the .aidl virtual status_t acquireWakeLock(int flags, const sp& lock, const String16& tag, const String16& packageName, bool isOneWay = false) = 0; virtual status_t acquireWakeLockWithUid(int flags, const sp& lock, const String16& tag, const String16& packageName, int uid, bool isOneWay = false) = 0; virtual status_t releaseWakeLock(const sp& lock, int flags, bool isOneWay = false) = 0; virtual status_t updateWakeLockUids(const sp& lock, int len, const int *uids, bool isOneWay = false) = 0; virtual status_t powerHint(int hintId, int data) = 0; virtual status_t goToSleep(int64_t event_time_ms, int reason, int flags) = 0; virtual status_t reboot(bool confirm, const String16& reason, bool wait) = 0; virtual status_t shutdown(bool confirm, const String16& reason, bool wait) = 0; virtual status_t crash(const String16& message) = 0; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_IPOWERMANAGER_H include/powermanager/PowerManager.h0100644 0000000 0000000 00000002233 13077405420 016461 0ustar000000000 0000000 /* * 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_POWERMANAGER_H #define ANDROID_POWERMANAGER_H namespace android { // must be kept in sync with definitions in PowerManager.java enum { POWERMANAGER_PARTIAL_WAKE_LOCK = 1, // equals PowerManager.PARTIAL_WAKE_LOCK constant }; enum { USER_ACTIVITY_EVENT_OTHER = 0, USER_ACTIVITY_EVENT_BUTTON = 1, USER_ACTIVITY_EVENT_TOUCH = 2, USER_ACTIVITY_EVENT_ACCESSIBILITY = 3, USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code. }; }; // namespace android #endif // ANDROID_POWERMANAGER_H include/private/0040755 0000000 0000000 00000000000 13077405420 012707 5ustar000000000 0000000 include/private/binder/0040755 0000000 0000000 00000000000 13077405420 014152 5ustar000000000 0000000 include/private/binder/Static.h0100644 0000000 0000000 00000002407 13077405420 015552 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ // All static variables go here, to control initialization and // destruction order in the library. #include #include #include #include #include #include namespace android { // For TextStream.cpp extern Vector gTextBuffers; // For ProcessState.cpp extern Mutex gProcessMutex; extern sp gProcess; // For IServiceManager.cpp extern Mutex gDefaultServiceManagerLock; extern sp gDefaultServiceManager; extern sp gPermissionController; } // namespace android include/private/binder/binder_module.h0100644 0000000 0000000 00000001621 13077405420 017130 0ustar000000000 0000000 /* * Copyright (C) 2008 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 _BINDER_MODULE_H_ #define _BINDER_MODULE_H_ #ifdef __cplusplus namespace android { #endif /* obtain structures and constants from the kernel header */ #include #include #ifdef __cplusplus } // namespace android #endif #endif // _BINDER_MODULE_H_ include/private/gui/0040755 0000000 0000000 00000000000 13077405420 013473 5ustar000000000 0000000 include/private/gui/ComposerService.h0100644 0000000 0000000 00000003706 13077405420 016757 0ustar000000000 0000000 /* * 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_PRIVATE_GUI_COMPOSER_SERVICE_H #define ANDROID_PRIVATE_GUI_COMPOSER_SERVICE_H #include #include #include #include namespace android { // --------------------------------------------------------------------------- class IMemoryHeap; class ISurfaceComposer; // --------------------------------------------------------------------------- // This holds our connection to the composer service (i.e. SurfaceFlinger). // If the remote side goes away, we will re-establish the connection. // Users of this class should not retain the value from // getComposerService() for an extended period. // // (It's not clear that using Singleton is useful here anymore.) class ComposerService : public Singleton { sp mComposerService; sp mDeathObserver; Mutex mLock; ComposerService(); void connectLocked(); void composerServiceDied(); friend class Singleton; public: // Get a connection to the Composer Service. This will block until // a connection is established. static sp getComposerService(); }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_PRIVATE_GUI_COMPOSER_SERVICE_H include/private/gui/LayerState.h0100644 0000000 0000000 00000010227 13077405420 015720 0ustar000000000 0000000 /* * Copyright (C) 2008 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_SF_LAYER_STATE_H #define ANDROID_SF_LAYER_STATE_H #include #include #include #include #include namespace android { class Parcel; class ISurfaceComposerClient; /* * Used to communicate layer information between SurfaceFlinger and its clients. */ struct layer_state_t { enum { eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java eLayerOpaque = 0x02, // SURFACE_OPAQUE eLayerSecure = 0x80, // SECURE }; enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, eSizeChanged = 0x00000004, eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, eCropChanged = 0x00000100, eDeferTransaction = 0x00000200, eFinalCropChanged = 0x00000400, eOverrideScalingModeChanged = 0x00000800, ePositionAppliesWithResize = 0x00001000, }; layer_state_t() : what(0), x(0), y(0), z(0), w(0), h(0), layerStack(0), alpha(0), flags(0), mask(0), reserved(0), crop(Rect::INVALID_RECT), finalCrop(Rect::INVALID_RECT), frameNumber(0), overrideScalingMode(-1) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; } status_t write(Parcel& output) const; status_t read(const Parcel& input); struct matrix22_t { float dsdx; float dtdx; float dsdy; float dtdy; }; sp surface; uint32_t what; float x; float y; uint32_t z; uint32_t w; uint32_t h; uint32_t layerStack; float alpha; uint8_t flags; uint8_t mask; uint8_t reserved; matrix22_t matrix; Rect crop; Rect finalCrop; sp handle; uint64_t frameNumber; int32_t overrideScalingMode; // non POD must be last. see write/read Region transparentRegion; }; struct ComposerState { sp client; layer_state_t state; status_t write(Parcel& output) const; status_t read(const Parcel& input); }; struct DisplayState { enum { eOrientationDefault = 0, eOrientation90 = 1, eOrientation180 = 2, eOrientation270 = 3, eOrientationUnchanged = 4, eOrientationSwapMask = 0x01 }; enum { eSurfaceChanged = 0x01, eLayerStackChanged = 0x02, eDisplayProjectionChanged = 0x04, eDisplaySizeChanged = 0x08 }; DisplayState(); uint32_t what; sp token; sp surface; uint32_t layerStack; uint32_t orientation; Rect viewport; Rect frame; uint32_t width, height; status_t write(Parcel& output) const; status_t read(const Parcel& input); }; }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H include/private/gui/SyncFeatures.h0100644 0000000 0000000 00000002507 13077405420 016260 0ustar000000000 0000000 /* * Copyright (C) 2013 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_GUI_SYNC_FEATURES_H #define ANDROID_GUI_SYNC_FEATURES_H #include #include namespace android { // ---------------------------------------------------------------------------- class SyncFeatures : public Singleton { friend class Singleton; bool mHasNativeFenceSync; bool mHasFenceSync; bool mHasWaitSync; String8 mString; SyncFeatures(); public: bool useNativeFenceSync() const; bool useFenceSync() const; bool useWaitSync() const; String8 toString() const; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GUI_SYNC_FEATURES_H include/private/ui/0040755 0000000 0000000 00000000000 13077405420 013324 5ustar000000000 0000000 include/private/ui/RegionHelper.h0100644 0000000 0000000 00000022542 13077405420 016062 0ustar000000000 0000000 /* * Copyright (C) 2009 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_UI_PRIVATE_REGION_HELPER_H #define ANDROID_UI_PRIVATE_REGION_HELPER_H #include #include namespace android { // ---------------------------------------------------------------------------- template class region_operator { public: typedef typename RECT::value_type TYPE; static const TYPE max_value = 0x7FFFFFF; /* * Common boolean operations: * value is computed as 0b101 op 0b110 * other boolean operation are possible, simply compute * their corresponding value with the above formulae and use * it when instantiating a region_operator. */ static const uint32_t LHS = 0x5; // 0b101 static const uint32_t RHS = 0x6; // 0b110 enum { op_nand = LHS & ~RHS, op_and = LHS & RHS, op_or = LHS | RHS, op_xor = LHS ^ RHS }; struct region { RECT const* rects; size_t count; TYPE dx; TYPE dy; inline region(const region& rhs) : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { } inline region(RECT const* r, size_t c) : rects(r), count(c), dx(), dy() { } inline region(RECT const* r, size_t c, TYPE dx, TYPE dy) : rects(r), count(c), dx(dx), dy(dy) { } }; class region_rasterizer { friend class region_operator; virtual void operator()(const RECT& rect) = 0; public: virtual ~region_rasterizer() { }; }; inline region_operator(int op, const region& lhs, const region& rhs) : op_mask(op), spanner(lhs, rhs) { } void operator()(region_rasterizer& rasterizer) { RECT current(Rect::EMPTY_RECT); do { SpannerInner spannerInner(spanner.lhs, spanner.rhs); int inside = spanner.next(current.top, current.bottom); spannerInner.prepare(inside); do { TYPE left, right; int inside = spannerInner.next(current.left, current.right); if ((op_mask >> inside) & 1) { if (current.left < current.right && current.top < current.bottom) { rasterizer(current); } } } while(!spannerInner.isDone()); } while(!spanner.isDone()); } private: uint32_t op_mask; class SpannerBase { public: SpannerBase() : lhs_head(max_value), lhs_tail(max_value), rhs_head(max_value), rhs_tail(max_value) { } enum { lhs_before_rhs = 0, lhs_after_rhs = 1, lhs_coincide_rhs = 2 }; protected: TYPE lhs_head; TYPE lhs_tail; TYPE rhs_head; TYPE rhs_tail; inline int next(TYPE& head, TYPE& tail, bool& more_lhs, bool& more_rhs) { int inside; more_lhs = false; more_rhs = false; if (lhs_head < rhs_head) { inside = lhs_before_rhs; head = lhs_head; if (lhs_tail <= rhs_head) { tail = lhs_tail; more_lhs = true; } else { lhs_head = rhs_head; tail = rhs_head; } } else if (rhs_head < lhs_head) { inside = lhs_after_rhs; head = rhs_head; if (rhs_tail <= lhs_head) { tail = rhs_tail; more_rhs = true; } else { rhs_head = lhs_head; tail = lhs_head; } } else { inside = lhs_coincide_rhs; head = lhs_head; if (lhs_tail <= rhs_tail) { tail = rhs_head = lhs_tail; more_lhs = true; } if (rhs_tail <= lhs_tail) { tail = lhs_head = rhs_tail; more_rhs = true; } } return inside; } }; class Spanner : protected SpannerBase { friend class region_operator; region lhs; region rhs; public: inline Spanner(const region& lhs, const region& rhs) : lhs(lhs), rhs(rhs) { if (lhs.count) { SpannerBase::lhs_head = lhs.rects->top + lhs.dy; SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy; } if (rhs.count) { SpannerBase::rhs_head = rhs.rects->top + rhs.dy; SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy; } } inline bool isDone() const { return !rhs.count && !lhs.count; } inline int next(TYPE& top, TYPE& bottom) { bool more_lhs = false; bool more_rhs = false; int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs); if (more_lhs) { advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail); } if (more_rhs) { advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail); } return inside; } private: static inline void advance(region& reg, TYPE& aTop, TYPE& aBottom) { // got to next span size_t count = reg.count; RECT const * rects = reg.rects; RECT const * const end = rects + count; const int top = rects->top; while (rects != end && rects->top == top) { rects++; count--; } if (rects != end) { aTop = rects->top + reg.dy; aBottom = rects->bottom + reg.dy; } else { aTop = max_value; aBottom = max_value; } reg.rects = rects; reg.count = count; } }; class SpannerInner : protected SpannerBase { region lhs; region rhs; public: inline SpannerInner(const region& lhs, const region& rhs) : lhs(lhs), rhs(rhs) { } inline void prepare(int inside) { if (inside == SpannerBase::lhs_before_rhs) { if (lhs.count) { SpannerBase::lhs_head = lhs.rects->left + lhs.dx; SpannerBase::lhs_tail = lhs.rects->right + lhs.dx; } SpannerBase::rhs_head = max_value; SpannerBase::rhs_tail = max_value; } else if (inside == SpannerBase::lhs_after_rhs) { SpannerBase::lhs_head = max_value; SpannerBase::lhs_tail = max_value; if (rhs.count) { SpannerBase::rhs_head = rhs.rects->left + rhs.dx; SpannerBase::rhs_tail = rhs.rects->right + rhs.dx; } } else { if (lhs.count) { SpannerBase::lhs_head = lhs.rects->left + lhs.dx; SpannerBase::lhs_tail = lhs.rects->right + lhs.dx; } if (rhs.count) { SpannerBase::rhs_head = rhs.rects->left + rhs.dx; SpannerBase::rhs_tail = rhs.rects->right + rhs.dx; } } } inline bool isDone() const { return SpannerBase::lhs_head == max_value && SpannerBase::rhs_head == max_value; } inline int next(TYPE& left, TYPE& right) { bool more_lhs = false; bool more_rhs = false; int inside = SpannerBase::next(left, right, more_lhs, more_rhs); if (more_lhs) { advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail); } if (more_rhs) { advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail); } return inside; } private: static inline void advance(region& reg, TYPE& left, TYPE& right) { if (reg.rects && reg.count) { const int cur_span_top = reg.rects->top; reg.rects++; reg.count--; if (!reg.count || reg.rects->top != cur_span_top) { left = max_value; right = max_value; } else { left = reg.rects->left + reg.dx; right = reg.rects->right + reg.dx; } } } }; Spanner spanner; }; // ---------------------------------------------------------------------------- }; #endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */ include/ui/0040755 0000000 0000000 00000000000 13077405420 011652 5ustar000000000 0000000 include/ui/ANativeObjectBase.h0100644 0000000 0000000 00000005770 13077405420 015302 0ustar000000000 0000000 /* * Copyright (C) 2009 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_ANDROID_NATIVES_H #define ANDROID_ANDROID_NATIVES_H #include #include #include #include // --------------------------------------------------------------------------- /* FIXME: this is legacy for pixmaps */ typedef struct egl_native_pixmap_t { int32_t version; /* must be 32 */ int32_t width; int32_t height; int32_t stride; uint8_t* data; uint8_t format; uint8_t rfu[3]; union { uint32_t compressedFormat; int32_t vstride; }; int32_t reserved; } egl_native_pixmap_t; /*****************************************************************************/ #ifdef __cplusplus #include namespace android { /* * This helper class turns a ANativeXXX object type into a C++ * reference-counted object; with proper type conversions. */ template class ANativeObjectBase : public NATIVE_TYPE, public REF { public: // Disambiguate between the incStrong in REF and NATIVE_TYPE void incStrong(const void* id) const { REF::incStrong(id); } void decStrong(const void* id) const { REF::decStrong(id); } protected: typedef ANativeObjectBase BASE; ANativeObjectBase() : NATIVE_TYPE(), REF() { NATIVE_TYPE::common.incRef = incRef; NATIVE_TYPE::common.decRef = decRef; } static inline TYPE* getSelf(NATIVE_TYPE* self) { return static_cast(self); } static inline TYPE const* getSelf(NATIVE_TYPE const* self) { return static_cast(self); } static inline TYPE* getSelf(android_native_base_t* base) { return getSelf(reinterpret_cast(base)); } static inline TYPE const * getSelf(android_native_base_t const* base) { return getSelf(reinterpret_cast(base)); } static void incRef(android_native_base_t* base) { ANativeObjectBase* self = getSelf(base); self->incStrong(self); } static void decRef(android_native_base_t* base) { ANativeObjectBase* self = getSelf(base); self->decStrong(self); } }; } // namespace android #endif // __cplusplus /*****************************************************************************/ #endif /* ANDROID_ANDROID_NATIVES_H */ include/ui/DisplayInfo.h0100644 0000000 0000000 00000002501 13077405420 014237 0ustar000000000 0000000 /* * Copyright (C) 2007 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_UI_DISPLAY_INFO_H #define ANDROID_UI_DISPLAY_INFO_H #include #include #include #include namespace android { struct DisplayInfo { uint32_t w; uint32_t h; float xdpi; float ydpi; float fps; float density; uint8_t orientation; bool secure; nsecs_t appVsyncOffset; nsecs_t presentationDeadline; int colorTransform; }; /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */ enum { DISPLAY_ORIENTATION_0 = 0, DISPLAY_ORIENTATION_90 = 1, DISPLAY_ORIENTATION_180 = 2, DISPLAY_ORIENTATION_270 = 3 }; }; // namespace android #endif // ANDROID_COMPOSER_DISPLAY_INFO_H include/ui/DisplayStatInfo.h0100644 0000000 0000000 00000001575 13077405420 015105 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_UI_DISPLAY_STAT_INFO_H #define ANDROID_UI_DISPLAY_STAT_INFO_H #include namespace android { struct DisplayStatInfo { nsecs_t vsyncTime; nsecs_t vsyncPeriod; }; }; // namespace android #endif // ANDROID_COMPOSER_DISPLAY_STAT_INFO_H include/ui/Fence.h0100644 0000000 0000000 00000010435 13077405420 013043 0ustar000000000 0000000 /* * Copyright (C) 2012 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_FENCE_H #define ANDROID_FENCE_H #include #include #include #include #include #include #include #include struct ANativeWindowBuffer; namespace android { // =========================================================================== // Fence // =========================================================================== class Fence : public LightRefBase, public Flattenable { public: static const sp NO_FENCE; // TIMEOUT_NEVER may be passed to the wait method to indicate that it // should wait indefinitely for the fence to signal. enum { TIMEOUT_NEVER = -1 }; // Construct a new Fence object with an invalid file descriptor. This // should be done when the Fence object will be set up by unflattening // serialized data. Fence(); // Construct a new Fence object to manage a given fence file descriptor. // When the new Fence object is destructed the file descriptor will be // closed. Fence(int fenceFd); // Check whether the Fence has an open fence file descriptor. Most Fence // methods treat an invalid file descriptor just like a valid fence that // is already signalled, so using this is usually not necessary. bool isValid() const { return mFenceFd != -1; } // wait waits for up to timeout milliseconds for the fence to signal. If // the fence signals then NO_ERROR is returned. If the timeout expires // before the fence signals then -ETIME is returned. A timeout of // TIMEOUT_NEVER may be used to indicate that the call should wait // indefinitely for the fence to signal. status_t wait(int timeout); // waitForever is a convenience function for waiting forever for a fence to // signal (just like wait(TIMEOUT_NEVER)), but issuing an error to the // system log and fence state to the kernel log if the wait lasts longer // than a warning timeout. // The logname argument should be a string identifying // the caller and will be included in the log message. status_t waitForever(const char* logname); // merge combines two Fence objects, creating a new Fence object that // becomes signaled when both f1 and f2 are signaled (even if f1 or f2 is // destroyed before it becomes signaled). The name argument specifies the // human-readable name to associated with the new Fence object. static sp merge(const String8& name, const sp& f1, const sp& f2); // Return a duplicate of the fence file descriptor. The caller is // responsible for closing the returned file descriptor. On error, -1 will // be returned and errno will indicate the problem. int dup() const; // getSignalTime returns the system monotonic clock time at which the // fence transitioned to the signaled state. If the fence is not signaled // then INT64_MAX is returned. If the fence is invalid or if an error // occurs then -1 is returned. nsecs_t getSignalTime() const; // Flattenable interface size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); private: // Only allow instantiation using ref counting. friend class LightRefBase; ~Fence(); // Disallow copying Fence(const Fence& rhs); Fence& operator = (const Fence& rhs); const Fence& operator = (const Fence& rhs) const; int mFenceFd; }; }; // namespace android #endif // ANDROID_FENCE_H include/ui/FrameStats.h0100644 0000000 0000000 00000004011 13077405420 014065 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_UI_FRAME_STATS_H #define ANDROID_UI_FRAME_STATS_H #include #include #include namespace android { class FrameStats : public LightFlattenable { public: FrameStats() : refreshPeriodNano(0) {}; /* * Approximate refresh time, in nanoseconds. */ nsecs_t refreshPeriodNano; /* * The times in nanoseconds for when the frame contents were posted by the producer (e.g. * the application). They are either explicitly set or defaulted to the time when * Surface::queueBuffer() was called. */ Vector desiredPresentTimesNano; /* * The times in milliseconds for when the frame contents were presented on the screen. */ Vector actualPresentTimesNano; /* * The times in nanoseconds for when the frame contents were ready to be presented. Note that * a frame can be posted and still it contents being rendered asynchronously in GL. In such a * case these are the times when the frame contents were completely rendered (i.e. their fences * signaled). */ Vector frameReadyTimesNano; // LightFlattenable bool isFixedSize() const; size_t getFlattenedSize() const; status_t flatten(void* buffer, size_t size) const; status_t unflatten(void const* buffer, size_t size); }; }; // namespace android #endif // ANDROID_UI_FRAME_STATS_H include/ui/GraphicBuffer.h0100644 0000000 0000000 00000014346 13077405420 014537 0ustar000000000 0000000 /* * Copyright (C) 2007 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_GRAPHIC_BUFFER_H #define ANDROID_GRAPHIC_BUFFER_H #include #include #include #include #include #include #include struct ANativeWindowBuffer; namespace android { class GraphicBufferMapper; // =========================================================================== // GraphicBuffer // =========================================================================== class GraphicBuffer : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, public Flattenable { friend class Flattenable; public: enum { USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER, USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, USAGE_PROTECTED = GRALLOC_USAGE_PROTECTED, USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, USAGE_HW_2D = GRALLOC_USAGE_HW_2D, USAGE_HW_COMPOSER = GRALLOC_USAGE_HW_COMPOSER, USAGE_HW_VIDEO_ENCODER = GRALLOC_USAGE_HW_VIDEO_ENCODER, USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK, USAGE_CURSOR = GRALLOC_USAGE_CURSOR, }; GraphicBuffer(); // creates w * h buffer GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage); // create a buffer from an existing handle GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, bool keepOwnership); // create a buffer from an existing ANativeWindowBuffer GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership); // return status status_t initCheck() const; uint32_t getWidth() const { return static_cast(width); } uint32_t getHeight() const { return static_cast(height); } uint32_t getStride() const { return static_cast(stride); } uint32_t getUsage() const { return static_cast(usage); } PixelFormat getPixelFormat() const { return format; } Rect getBounds() const { return Rect(width, height); } uint64_t getId() const { return mId; } uint32_t getGenerationNumber() const { return mGenerationNumber; } void setGenerationNumber(uint32_t generation) { mGenerationNumber = generation; } status_t reallocate(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage); bool needsReallocation(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage); status_t lock(uint32_t inUsage, void** vaddr); status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr); // For HAL_PIXEL_FORMAT_YCbCr_420_888 status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr); status_t lockYCbCr(uint32_t inUsage, const Rect& rect, android_ycbcr *ycbcr); status_t unlock(); status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd); status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd); status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr, int fenceFd); status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, android_ycbcr *ycbcr, int fenceFd); status_t unlockAsync(int *fenceFd); ANativeWindowBuffer* getNativeBuffer() const; // for debugging static void dumpAllocationsToSystemLog(); // Flattenable protocol size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); private: ~GraphicBuffer(); enum { ownNone = 0, ownHandle = 1, ownData = 2, }; inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } uint8_t mOwner; private: friend class Surface; friend class BpSurface; friend class BnSurface; friend class LightRefBase; GraphicBuffer(const GraphicBuffer& rhs); GraphicBuffer& operator = (const GraphicBuffer& rhs); const GraphicBuffer& operator = (const GraphicBuffer& rhs) const; status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage); void free_handle(); GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; // If we're wrapping another buffer then this reference will make sure it // doesn't get freed. sp mWrappedBuffer; uint64_t mId; // Stores the generation number of this buffer. If this number does not // match the BufferQueue's internal generation number (set through // IGBP::setGenerationNumber), attempts to attach the buffer will fail. uint32_t mGenerationNumber; }; }; // namespace android #endif // ANDROID_GRAPHIC_BUFFER_H include/ui/GraphicBufferAllocator.h0100644 0000000 0000000 00000005441 13077405420 016374 0ustar000000000 0000000 /* ** ** Copyright 2009, 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_BUFFER_ALLOCATOR_H #define ANDROID_BUFFER_ALLOCATOR_H #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class String8; class GraphicBufferAllocator : public Singleton { public: enum { USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER, USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, USAGE_HW_2D = GRALLOC_USAGE_HW_2D, USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK }; static inline GraphicBufferAllocator& get() { return getInstance(); } status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, buffer_handle_t* handle, uint32_t* stride); status_t free(buffer_handle_t handle); void dump(String8& res) const; static void dumpToSystemLog(); private: struct alloc_rec_t { uint32_t width; uint32_t height; uint32_t stride; PixelFormat format; uint32_t usage; size_t size; }; static Mutex sLock; static KeyedVector sAllocList; friend class Singleton; GraphicBufferAllocator(); ~GraphicBufferAllocator(); alloc_device_t *mAllocDev; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_BUFFER_ALLOCATOR_H include/ui/GraphicBufferMapper.h0100644 0000000 0000000 00000004176 13077405420 015704 0ustar000000000 0000000 /* * Copyright (C) 2007 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_UI_BUFFER_MAPPER_H #define ANDROID_UI_BUFFER_MAPPER_H #include #include #include #include struct gralloc_module_t; namespace android { // --------------------------------------------------------------------------- class Rect; class GraphicBufferMapper : public Singleton { public: static inline GraphicBufferMapper& get() { return getInstance(); } status_t registerBuffer(buffer_handle_t handle); status_t unregisterBuffer(buffer_handle_t handle); status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr); status_t lockYCbCr(buffer_handle_t handle, uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr); status_t unlock(buffer_handle_t handle); status_t lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd); status_t lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd); status_t unlockAsync(buffer_handle_t handle, int *fenceFd); // dumps information about the mapping of this handle void dump(buffer_handle_t handle); private: friend class Singleton; GraphicBufferMapper(); gralloc_module_t const *mAllocMod; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_UI_BUFFER_MAPPER_H include/ui/HdrCapabilities.h0100644 0000000 0000000 00000004202 13077405420 015045 0ustar000000000 0000000 /* * Copyright 2016 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_UI_HDR_CAPABILTIES_H #define ANDROID_UI_HDR_CAPABILTIES_H #include namespace android { class HdrCapabilities : public Parcelable { public: HdrCapabilities(const std::vector& types, float maxLuminance, float maxAverageLuminance, float minLuminance) : mSupportedHdrTypes(types), mMaxLuminance(maxLuminance), mMaxAverageLuminance(maxAverageLuminance), mMinLuminance(minLuminance) {} // Make this move-constructable and move-assignable HdrCapabilities(HdrCapabilities&& other) = default; HdrCapabilities& operator=(HdrCapabilities&& other) = default; HdrCapabilities() : mSupportedHdrTypes(), mMaxLuminance(-1.0f), mMaxAverageLuminance(-1.0f), mMinLuminance(-1.0f) {} virtual ~HdrCapabilities() = default; const std::vector& getSupportedHdrTypes() const { return mSupportedHdrTypes; } float getDesiredMaxLuminance() const { return mMaxLuminance; } float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; } float getDesiredMinLuminance() const { return mMinLuminance; } // Parcelable interface virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; private: std::vector mSupportedHdrTypes; float mMaxLuminance; float mMaxAverageLuminance; float mMinLuminance; }; } // namespace android #endif include/ui/PixelFormat.h0100644 0000000 0000000 00000004677 13077405420 014270 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ // // Pixel formats used across the system. // These formats might not all be supported by all renderers, for instance // skia or SurfaceFlinger are not required to support all of these formats // (either as source or destination) #ifndef UI_PIXELFORMAT_H #define UI_PIXELFORMAT_H #include namespace android { enum { // // these constants need to match those // in graphics/PixelFormat.java & pixelflinger/format.h // PIXEL_FORMAT_UNKNOWN = 0, PIXEL_FORMAT_NONE = 0, // logical pixel formats used by the SurfaceFlinger ----------------------- PIXEL_FORMAT_CUSTOM = -4, // Custom pixel-format described by a PixelFormatInfo structure PIXEL_FORMAT_TRANSLUCENT = -3, // System chooses a format that supports translucency (many alpha bits) PIXEL_FORMAT_TRANSPARENT = -2, // System chooses a format that supports transparency // (at least 1 alpha bit) PIXEL_FORMAT_OPAQUE = -1, // System chooses an opaque format (no alpha bits required) // real pixel formats supported for rendering ----------------------------- PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0 PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB }; typedef int32_t PixelFormat; uint32_t bytesPerPixel(PixelFormat format); uint32_t bitsPerPixel(PixelFormat format); }; // namespace android #endif // UI_PIXELFORMAT_H include/ui/Point.h0100644 0000000 0000000 00000004302 13077405420 013110 0ustar000000000 0000000 /* * Copyright (C) 2006 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_UI_POINT #define ANDROID_UI_POINT #include #include namespace android { class Point : public LightFlattenablePod { public: int x; int y; // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions // Default constructor doesn't initialize the Point inline Point() { } inline Point(int x, int y) : x(x), y(y) { } inline bool operator == (const Point& rhs) const { return (x == rhs.x) && (y == rhs.y); } inline bool operator != (const Point& rhs) const { return !operator == (rhs); } inline bool isOrigin() const { return !(x|y); } // operator < defines an order which allows to use points in sorted // vectors. bool operator < (const Point& rhs) const { return y #include #include #include #include namespace android { class Rect : public ARect, public LightFlattenablePod { public: typedef ARect::value_type value_type; static const Rect INVALID_RECT; static const Rect EMPTY_RECT; // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions inline Rect() : Rect(INVALID_RECT) {} template inline Rect(T w, T h) { if (w > INT32_MAX) { ALOG(LOG_WARN, "Rect", "Width %u too large for Rect class, clamping", w); w = INT32_MAX; } if (h > INT32_MAX) { ALOG(LOG_WARN, "Rect", "Height %u too large for Rect class, clamping", h); h = INT32_MAX; } left = top = 0; right = static_cast(w); bottom = static_cast(h); } inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) { left = l; top = t; right = r; bottom = b; } inline Rect(const Point& lt, const Point& rb) { left = lt.x; top = lt.y; right = rb.x; bottom = rb.y; } void makeInvalid(); inline void clear() { left = top = right = bottom = 0; } // a valid rectangle has a non negative width and height inline bool isValid() const { return (getWidth() >= 0) && (getHeight() >= 0); } // an empty rect has a zero width or height, or is invalid inline bool isEmpty() const { return (getWidth() <= 0) || (getHeight() <= 0); } // rectangle's width inline int32_t getWidth() const { return right - left; } // rectangle's height inline int32_t getHeight() const { return bottom - top; } inline Rect getBounds() const { return Rect(right - left, bottom - top); } void setLeftTop(const Point& lt) { left = lt.x; top = lt.y; } void setRightBottom(const Point& rb) { right = rb.x; bottom = rb.y; } // the following 4 functions return the 4 corners of the rect as Point Point leftTop() const { return Point(left, top); } Point rightBottom() const { return Point(right, bottom); } Point rightTop() const { return Point(right, top); } Point leftBottom() const { return Point(left, bottom); } // comparisons inline bool operator == (const Rect& rhs) const { return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) && (bottom == rhs.bottom); } inline bool operator != (const Rect& rhs) const { return !operator == (rhs); } // operator < defines an order which allows to use rectangles in sorted // vectors. bool operator < (const Rect& rhs) const; const Rect operator + (const Point& rhs) const; const Rect operator - (const Point& rhs) const; Rect& operator += (const Point& rhs) { return offsetBy(rhs.x, rhs.y); } Rect& operator -= (const Point& rhs) { return offsetBy(-rhs.x, -rhs.y); } Rect& offsetToOrigin() { right -= left; bottom -= top; left = top = 0; return *this; } Rect& offsetTo(const Point& p) { return offsetTo(p.x, p.y); } Rect& offsetBy(const Point& dp) { return offsetBy(dp.x, dp.y); } Rect& offsetTo(int32_t x, int32_t y); Rect& offsetBy(int32_t x, int32_t y); bool intersect(const Rect& with, Rect* result) const; // Create a new Rect by transforming this one using a graphics HAL // transform. This rectangle is defined in a coordinate space starting at // the origin and extending to (width, height). If the transform includes // a ROT90 then the output rectangle is defined in a space extending to // (height, width). Otherwise the output rectangle is in the same space as // the input. Rect transform(uint32_t xform, int32_t width, int32_t height) const; // this calculates (Region(*this) - exclude).bounds() efficiently Rect reduce(const Rect& exclude) const; // for backward compatibility inline int32_t width() const { return getWidth(); } inline int32_t height() const { return getHeight(); } inline void set(const Rect& rhs) { operator = (rhs); } }; ANDROID_BASIC_TYPES_TRAITS(Rect) }; // namespace android #endif // ANDROID_UI_RECT include/ui/Region.h0100644 0000000 0000000 00000017524 13077405420 013254 0ustar000000000 0000000 /* * Copyright (C) 2007 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_UI_REGION_H #define ANDROID_UI_REGION_H #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class String8; // --------------------------------------------------------------------------- class Region : public LightFlattenable { public: static const Region INVALID_REGION; Region(); Region(const Region& rhs); explicit Region(const Rect& rhs); ~Region(); static Region createTJunctionFreeRegion(const Region& r); Region& operator = (const Region& rhs); inline bool isEmpty() const { return getBounds().isEmpty(); } inline bool isRect() const { return mStorage.size() == 1; } inline Rect getBounds() const { return mStorage[mStorage.size() - 1]; } inline Rect bounds() const { return getBounds(); } bool contains(const Point& point) const; bool contains(int x, int y) const; // the region becomes its bounds Region& makeBoundsSelf(); void clear(); void set(const Rect& r); void set(int32_t w, int32_t h); void set(uint32_t w, uint32_t h); Region& orSelf(const Rect& rhs); Region& xorSelf(const Rect& rhs); Region& andSelf(const Rect& rhs); Region& subtractSelf(const Rect& rhs); // boolean operators, applied on this Region& orSelf(const Region& rhs); Region& xorSelf(const Region& rhs); Region& andSelf(const Region& rhs); Region& subtractSelf(const Region& rhs); // boolean operators const Region merge(const Rect& rhs) const; const Region mergeExclusive(const Rect& rhs) const; const Region intersect(const Rect& rhs) const; const Region subtract(const Rect& rhs) const; // boolean operators const Region merge(const Region& rhs) const; const Region mergeExclusive(const Region& rhs) const; const Region intersect(const Region& rhs) const; const Region subtract(const Region& rhs) const; // these translate rhs first Region& translateSelf(int dx, int dy); Region& orSelf(const Region& rhs, int dx, int dy); Region& xorSelf(const Region& rhs, int dx, int dy); Region& andSelf(const Region& rhs, int dx, int dy); Region& subtractSelf(const Region& rhs, int dx, int dy); // these translate rhs first const Region translate(int dx, int dy) const; const Region merge(const Region& rhs, int dx, int dy) const; const Region mergeExclusive(const Region& rhs, int dx, int dy) const; const Region intersect(const Region& rhs, int dx, int dy) const; const Region subtract(const Region& rhs, int dx, int dy) const; // convenience operators overloads inline const Region operator | (const Region& rhs) const; inline const Region operator ^ (const Region& rhs) const; inline const Region operator & (const Region& rhs) const; inline const Region operator - (const Region& rhs) const; inline const Region operator + (const Point& pt) const; inline Region& operator |= (const Region& rhs); inline Region& operator ^= (const Region& rhs); inline Region& operator &= (const Region& rhs); inline Region& operator -= (const Region& rhs); inline Region& operator += (const Point& pt); // returns true if the regions share the same underlying storage bool isTriviallyEqual(const Region& region) const; /* various ways to access the rectangle list */ // STL-like iterators typedef Rect const* const_iterator; const_iterator begin() const; const_iterator end() const; // returns an array of rect which has the same life-time has this // Region object. Rect const* getArray(size_t* count) const; /* no user serviceable parts here... */ // add a rectangle to the internal list. This rectangle must // be sorted in Y and X and must not make the region invalid. void addRectUnchecked(int l, int t, int r, int b); inline bool isFixedSize() const { return false; } size_t getFlattenedSize() const; status_t flatten(void* buffer, size_t size) const; status_t unflatten(void const* buffer, size_t size); void dump(String8& out, const char* what, uint32_t flags=0) const; void dump(const char* what, uint32_t flags=0) const; private: class rasterizer; friend class rasterizer; Region& operationSelf(const Rect& r, int op); Region& operationSelf(const Region& r, int op); Region& operationSelf(const Region& r, int dx, int dy, int op); const Region operation(const Rect& rhs, int op) const; const Region operation(const Region& rhs, int op) const; const Region operation(const Region& rhs, int dx, int dy, int op) const; static void boolean_operation(int op, Region& dst, const Region& lhs, const Region& rhs, int dx, int dy); static void boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs, int dx, int dy); static void boolean_operation(int op, Region& dst, const Region& lhs, const Region& rhs); static void boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs); static void translate(Region& reg, int dx, int dy); static void translate(Region& dst, const Region& reg, int dx, int dy); static bool validate(const Region& reg, const char* name, bool silent = false); // mStorage is a (manually) sorted array of Rects describing the region // with an extra Rect as the last element which is set to the // bounds of the region. However, if the region is // a simple Rect then mStorage contains only that rect. Vector mStorage; }; const Region Region::operator | (const Region& rhs) const { return merge(rhs); } const Region Region::operator ^ (const Region& rhs) const { return mergeExclusive(rhs); } const Region Region::operator & (const Region& rhs) const { return intersect(rhs); } const Region Region::operator - (const Region& rhs) const { return subtract(rhs); } const Region Region::operator + (const Point& pt) const { return translate(pt.x, pt.y); } Region& Region::operator |= (const Region& rhs) { return orSelf(rhs); } Region& Region::operator ^= (const Region& rhs) { return xorSelf(rhs); } Region& Region::operator &= (const Region& rhs) { return andSelf(rhs); } Region& Region::operator -= (const Region& rhs) { return subtractSelf(rhs); } Region& Region::operator += (const Point& pt) { return translateSelf(pt.x, pt.y); } // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_UI_REGION_H include/ui/TMatHelpers.h0100644 0000000 0000000 00000016737 13077405420 014226 0ustar000000000 0000000 /* * Copyright 2013 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 TMAT_IMPLEMENTATION #error "Don't include TMatHelpers.h directly. use ui/mat*.h instead" #else #undef TMAT_IMPLEMENTATION #endif #ifndef UI_TMAT_HELPERS_H #define UI_TMAT_HELPERS_H #include #include #include #include #include #define PURE __attribute__((pure)) namespace android { // ------------------------------------------------------------------------------------- /* * No user serviceable parts here. * * Don't use this file directly, instead include ui/mat*.h */ /* * Matrix utilities */ namespace matrix { inline int PURE transpose(int v) { return v; } inline float PURE transpose(float v) { return v; } inline double PURE transpose(double v) { return v; } inline int PURE trace(int v) { return v; } inline float PURE trace(float v) { return v; } inline double PURE trace(double v) { return v; } template MATRIX PURE inverse(const MATRIX& src) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::COL_SIZE == MATRIX::ROW_SIZE ); typename MATRIX::value_type t; const size_t N = MATRIX::col_size(); size_t swap; MATRIX tmp(src); MATRIX inverse(1); for (size_t i=0 ; i fabs(tmp[i][i])) { swap = j; } } if (swap != i) { /* swap rows. */ for (size_t k=0 ; k MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { // pre-requisite: // lhs : D columns, R rows // rhs : C columns, D rows // res : C columns, R rows COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_A::ROW_SIZE == MATRIX_B::COL_SIZE ); COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::ROW_SIZE == MATRIX_B::ROW_SIZE ); COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::COL_SIZE == MATRIX_A::COL_SIZE ); MATRIX_R res(MATRIX_R::NO_INIT); for (size_t r=0 ; r MATRIX PURE transpose(const MATRIX& m) { // for now we only handle square matrix transpose COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); MATRIX result(MATRIX::NO_INIT); for (size_t r=0 ; r typename MATRIX::value_type PURE trace(const MATRIX& m) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); typename MATRIX::value_type result(0); for (size_t r=0 ; r typename MATRIX::col_type PURE diag(const MATRIX& m) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); typename MATRIX::col_type result(MATRIX::col_type::NO_INIT); for (size_t r=0 ; r String8 asString(const MATRIX& m) { String8 s; for (size_t c=0 ; c. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TMatProductOperators BASE will automatically * get all the functionality here. */ template class BASE, typename T> class TMatProductOperators { public: // multiply by a scalar BASE& operator *= (T v) { BASE& lhs(static_cast< BASE& >(*this)); for (size_t r=0 ; r& operator /= (T v) { BASE& lhs(static_cast< BASE& >(*this)); for (size_t r=0 ; r friend BASE PURE operator *(const BASE& lhs, const BASE& rhs) { return matrix::multiply >(lhs, rhs); } }; /* * TMatSquareFunctions implements functions on a matrix of type BASE. * * BASE only needs to implement: * - operator[] * - col_type * - row_type * - COL_SIZE * - ROW_SIZE * * By simply inheriting from TMatSquareFunctions BASE will automatically * get all the functionality here. */ template class BASE, typename T> class TMatSquareFunctions { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ friend BASE PURE inverse(const BASE& m) { return matrix::inverse(m); } friend BASE PURE transpose(const BASE& m) { return matrix::transpose(m); } friend T PURE trace(const BASE& m) { return matrix::trace(m); } }; template class BASE, typename T> class TMatDebug { public: String8 asString() const { return matrix::asString( static_cast< const BASE& >(*this) ); } }; // ------------------------------------------------------------------------------------- }; // namespace android #undef PURE #endif /* UI_TMAT_HELPERS_H */ include/ui/TVecHelpers.h0100644 0000000 0000000 00000027525 13077405420 014217 0ustar000000000 0000000 /* * Copyright 2013 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 TVEC_IMPLEMENTATION #error "Don't include TVecHelpers.h directly. use ui/vec*.h instead" #else #undef TVEC_IMPLEMENTATION #endif #ifndef UI_TVEC_HELPERS_H #define UI_TVEC_HELPERS_H #include #include #define PURE __attribute__((pure)) namespace android { // ------------------------------------------------------------------------------------- /* * No user serviceable parts here. * * Don't use this file directly, instead include ui/vec{2|3|4}.h */ /* * This class casts itself into anything and assign itself from anything! * Use with caution! */ template struct Impersonator { Impersonator& operator = (const TYPE& rhs) { reinterpret_cast(*this) = rhs; return *this; } operator TYPE& () { return reinterpret_cast(*this); } operator TYPE const& () const { return reinterpret_cast(*this); } }; /* * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments * operators on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVec{Add|Product}Operators BASE will automatically * get all the functionality here. */ template class BASE, typename T> class TVecAddOperators { public: /* compound assignment from a another vector of the same size but different * element type. */ template BASE& operator += (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] += v[i]; } return rhs; } template BASE& operator -= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] -= v[i]; } return rhs; } /* compound assignment from a another vector of the same type. * These operators can be used for implicit conversion and handle operations * like "vector *= scalar" by letting the compiler implicitly convert a scalar * to a vector (assuming the BASE allows it). */ BASE& operator += (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] += v[i]; } return rhs; } BASE& operator -= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] -= v[i]; } return rhs; } /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ /* The operators below handle operation between vectors of the same side * but of a different element type. */ template friend inline BASE PURE operator +(const BASE& lv, const BASE& rv) { return BASE(lv) += rv; } template friend inline BASE PURE operator -(const BASE& lv, const BASE& rv) { return BASE(lv) -= rv; } /* The operators below (which are not templates once this class is instanced, * i.e.: BASE is known) can be used for implicit conversion on both sides. * These handle operations like "vector * scalar" and "scalar * vector" by * letting the compiler implicitly convert a scalar to a vector (assuming * the BASE allows it). */ friend inline BASE PURE operator +(const BASE& lv, const BASE& rv) { return BASE(lv) += rv; } friend inline BASE PURE operator -(const BASE& lv, const BASE& rv) { return BASE(lv) -= rv; } }; template class BASE, typename T> class TVecProductOperators { public: /* compound assignment from a another vector of the same size but different * element type. */ template BASE& operator *= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] *= v[i]; } return rhs; } template BASE& operator /= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] /= v[i]; } return rhs; } /* compound assignment from a another vector of the same type. * These operators can be used for implicit conversion and handle operations * like "vector *= scalar" by letting the compiler implicitly convert a scalar * to a vector (assuming the BASE allows it). */ BASE& operator *= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] *= v[i]; } return rhs; } BASE& operator /= (const BASE& v) { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { rhs[i] /= v[i]; } return rhs; } /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ /* The operators below handle operation between vectors of the same side * but of a different element type. */ template friend inline BASE PURE operator *(const BASE& lv, const BASE& rv) { return BASE(lv) *= rv; } template friend inline BASE PURE operator /(const BASE& lv, const BASE& rv) { return BASE(lv) /= rv; } /* The operators below (which are not templates once this class is instanced, * i.e.: BASE is known) can be used for implicit conversion on both sides. * These handle operations like "vector * scalar" and "scalar * vector" by * letting the compiler implicitly convert a scalar to a vector (assuming * the BASE allows it). */ friend inline BASE PURE operator *(const BASE& lv, const BASE& rv) { return BASE(lv) *= rv; } friend inline BASE PURE operator /(const BASE& lv, const BASE& rv) { return BASE(lv) /= rv; } }; /* * TVecUnaryOperators implements unary operators on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecUnaryOperators BASE will automatically * get all the functionality here. * * These operators are implemented as friend functions of TVecUnaryOperators */ template class BASE, typename T> class TVecUnaryOperators { public: BASE& operator ++ () { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { ++rhs[i]; } return rhs; } BASE& operator -- () { BASE& rhs = static_cast&>(*this); for (size_t i=0 ; i::size() ; i++) { --rhs[i]; } return rhs; } BASE operator - () const { BASE r(BASE::NO_INIT); BASE const& rv(static_cast const&>(*this)); for (size_t i=0 ; i::size() ; i++) { r[i] = -rv[i]; } return r; } }; /* * TVecComparisonOperators implements relational/comparison operators * on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecComparisonOperators BASE will automatically * get all the functionality here. */ template class BASE, typename T> class TVecComparisonOperators { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline bool PURE operator ==(const BASE& lv, const BASE& rv) { for (size_t i = 0; i < BASE::size(); i++) if (lv[i] != rv[i]) return false; return true; } template friend inline bool PURE operator !=(const BASE& lv, const BASE& rv) { return !operator ==(lv, rv); } template friend inline bool PURE operator >(const BASE& lv, const BASE& rv) { for (size_t i = 0; i < BASE::size(); i++) if (lv[i] <= rv[i]) return false; return true; } template friend inline bool PURE operator <=(const BASE& lv, const BASE& rv) { return !(lv > rv); } template friend inline bool PURE operator <(const BASE& lv, const BASE& rv) { for (size_t i = 0; i < BASE::size(); i++) if (lv[i] >= rv[i]) return false; return true; } template friend inline bool PURE operator >=(const BASE& lv, const BASE& rv) { return !(lv < rv); } }; /* * TVecFunctions implements functions on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecFunctions BASE will automatically * get all the functionality here. */ template class BASE, typename T> class TVecFunctions { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline T PURE dot(const BASE& lv, const BASE& rv) { T r(0); for (size_t i = 0; i < BASE::size(); i++) r += lv[i]*rv[i]; return r; } friend inline T PURE length(const BASE& lv) { return sqrt( dot(lv, lv) ); } template friend inline T PURE distance(const BASE& lv, const BASE& rv) { return length(rv - lv); } friend inline BASE PURE normalize(const BASE& lv) { return lv * (1 / length(lv)); } }; #undef PURE // ------------------------------------------------------------------------------------- }; // namespace android #endif /* UI_TVEC_HELPERS_H */ include/ui/UiConfig.h0100644 0000000 0000000 00000001567 13077405420 013534 0ustar000000000 0000000 /* * Copyright (C) 2012 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_UI_CONFIG_H #define ANDROID_UI_CONFIG_H #include namespace android { // Append the libui configuration details to configStr. void appendUiConfigString(String8& configStr); }; // namespace android #endif /*ANDROID_UI_CONFIG_H*/ include/ui/mat4.h0100644 0000000 0000000 00000027662 13077405420 012702 0ustar000000000 0000000 /* * Copyright 2013 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 UI_MAT4_H #define UI_MAT4_H #include #include #include #include #define TMAT_IMPLEMENTATION #include #define PURE __attribute__((pure)) namespace android { // ------------------------------------------------------------------------------------- template class tmat44 : public TVecUnaryOperators, public TVecComparisonOperators, public TVecAddOperators, public TMatProductOperators, public TMatSquareFunctions, public TMatDebug { public: enum no_init { NO_INIT }; typedef T value_type; typedef T& reference; typedef T const& const_reference; typedef size_t size_type; typedef tvec4 col_type; typedef tvec4 row_type; // size of a column (i.e.: number of rows) enum { COL_SIZE = col_type::SIZE }; static inline size_t col_size() { return COL_SIZE; } // size of a row (i.e.: number of columns) enum { ROW_SIZE = row_type::SIZE }; static inline size_t row_size() { return ROW_SIZE; } static inline size_t size() { return row_size(); } // for TVec*<> private: /* * <-- N columns --> * * a00 a10 a20 ... aN0 ^ * a01 a11 a21 ... aN1 | * a02 a12 a22 ... aN2 M rows * ... | * a0M a1M a2M ... aNM v * * COL_SIZE = M * ROW_SIZE = N * m[0] = [a00 a01 a02 ... a01M] */ col_type mValue[ROW_SIZE]; public: // array access inline col_type const& operator [] (size_t i) const { return mValue[i]; } inline col_type& operator [] (size_t i) { return mValue[i]; } T const* asArray() const { return &mValue[0][0]; } // ----------------------------------------------------------------------- // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions /* * constructors */ // leaves object uninitialized. use with caution. explicit tmat44(no_init) { } // initialize to identity tmat44(); // initialize to Identity*scalar. template explicit tmat44(U v); // sets the diagonal to the passed vector template explicit tmat44(const tvec4& rhs); // construct from another matrix of the same size template explicit tmat44(const tmat44& rhs); // construct from 4 column vectors template tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3); // construct from 16 scalars template < typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> tmat44( A m00, B m01, C m02, D m03, E m10, F m11, G m12, H m13, I m20, J m21, K m22, L m23, M m30, N m31, O m32, P m33); // construct from a C array template explicit tmat44(U const* rawArray); /* * helpers */ static tmat44 ortho(T left, T right, T bottom, T top, T near, T far); static tmat44 frustum(T left, T right, T bottom, T top, T near, T far); template static tmat44 lookAt(const tvec3& eye, const tvec3& center, const tvec3& up); template static tmat44 translate(const tvec4& t); template static tmat44 scale(const tvec4& s); template static tmat44 rotate(A radian, const tvec3& about); }; // ---------------------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------------------- /* * Since the matrix code could become pretty big quickly, we don't inline most * operations. */ template tmat44::tmat44() { mValue[0] = col_type(1,0,0,0); mValue[1] = col_type(0,1,0,0); mValue[2] = col_type(0,0,1,0); mValue[3] = col_type(0,0,0,1); } template template tmat44::tmat44(U v) { mValue[0] = col_type(v,0,0,0); mValue[1] = col_type(0,v,0,0); mValue[2] = col_type(0,0,v,0); mValue[3] = col_type(0,0,0,v); } template template tmat44::tmat44(const tvec4& v) { mValue[0] = col_type(v.x,0,0,0); mValue[1] = col_type(0,v.y,0,0); mValue[2] = col_type(0,0,v.z,0); mValue[3] = col_type(0,0,0,v.w); } // construct from 16 scalars template template < typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> tmat44::tmat44( A m00, B m01, C m02, D m03, E m10, F m11, G m12, H m13, I m20, J m21, K m22, L m23, M m30, N m31, O m32, P m33) { mValue[0] = col_type(m00, m01, m02, m03); mValue[1] = col_type(m10, m11, m12, m13); mValue[2] = col_type(m20, m21, m22, m23); mValue[3] = col_type(m30, m31, m32, m33); } template template tmat44::tmat44(const tmat44& rhs) { for (size_t r=0 ; r template tmat44::tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3) { mValue[0] = v0; mValue[1] = v1; mValue[2] = v2; mValue[3] = v3; } template template tmat44::tmat44(U const* rawArray) { for (size_t r=0 ; r tmat44 tmat44::ortho(T left, T right, T bottom, T top, T near, T far) { tmat44 m; m[0][0] = 2 / (right - left); m[1][1] = 2 / (top - bottom); m[2][2] = -2 / (far - near); m[3][0] = -(right + left) / (right - left); m[3][1] = -(top + bottom) / (top - bottom); m[3][2] = -(far + near) / (far - near); return m; } template tmat44 tmat44::frustum(T left, T right, T bottom, T top, T near, T far) { tmat44 m; T A = (right + left) / (right - left); T B = (top + bottom) / (top - bottom); T C = (far + near) / (far - near); T D = (2 * far * near) / (far - near); m[0][0] = (2 * near) / (right - left); m[1][1] = (2 * near) / (top - bottom); m[2][0] = A; m[2][1] = B; m[2][2] = C; m[2][3] =-1; m[3][2] = D; m[3][3] = 0; return m; } template template tmat44 tmat44::lookAt(const tvec3& eye, const tvec3& center, const tvec3& up) { tvec3 L(normalize(center - eye)); tvec3 S(normalize( cross(L, up) )); tvec3 U(cross(S, L)); return tmat44( tvec4( S, 0), tvec4( U, 0), tvec4(-L, 0), tvec4(-eye, 1)); } template template tmat44 tmat44::translate(const tvec4& t) { tmat44 r; r[3] = t; return r; } template template tmat44 tmat44::scale(const tvec4& s) { tmat44 r; r[0][0] = s[0]; r[1][1] = s[1]; r[2][2] = s[2]; r[3][3] = s[3]; return r; } template template tmat44 tmat44::rotate(A radian, const tvec3& about) { tmat44 rotation; T* r = const_cast(rotation.asArray()); T c = cos(radian); T s = sin(radian); if (about.x==1 && about.y==0 && about.z==0) { r[5] = c; r[10]= c; r[6] = s; r[9] = -s; } else if (about.x==0 && about.y==1 && about.z==0) { r[0] = c; r[10]= c; r[8] = s; r[2] = -s; } else if (about.x==0 && about.y==0 && about.z==1) { r[0] = c; r[5] = c; r[1] = s; r[4] = -s; } else { tvec3 nabout = normalize(about); B x = nabout.x; B y = nabout.y; B z = nabout.z; T nc = 1 - c; T xy = x * y; T yz = y * z; T zx = z * x; T xs = x * s; T ys = y * s; T zs = z * s; r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys; r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs; r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c; } return rotation; } // ---------------------------------------------------------------------------------------- // Arithmetic operators outside of class // ---------------------------------------------------------------------------------------- /* We use non-friend functions here to prevent the compiler from using * implicit conversions, for instance of a scalar to a vector. The result would * not be what the caller expects. * * Also note that the order of the arguments in the inner loop is important since * it determines the output type (only relevant when T != U). */ // matrix * vector, result is a vector of the same type than the input vector template typename tmat44::col_type PURE operator *(const tmat44& lv, const tvec4& rv) { typename tmat44::col_type result; for (size_t r=0 ; r::row_size() ; r++) result += rv[r]*lv[r]; return result; } // vector * matrix, result is a vector of the same type than the input vector template typename tmat44::row_type PURE operator *(const tvec4& rv, const tmat44& lv) { typename tmat44::row_type result(tmat44::row_type::NO_INIT); for (size_t r=0 ; r::row_size() ; r++) result[r] = dot(rv, lv[r]); return result; } // matrix * scalar, result is a matrix of the same type than the input matrix template tmat44 PURE operator *(const tmat44& lv, U rv) { tmat44 result(tmat44::NO_INIT); for (size_t r=0 ; r::row_size() ; r++) result[r] = lv[r]*rv; return result; } // scalar * matrix, result is a matrix of the same type than the input matrix template tmat44 PURE operator *(U rv, const tmat44& lv) { tmat44 result(tmat44::NO_INIT); for (size_t r=0 ; r::row_size() ; r++) result[r] = lv[r]*rv; return result; } // ---------------------------------------------------------------------------------------- /* FIXME: this should go into TMatSquareFunctions<> but for some reason * BASE::col_type is not accessible from there (???) */ template typename tmat44::col_type PURE diag(const tmat44& m) { return matrix::diag(m); } // ---------------------------------------------------------------------------------------- typedef tmat44 mat4; // ---------------------------------------------------------------------------------------- }; // namespace android #undef PURE #endif /* UI_MAT4_H */ include/ui/vec2.h0100644 0000000 0000000 00000005225 13077405420 012663 0ustar000000000 0000000 /* * Copyright 2013 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 UI_VEC2_H #define UI_VEC2_H #include #include #define TVEC_IMPLEMENTATION #include namespace android { // ------------------------------------------------------------------------------------- template class tvec2 : public TVecProductOperators, public TVecAddOperators, public TVecUnaryOperators, public TVecComparisonOperators, public TVecFunctions { public: enum no_init { NO_INIT }; typedef T value_type; typedef T& reference; typedef T const& const_reference; typedef size_t size_type; union { struct { T x, y; }; struct { T s, t; }; struct { T r, g; }; }; enum { SIZE = 2 }; inline static size_type size() { return SIZE; } // array access inline T const& operator [] (size_t i) const { return (&x)[i]; } inline T& operator [] (size_t i) { return (&x)[i]; } // ----------------------------------------------------------------------- // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions // constructors // leaves object uninitialized. use with caution. explicit tvec2(no_init) { } // default constructor tvec2() : x(0), y(0) { } // handles implicit conversion to a tvec4. must not be explicit. template tvec2(A v) : x(v), y(v) { } template tvec2(A x, B y) : x(x), y(y) { } template explicit tvec2(const tvec2& v) : x(v.x), y(v.y) { } template tvec2(const Impersonator< tvec2 >& v) : x(((const tvec2&)v).x), y(((const tvec2&)v).y) { } }; // ---------------------------------------------------------------------------------------- typedef tvec2 vec2; // ---------------------------------------------------------------------------------------- }; // namespace android #endif /* UI_VEC4_H */ include/ui/vec3.h0100644 0000000 0000000 00000006607 13077405420 012671 0ustar000000000 0000000 /* * Copyright 2013 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 UI_VEC3_H #define UI_VEC3_H #include #include #include namespace android { // ------------------------------------------------------------------------------------- template class tvec3 : public TVecProductOperators, public TVecAddOperators, public TVecUnaryOperators, public TVecComparisonOperators, public TVecFunctions { public: enum no_init { NO_INIT }; typedef T value_type; typedef T& reference; typedef T const& const_reference; typedef size_t size_type; union { struct { T x, y, z; }; struct { T s, t, p; }; struct { T r, g, b; }; Impersonator< tvec2 > xy; Impersonator< tvec2 > st; Impersonator< tvec2 > rg; }; enum { SIZE = 3 }; inline static size_type size() { return SIZE; } // array access inline T const& operator [] (size_t i) const { return (&x)[i]; } inline T& operator [] (size_t i) { return (&x)[i]; } // ----------------------------------------------------------------------- // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions // constructors // leaves object uninitialized. use with caution. explicit tvec3(no_init) { } // default constructor tvec3() : x(0), y(0), z(0) { } // handles implicit conversion to a tvec4. must not be explicit. template tvec3(A v) : x(v), y(v), z(v) { } template tvec3(A x, B y, C z) : x(x), y(y), z(z) { } template tvec3(const tvec2& v, B z) : x(v.x), y(v.y), z(z) { } template explicit tvec3(const tvec3& v) : x(v.x), y(v.y), z(v.z) { } template tvec3(const Impersonator< tvec3 >& v) : x(((const tvec3&)v).x), y(((const tvec3&)v).y), z(((const tvec3&)v).z) { } template tvec3(const Impersonator< tvec2 >& v, B z) : x(((const tvec2&)v).x), y(((const tvec2&)v).y), z(z) { } // cross product works only on vectors of size 3 template friend inline tvec3 __attribute__((pure)) cross(const tvec3& u, const tvec3& v) { return tvec3( u.y*v.z - u.z*v.y, u.z*v.x - u.x*v.z, u.x*v.y - u.y*v.x); } }; // ---------------------------------------------------------------------------------------- typedef tvec3 vec3; // ---------------------------------------------------------------------------------------- }; // namespace android #endif /* UI_VEC4_H */ include/ui/vec4.h0100644 0000000 0000000 00000007232 13077405420 012665 0ustar000000000 0000000 /* * Copyright 2013 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 UI_VEC4_H #define UI_VEC4_H #include #include #include namespace android { // ------------------------------------------------------------------------------------- template class tvec4 : public TVecProductOperators, public TVecAddOperators, public TVecUnaryOperators, public TVecComparisonOperators, public TVecFunctions { public: enum no_init { NO_INIT }; typedef T value_type; typedef T& reference; typedef T const& const_reference; typedef size_t size_type; union { struct { T x, y, z, w; }; struct { T s, t, p, q; }; struct { T r, g, b, a; }; Impersonator< tvec2 > xy; Impersonator< tvec2 > st; Impersonator< tvec2 > rg; Impersonator< tvec3 > xyz; Impersonator< tvec3 > stp; Impersonator< tvec3 > rgb; }; enum { SIZE = 4 }; inline static size_type size() { return SIZE; } // array access inline T const& operator [] (size_t i) const { return (&x)[i]; } inline T& operator [] (size_t i) { return (&x)[i]; } // ----------------------------------------------------------------------- // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions // constructors // leaves object uninitialized. use with caution. explicit tvec4(no_init) { } // default constructor tvec4() : x(0), y(0), z(0), w(0) { } // handles implicit conversion to a tvec4. must not be explicit. template tvec4(A v) : x(v), y(v), z(v), w(v) { } template tvec4(A x, B y, C z, D w) : x(x), y(y), z(z), w(w) { } template tvec4(const tvec2& v, B z, C w) : x(v.x), y(v.y), z(z), w(w) { } template tvec4(const tvec3& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { } template explicit tvec4(const tvec4& v) : x(v.x), y(v.y), z(v.z), w(v.w) { } template tvec4(const Impersonator< tvec4 >& v) : x(((const tvec4&)v).x), y(((const tvec4&)v).y), z(((const tvec4&)v).z), w(((const tvec4&)v).w) { } template tvec4(const Impersonator< tvec3 >& v, B w) : x(((const tvec3&)v).x), y(((const tvec3&)v).y), z(((const tvec3&)v).z), w(w) { } template tvec4(const Impersonator< tvec2 >& v, B z, C w) : x(((const tvec2&)v).x), y(((const tvec2&)v).y), z(z), w(w) { } }; // ---------------------------------------------------------------------------------------- typedef tvec4 vec4; // ---------------------------------------------------------------------------------------- }; // namespace android #endif /* UI_VEC4_H */ libs/0040755 0000000 0000000 00000000000 13077405420 010543 5ustar000000000 0000000 libs/binder/0040755 0000000 0000000 00000000000 13077405420 012006 5ustar000000000 0000000 libs/binder/Android.mk0100644 0000000 0000000 00000003712 13077405420 013717 0ustar000000000 0000000 # Copyright (C) 2009 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. # we have the common sources, plus some device-specific stuff sources := \ AppOpsManager.cpp \ Binder.cpp \ BpBinder.cpp \ BufferedTextOutput.cpp \ Debug.cpp \ IAppOpsCallback.cpp \ IAppOpsService.cpp \ IBatteryStats.cpp \ IInterface.cpp \ IMediaResourceMonitor.cpp \ IMemory.cpp \ IPCThreadState.cpp \ IPermissionController.cpp \ IProcessInfoService.cpp \ IResultReceiver.cpp \ IServiceManager.cpp \ MemoryBase.cpp \ MemoryDealer.cpp \ MemoryHeapBase.cpp \ Parcel.cpp \ PermissionCache.cpp \ PersistableBundle.cpp \ ProcessInfoService.cpp \ ProcessState.cpp \ Static.cpp \ Status.cpp \ TextOutput.cpp \ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libbinder LOCAL_SHARED_LIBRARIES := liblog libcutils libutils LOCAL_CLANG := true LOCAL_SANITIZE := integer LOCAL_SRC_FILES := $(sources) ifneq ($(TARGET_USES_64_BIT_BINDER),true) ifneq ($(TARGET_IS_64_BIT),true) LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 endif endif LOCAL_CFLAGS += -Werror include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libbinder LOCAL_STATIC_LIBRARIES += libutils LOCAL_SRC_FILES := $(sources) ifneq ($(TARGET_USES_64_BIT_BINDER),true) ifneq ($(TARGET_IS_64_BIT),true) LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 endif endif LOCAL_CFLAGS += -Werror include $(BUILD_STATIC_LIBRARY) libs/binder/AppOpsManager.cpp0100644 0000000 0000000 00000007354 13077405420 015215 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include namespace android { static String16 _appops("appops"); static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER; static sp gToken; static const sp& getToken(const sp& service) { pthread_mutex_lock(&gTokenMutex); if (gToken == NULL || gToken->pingBinder() != NO_ERROR) { gToken = service->getToken(new BBinder()); } pthread_mutex_unlock(&gTokenMutex); return gToken; } AppOpsManager::AppOpsManager() { } sp AppOpsManager::getService() { int64_t startTime = 0; mLock.lock(); sp service = mService; while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { sp binder = defaultServiceManager()->checkService(_appops); if (binder == NULL) { // Wait for the app ops service to come back... if (startTime == 0) { startTime = uptimeMillis(); ALOGI("Waiting for app ops service"); } else if ((uptimeMillis()-startTime) > 10000) { ALOGW("Waiting too long for app ops service, giving up"); return NULL; } sleep(1); } else { service = interface_cast(binder); mService = service; } } mLock.unlock(); return service; } int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); return service != NULL ? service->checkOperation(op, uid, callingPackage) : MODE_IGNORED; } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); return service != NULL ? service->noteOperation(op, uid, callingPackage) : MODE_IGNORED; } int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); return service != NULL ? service->startOperation(getToken(service), op, uid, callingPackage) : MODE_IGNORED; } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); if (service != NULL) { service->finishOperation(getToken(service), op, uid, callingPackage); } } void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName, const sp& callback) { sp service = getService(); if (service != NULL) { service->startWatchingMode(op, packageName, callback); } } void AppOpsManager::stopWatchingMode(const sp& callback) { sp service = getService(); if (service != NULL) { service->stopWatchingMode(callback); } } int32_t AppOpsManager::permissionToOpCode(const String16& permission) { sp service = getService(); if (service != NULL) { return service->permissionToOpCode(permission); } return -1; } }; // namespace android libs/binder/Binder.cpp0100644 0000000 0000000 00000017066 13077405420 013724 0ustar000000000 0000000 /* * Copyright (C) 2005 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 #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- IBinder::IBinder() : RefBase() { } IBinder::~IBinder() { } // --------------------------------------------------------------------------- sp IBinder::queryLocalInterface(const String16& /*descriptor*/) { return NULL; } BBinder* IBinder::localBinder() { return NULL; } BpBinder* IBinder::remoteBinder() { return NULL; } bool IBinder::checkSubclass(const void* /*subclassID*/) const { return false; } status_t IBinder::shellCommand(const sp& target, int in, int out, int err, Vector& args, const sp& resultReceiver) { Parcel send; Parcel reply; send.writeFileDescriptor(in); send.writeFileDescriptor(out); send.writeFileDescriptor(err); const size_t numArgs = args.size(); send.writeInt32(numArgs); for (size_t i = 0; i < numArgs; i++) { send.writeString16(args[i]); } send.writeStrongBinder(resultReceiver != NULL ? IInterface::asBinder(resultReceiver) : NULL); return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply); } // --------------------------------------------------------------------------- class BBinder::Extras { public: Mutex mLock; BpBinder::ObjectManager mObjects; }; // --------------------------------------------------------------------------- BBinder::BBinder() : mExtras(nullptr) { } bool BBinder::isBinderAlive() const { return true; } status_t BBinder::pingBinder() { return NO_ERROR; } const String16& BBinder::getInterfaceDescriptor() const { // This is a local static rather than a global static, // to avoid static initializer ordering issues. static String16 sEmptyDescriptor; ALOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this); return sEmptyDescriptor; } status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { data.setDataPosition(0); status_t err = NO_ERROR; switch (code) { case PING_TRANSACTION: reply->writeInt32(pingBinder()); break; default: err = onTransact(code, data, reply, flags); break; } if (reply != NULL) { reply->setDataPosition(0); } return err; } status_t BBinder::linkToDeath( const sp& /*recipient*/, void* /*cookie*/, uint32_t /*flags*/) { return INVALID_OPERATION; } status_t BBinder::unlinkToDeath( const wp& /*recipient*/, void* /*cookie*/, uint32_t /*flags*/, wp* /*outRecipient*/) { return INVALID_OPERATION; } status_t BBinder::dump(int /*fd*/, const Vector& /*args*/) { return NO_ERROR; } void BBinder::attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) { Extras* e = mExtras.load(std::memory_order_acquire); if (!e) { e = new Extras; Extras* expected = nullptr; if (!mExtras.compare_exchange_strong(expected, e, std::memory_order_release, std::memory_order_acquire)) { delete e; e = expected; // Filled in by CAS } if (e == 0) return; // out of memory } AutoMutex _l(e->mLock); e->mObjects.attach(objectID, object, cleanupCookie, func); } void* BBinder::findObject(const void* objectID) const { Extras* e = mExtras.load(std::memory_order_acquire); if (!e) return NULL; AutoMutex _l(e->mLock); return e->mObjects.find(objectID); } void BBinder::detachObject(const void* objectID) { Extras* e = mExtras.load(std::memory_order_acquire); if (!e) return; AutoMutex _l(e->mLock); e->mObjects.detach(objectID); } BBinder* BBinder::localBinder() { return this; } BBinder::~BBinder() { Extras* e = mExtras.load(std::memory_order_relaxed); if (e) delete e; } status_t BBinder::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/) { switch (code) { case INTERFACE_TRANSACTION: reply->writeString16(getInterfaceDescriptor()); return NO_ERROR; case DUMP_TRANSACTION: { int fd = data.readFileDescriptor(); int argc = data.readInt32(); Vector args; for (int i = 0; i < argc && data.dataAvail() > 0; i++) { args.add(data.readString16()); } return dump(fd, args); } case SHELL_COMMAND_TRANSACTION: { int in = data.readFileDescriptor(); int out = data.readFileDescriptor(); int err = data.readFileDescriptor(); int argc = data.readInt32(); Vector args; for (int i = 0; i < argc && data.dataAvail() > 0; i++) { args.add(data.readString16()); } sp resultReceiver = IResultReceiver::asInterface( data.readStrongBinder()); // XXX can't add virtuals until binaries are updated. //return shellCommand(in, out, err, args, resultReceiver); if (resultReceiver != NULL) { resultReceiver->send(INVALID_OPERATION); } } case SYSPROPS_TRANSACTION: { report_sysprop_change(); return NO_ERROR; } default: return UNKNOWN_TRANSACTION; } } // --------------------------------------------------------------------------- enum { // This is used to transfer ownership of the remote binder from // the BpRefBase object holding it (when it is constructed), to the // owner of the BpRefBase object when it first acquires that BpRefBase. kRemoteAcquired = 0x00000001 }; BpRefBase::BpRefBase(const sp& o) : mRemote(o.get()), mRefs(NULL), mState(0) { extendObjectLifetime(OBJECT_LIFETIME_WEAK); if (mRemote) { mRemote->incStrong(this); // Removed on first IncStrong(). mRefs = mRemote->createWeak(this); // Held for our entire lifetime. } } BpRefBase::~BpRefBase() { if (mRemote) { if (!(mState.load(std::memory_order_relaxed)&kRemoteAcquired)) { mRemote->decStrong(this); } mRefs->decWeak(this); } } void BpRefBase::onFirstRef() { mState.fetch_or(kRemoteAcquired, std::memory_order_relaxed); } void BpRefBase::onLastStrongRef(const void* /*id*/) { if (mRemote) { mRemote->decStrong(this); } } bool BpRefBase::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) { return mRemote ? mRefs->attemptIncStrong(this) : false; } // --------------------------------------------------------------------------- }; // namespace android libs/binder/BpBinder.cpp0100644 0000000 0000000 00000023516 13077405420 014203 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "BpBinder" //#define LOG_NDEBUG 0 #include #include #include #include #include //#undef ALOGV //#define ALOGV(...) fprintf(stderr, __VA_ARGS__) namespace android { // --------------------------------------------------------------------------- BpBinder::ObjectManager::ObjectManager() { } BpBinder::ObjectManager::~ObjectManager() { kill(); } void BpBinder::ObjectManager::attach( const void* objectID, void* object, void* cleanupCookie, IBinder::object_cleanup_func func) { entry_t e; e.object = object; e.cleanupCookie = cleanupCookie; e.func = func; if (mObjects.indexOfKey(objectID) >= 0) { ALOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use", objectID, this, object); return; } mObjects.add(objectID, e); } void* BpBinder::ObjectManager::find(const void* objectID) const { const ssize_t i = mObjects.indexOfKey(objectID); if (i < 0) return NULL; return mObjects.valueAt(i).object; } void BpBinder::ObjectManager::detach(const void* objectID) { mObjects.removeItem(objectID); } void BpBinder::ObjectManager::kill() { const size_t N = mObjects.size(); ALOGV("Killing %zu objects in manager %p", N, this); for (size_t i=0; iincWeakHandle(handle); } bool BpBinder::isDescriptorCached() const { Mutex::Autolock _l(mLock); return mDescriptorCache.size() ? true : false; } const String16& BpBinder::getInterfaceDescriptor() const { if (isDescriptorCached() == false) { Parcel send, reply; // do the IPC without a lock held. status_t err = const_cast(this)->transact( INTERFACE_TRANSACTION, send, &reply); if (err == NO_ERROR) { String16 res(reply.readString16()); Mutex::Autolock _l(mLock); // mDescriptorCache could have been assigned while the lock was // released. if (mDescriptorCache.size() == 0) mDescriptorCache = res; } } // we're returning a reference to a non-static object here. Usually this // is not something smart to do, however, with binder objects it is // (usually) safe because they are reference-counted. return mDescriptorCache; } bool BpBinder::isBinderAlive() const { return mAlive != 0; } status_t BpBinder::pingBinder() { Parcel send; Parcel reply; status_t err = transact(PING_TRANSACTION, send, &reply); if (err != NO_ERROR) return err; if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA; return (status_t)reply.readInt32(); } status_t BpBinder::dump(int fd, const Vector& args) { Parcel send; Parcel reply; send.writeFileDescriptor(fd); const size_t numArgs = args.size(); send.writeInt32(numArgs); for (size_t i = 0; i < numArgs; i++) { send.writeString16(args[i]); } status_t err = transact(DUMP_TRANSACTION, send, &reply); return err; } status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT; } status_t BpBinder::linkToDeath( const sp& recipient, void* cookie, uint32_t flags) { Obituary ob; ob.recipient = recipient; ob.cookie = cookie; ob.flags = flags; LOG_ALWAYS_FATAL_IF(recipient == NULL, "linkToDeath(): recipient must be non-NULL"); { AutoMutex _l(mLock); if (!mObitsSent) { if (!mObituaries) { mObituaries = new Vector; if (!mObituaries) { return NO_MEMORY; } ALOGV("Requesting death notification: %p handle %d\n", this, mHandle); getWeakRefs()->incWeak(this); IPCThreadState* self = IPCThreadState::self(); self->requestDeathNotification(mHandle, this); self->flushCommands(); } ssize_t res = mObituaries->add(ob); return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res; } } return DEAD_OBJECT; } status_t BpBinder::unlinkToDeath( const wp& recipient, void* cookie, uint32_t flags, wp* outRecipient) { AutoMutex _l(mLock); if (mObitsSent) { return DEAD_OBJECT; } const size_t N = mObituaries ? mObituaries->size() : 0; for (size_t i=0; iitemAt(i); if ((obit.recipient == recipient || (recipient == NULL && obit.cookie == cookie)) && obit.flags == flags) { if (outRecipient != NULL) { *outRecipient = mObituaries->itemAt(i).recipient; } mObituaries->removeAt(i); if (mObituaries->size() == 0) { ALOGV("Clearing death notification: %p handle %d\n", this, mHandle); IPCThreadState* self = IPCThreadState::self(); self->clearDeathNotification(mHandle, this); self->flushCommands(); delete mObituaries; mObituaries = NULL; } return NO_ERROR; } } return NAME_NOT_FOUND; } void BpBinder::sendObituary() { ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, mHandle, mObitsSent ? "true" : "false"); mAlive = 0; if (mObitsSent) return; mLock.lock(); Vector* obits = mObituaries; if(obits != NULL) { ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle); IPCThreadState* self = IPCThreadState::self(); self->clearDeathNotification(mHandle, this); self->flushCommands(); mObituaries = NULL; } mObitsSent = 1; mLock.unlock(); ALOGV("Reporting death of proxy %p for %zu recipients\n", this, obits ? obits->size() : 0U); if (obits != NULL) { const size_t N = obits->size(); for (size_t i=0; iitemAt(i)); } delete obits; } } void BpBinder::reportOneDeath(const Obituary& obit) { sp recipient = obit.recipient.promote(); ALOGV("Reporting death to recipient: %p\n", recipient.get()); if (recipient == NULL) return; recipient->binderDied(this); } void BpBinder::attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) { AutoMutex _l(mLock); ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects); mObjects.attach(objectID, object, cleanupCookie, func); } void* BpBinder::findObject(const void* objectID) const { AutoMutex _l(mLock); return mObjects.find(objectID); } void BpBinder::detachObject(const void* objectID) { AutoMutex _l(mLock); mObjects.detach(objectID); } BpBinder* BpBinder::remoteBinder() { return this; } BpBinder::~BpBinder() { ALOGV("Destroying BpBinder %p handle %d\n", this, mHandle); IPCThreadState* ipc = IPCThreadState::self(); mLock.lock(); Vector* obits = mObituaries; if(obits != NULL) { if (ipc) ipc->clearDeathNotification(mHandle, this); mObituaries = NULL; } mLock.unlock(); if (obits != NULL) { // XXX Should we tell any remaining DeathRecipient // objects that the last strong ref has gone away, so they // are no longer linked? delete obits; } if (ipc) { ipc->expungeHandle(mHandle, this); ipc->decWeakHandle(mHandle); } } void BpBinder::onFirstRef() { ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle); IPCThreadState* ipc = IPCThreadState::self(); if (ipc) ipc->incStrongHandle(mHandle); } void BpBinder::onLastStrongRef(const void* /*id*/) { ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle); IF_ALOGV() { printRefs(); } IPCThreadState* ipc = IPCThreadState::self(); if (ipc) ipc->decStrongHandle(mHandle); } bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) { ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle); IPCThreadState* ipc = IPCThreadState::self(); return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } // --------------------------------------------------------------------------- }; // namespace android libs/binder/BufferedTextOutput.cpp0100644 0000000 0000000 00000017143 13077405420 016325 0ustar000000000 0000000 /* * Copyright (C) 2006 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 #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { struct BufferedTextOutput::BufferState : public RefBase { BufferState(int32_t _seq) : seq(_seq) , buffer(NULL) , bufferPos(0) , bufferSize(0) , atFront(true) , indent(0) , bundle(0) { } ~BufferState() { free(buffer); } status_t append(const char* txt, size_t len) { if ((len+bufferPos) > bufferSize) { size_t newSize = ((len+bufferPos)*3)/2; if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow void* b = realloc(buffer, newSize); if (!b) return NO_MEMORY; buffer = (char*)b; bufferSize = newSize; } memcpy(buffer+bufferPos, txt, len); bufferPos += len; return NO_ERROR; } void restart() { bufferPos = 0; atFront = true; if (bufferSize > 256) { void* b = realloc(buffer, 256); if (b) { buffer = (char*)b; bufferSize = 256; } } } const int32_t seq; char* buffer; size_t bufferPos; size_t bufferSize; bool atFront; int32_t indent; int32_t bundle; }; struct BufferedTextOutput::ThreadState { Vector > states; }; static mutex_t gMutex; static thread_store_t tls; BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState() { ThreadState* ts = (ThreadState*) thread_store_get( &tls ); if (ts) return ts; ts = new ThreadState; thread_store_set( &tls, ts, threadDestructor ); return ts; } void BufferedTextOutput::threadDestructor(void *st) { delete ((ThreadState*)st); } static volatile int32_t gSequence = 0; static volatile int32_t gFreeBufferIndex = -1; static int32_t allocBufferIndex() { int32_t res = -1; mutex_lock(&gMutex); if (gFreeBufferIndex >= 0) { res = gFreeBufferIndex; gFreeBufferIndex = gTextBuffers[res]; gTextBuffers.editItemAt(res) = -1; } else { res = gTextBuffers.size(); gTextBuffers.add(-1); } mutex_unlock(&gMutex); return res; } static void freeBufferIndex(int32_t idx) { mutex_lock(&gMutex); gTextBuffers.editItemAt(idx) = gFreeBufferIndex; gFreeBufferIndex = idx; mutex_unlock(&gMutex); } // --------------------------------------------------------------------------- BufferedTextOutput::BufferedTextOutput(uint32_t flags) : mFlags(flags) , mSeq(android_atomic_inc(&gSequence)) , mIndex(allocBufferIndex()) { mGlobalState = new BufferState(mSeq); if (mGlobalState) mGlobalState->incStrong(this); } BufferedTextOutput::~BufferedTextOutput() { if (mGlobalState) mGlobalState->decStrong(this); freeBufferIndex(mIndex); } status_t BufferedTextOutput::print(const char* txt, size_t len) { //printf("BufferedTextOutput: printing %d\n", len); AutoMutex _l(mLock); BufferState* b = getBuffer(); const char* const end = txt+len; status_t err; while (txt < end) { // Find the next line. const char* first = txt; while (txt < end && *txt != '\n') txt++; // Include this and all following empty lines. while (txt < end && *txt == '\n') txt++; // Special cases for first data on a line. if (b->atFront) { if (b->indent > 0) { // If this is the start of a line, add the indent. const char* prefix = stringForIndent(b->indent); err = b->append(prefix, strlen(prefix)); if (err != NO_ERROR) return err; } else if (*(txt-1) == '\n' && !b->bundle) { // Fast path: if we are not indenting or bundling, and // have been given one or more complete lines, just write // them out without going through the buffer. // Slurp up all of the lines. const char* lastLine = txt+1; while (txt < end) { if (*txt++ == '\n') lastLine = txt; } struct iovec vec; vec.iov_base = (void*)first; vec.iov_len = lastLine-first; //printf("Writing %d bytes of data!\n", vec.iov_len); writeLines(vec, 1); txt = lastLine; continue; } } // Append the new text to the buffer. err = b->append(first, txt-first); if (err != NO_ERROR) return err; b->atFront = *(txt-1) == '\n'; // If we have finished a line and are not bundling, write // it out. //printf("Buffer is now %d bytes\n", b->bufferPos); if (b->atFront && !b->bundle) { struct iovec vec; vec.iov_base = b->buffer; vec.iov_len = b->bufferPos; //printf("Writing %d bytes of data!\n", vec.iov_len); writeLines(vec, 1); b->restart(); } } return NO_ERROR; } void BufferedTextOutput::moveIndent(int delta) { AutoMutex _l(mLock); BufferState* b = getBuffer(); b->indent += delta; if (b->indent < 0) b->indent = 0; } void BufferedTextOutput::pushBundle() { AutoMutex _l(mLock); BufferState* b = getBuffer(); b->bundle++; } void BufferedTextOutput::popBundle() { AutoMutex _l(mLock); BufferState* b = getBuffer(); b->bundle--; LOG_FATAL_IF(b->bundle < 0, "TextOutput::popBundle() called more times than pushBundle()"); if (b->bundle < 0) b->bundle = 0; if (b->bundle == 0) { // Last bundle, write out data if it is complete. If it is not // complete, don't write until the last line is done... this may // or may not be the write thing to do, but it's the easiest. if (b->bufferPos > 0 && b->atFront) { struct iovec vec; vec.iov_base = b->buffer; vec.iov_len = b->bufferPos; writeLines(vec, 1); b->restart(); } } } BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const { if ((mFlags&MULTITHREADED) != 0) { ThreadState* ts = getThreadState(); if (ts) { while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL); BufferState* bs = ts->states[mIndex].get(); if (bs != NULL && bs->seq == mSeq) return bs; ts->states.editItemAt(mIndex) = new BufferState(mIndex); bs = ts->states[mIndex].get(); if (bs != NULL) return bs; } } return mGlobalState; } }; // namespace android libs/binder/Debug.cpp0100644 0000000 0000000 00000017721 13077405420 013545 0ustar000000000 0000000 /* * Copyright (C) 2005 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 #include #include #include #include namespace android { // --------------------------------------------------------------------- static const char indentStr[] = " " " "; const char* stringForIndent(int32_t indentLevel) { ssize_t off = sizeof(indentStr)-1-(indentLevel*2); return indentStr + (off < 0 ? 0 : off); } // --------------------------------------------------------------------- static void defaultPrintFunc(void* /*cookie*/, const char* txt) { printf("%s", txt); } // --------------------------------------------------------------------- static inline int isident(int c) { return isalnum(c) || c == '_'; } static inline bool isasciitype(char c) { if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; return false; } static inline char makehexdigit(uint32_t val) { return "0123456789abcdef"[val&0xF]; } static char* appendhexnum(uint32_t val, char* out) { for( int32_t i=28; i>=0; i-=4 ) { *out++ = makehexdigit( val>>i ); } *out = 0; return out; } static char* appendcharornum(char c, char* out, bool skipzero = true) { if (skipzero && c == 0) return out; if (isasciitype(c)) { *out++ = c; return out; } *out++ = '\\'; *out++ = 'x'; *out++ = makehexdigit(c>>4); *out++ = makehexdigit(c); return out; } static char* typetostring(uint32_t type, char* out, bool fullContext = true, bool strict = false) { char* pos = out; char c[4]; c[0] = (char)((type>>24)&0xFF); c[1] = (char)((type>>16)&0xFF); c[2] = (char)((type>>8)&0xFF); c[3] = (char)(type&0xFF); bool valid; if( !strict ) { // now even less strict! // valid = isasciitype(c[3]); valid = true; int32_t i = 0; bool zero = true; while (valid && i<3) { if (c[i] == 0) { if (!zero) valid = false; } else { zero = false; //if (!isasciitype(c[i])) valid = false; } i++; } // if all zeros, not a valid type code. if (zero) valid = false; } else { valid = isident(c[3]) ? true : false; int32_t i = 0; bool zero = true; while (valid && i<3) { if (c[i] == 0) { if (!zero) valid = false; } else { zero = false; if (!isident(c[i])) valid = false; } i++; } } if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { if( fullContext ) *pos++ = '\''; pos = appendcharornum(c[0], pos); pos = appendcharornum(c[1], pos); pos = appendcharornum(c[2], pos); pos = appendcharornum(c[3], pos); if( fullContext ) *pos++ = '\''; *pos = 0; return pos; } if( fullContext ) { *pos++ = '0'; *pos++ = 'x'; } return appendhexnum(type, pos); } void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) { char buffer[32]; char* end = typetostring(typeCode, buffer); *end = 0; func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); } void printHexData(int32_t indent, const void *buf, size_t length, size_t bytesPerLine, int32_t singleLineBytesCutoff, size_t alignment, bool cStyle, debugPrintFunc func, void* cookie) { if (alignment == 0) { if (bytesPerLine >= 16) alignment = 4; else if (bytesPerLine >= 8) alignment = 2; else alignment = 1; } if (func == NULL) func = defaultPrintFunc; size_t offset; unsigned char *pos = (unsigned char *)buf; if (pos == NULL) { if (singleLineBytesCutoff < 0) func(cookie, "\n"); func(cookie, "(NULL)"); return; } if (length == 0) { if (singleLineBytesCutoff < 0) func(cookie, "\n"); func(cookie, "(empty)"); return; } if ((int32_t)length < 0) { if (singleLineBytesCutoff < 0) func(cookie, "\n"); char buf[64]; sprintf(buf, "(bad length: %zu)", length); func(cookie, buf); return; } char buffer[256]; static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; const bool oneLine = (int32_t)length <= singleLineBytesCutoff; bool newLine = false; if (cStyle) { indent++; func(cookie, "{\n"); newLine = true; } else if (!oneLine) { func(cookie, "\n"); newLine = true; } for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { long remain = length; char* c = buffer; if (!oneLine && !cStyle) { sprintf(c, "0x%08x: ", (int)offset); c += 12; } size_t index; size_t word; for (word = 0; word < bytesPerLine; ) { const size_t startIndex = word+(alignment-(alignment?1:0)); for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { if (!cStyle) { if (index == 0 && word > 0 && alignment > 0) { *c++ = ' '; } if (remain-- > 0) { const unsigned char val = *(pos+startIndex-index); *c++ = makehexdigit(val>>4); *c++ = makehexdigit(val); } else if (!oneLine) { *c++ = ' '; *c++ = ' '; } } else { if (remain > 0) { if (index == 0 && word > 0) { *c++ = ','; *c++ = ' '; } if (index == 0) { *c++ = '0'; *c++ = 'x'; } const unsigned char val = *(pos+startIndex-index); *c++ = makehexdigit(val>>4); *c++ = makehexdigit(val); remain--; } } } word += index; } if (!cStyle) { remain = length; *c++ = ' '; *c++ = '\''; for (index = 0; index < bytesPerLine; index++) { if (remain-- > 0) { const unsigned char val = pos[index]; *c++ = (val >= ' ' && val < 127) ? val : '.'; } else if (!oneLine) { *c++ = ' '; } } *c++ = '\''; if (length > bytesPerLine) *c++ = '\n'; } else { if (remain > 0) *c++ = ','; *c++ = '\n'; } if (newLine && indent) func(cookie, stringForIndent(indent)); *c = 0; func(cookie, buffer); newLine = true; if (length <= bytesPerLine) break; length -= bytesPerLine; } if (cStyle) { if (indent > 0) func(cookie, stringForIndent(indent-1)); func(cookie, "};"); } } }; // namespace android libs/binder/IAppOpsCallback.cpp0100644 0000000 0000000 00000004120 13077405420 015434 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "AppOpsCallback" #include #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpAppOpsCallback : public BpInterface { public: BpAppOpsCallback(const sp& impl) : BpInterface(impl) { } virtual void opChanged(int32_t op, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsCallback::getInterfaceDescriptor()); data.writeInt32(op); data.writeString16(packageName); remote()->transact(OP_CHANGED_TRANSACTION, data, &reply); } }; IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback"); // ---------------------------------------------------------------------- status_t BnAppOpsCallback::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case OP_CHANGED_TRANSACTION: { CHECK_INTERFACE(IAppOpsCallback, data, reply); int32_t op = data.readInt32(); String16 packageName = data.readString16(); opChanged(op, packageName); reply->writeNoException(); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/binder/IAppOpsService.cpp0100644 0000000 0000000 00000020432 13077405420 015344 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "AppOpsService" #include #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpAppOpsService : public BpInterface { public: BpAppOpsService(const sp& impl) : BpInterface(impl) { } virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); remote()->transact(CHECK_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; return reply.readInt32(); } virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; return reply.readInt32(); } virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); remote()->transact(START_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; return reply.readInt32(); } virtual void finishOperation(const sp& token, int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); } virtual void startWatchingMode(int32_t op, const String16& packageName, const sp& callback) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(op); data.writeString16(packageName); data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(START_WATCHING_MODE_TRANSACTION, data, &reply); } virtual void stopWatchingMode(const sp& callback) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply); } virtual sp getToken(const sp& clientToken) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(clientToken); remote()->transact(GET_TOKEN_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return NULL; return reply.readStrongBinder(); } virtual int32_t permissionToOpCode(const String16& permission) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeString16(permission); remote()->transact(PERMISSION_TO_OP_CODE_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return -1; return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); // ---------------------------------------------------------------------- status_t BnAppOpsService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { //printf("AppOpsService received: "); data.print(); switch(code) { case CHECK_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); int32_t res = checkOperation(code, uid, packageName); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; case NOTE_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); int32_t res = noteOperation(code, uid, packageName); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; case START_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp token = data.readStrongBinder(); int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); int32_t res = startOperation(token, code, uid, packageName); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; case FINISH_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp token = data.readStrongBinder(); int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); finishOperation(token, code, uid, packageName); reply->writeNoException(); return NO_ERROR; } break; case START_WATCHING_MODE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t op = data.readInt32(); String16 packageName = data.readString16(); sp callback = interface_cast(data.readStrongBinder()); startWatchingMode(op, packageName, callback); reply->writeNoException(); return NO_ERROR; } break; case STOP_WATCHING_MODE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp callback = interface_cast(data.readStrongBinder()); stopWatchingMode(callback); reply->writeNoException(); return NO_ERROR; } break; case GET_TOKEN_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp clientToken = data.readStrongBinder(); sp token = getToken(clientToken); reply->writeNoException(); reply->writeStrongBinder(token); return NO_ERROR; } break; case PERMISSION_TO_OP_CODE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); String16 permission = data.readString16(); const int32_t opCode = permissionToOpCode(permission); reply->writeNoException(); reply->writeInt32(opCode); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/binder/IBatteryStats.cpp0100644 0000000 0000000 00000020565 13077405420 015261 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpBatteryStats : public BpInterface { public: BpBatteryStats(const sp& impl) : BpInterface(impl) { } virtual void noteStartSensor(int uid, int sensor) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); data.writeInt32(sensor); remote()->transact(NOTE_START_SENSOR_TRANSACTION, data, &reply); } virtual void noteStopSensor(int uid, int sensor) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); data.writeInt32(sensor); remote()->transact(NOTE_STOP_SENSOR_TRANSACTION, data, &reply); } virtual void noteStartVideo(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_START_VIDEO_TRANSACTION, data, &reply); } virtual void noteStopVideo(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_STOP_VIDEO_TRANSACTION, data, &reply); } virtual void noteStartAudio(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_START_AUDIO_TRANSACTION, data, &reply); } virtual void noteStopAudio(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_STOP_AUDIO_TRANSACTION, data, &reply); } virtual void noteResetVideo() { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_VIDEO_TRANSACTION, data, &reply); } virtual void noteResetAudio() { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply); } virtual void noteFlashlightOn(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_FLASHLIGHT_ON_TRANSACTION, data, &reply); } virtual void noteFlashlightOff(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_FLASHLIGHT_OFF_TRANSACTION, data, &reply); } virtual void noteStartCamera(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_START_CAMERA_TRANSACTION, data, &reply); } virtual void noteStopCamera(int uid) { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(NOTE_STOP_CAMERA_TRANSACTION, data, &reply); } virtual void noteResetCamera() { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_CAMERA_TRANSACTION, data, &reply); } virtual void noteResetFlashlight() { Parcel data, reply; data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_FLASHLIGHT_TRANSACTION, data, &reply); } }; IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats"); // ---------------------------------------------------------------------- status_t BnBatteryStats::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case NOTE_START_SENSOR_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); int sensor = data.readInt32(); noteStartSensor(uid, sensor); reply->writeNoException(); return NO_ERROR; } break; case NOTE_STOP_SENSOR_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); int sensor = data.readInt32(); noteStopSensor(uid, sensor); reply->writeNoException(); return NO_ERROR; } break; case NOTE_START_VIDEO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStartVideo(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_STOP_VIDEO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStopVideo(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_START_AUDIO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStartAudio(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_STOP_AUDIO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStopAudio(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_RESET_VIDEO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); noteResetVideo(); reply->writeNoException(); return NO_ERROR; } break; case NOTE_RESET_AUDIO_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); noteResetAudio(); reply->writeNoException(); return NO_ERROR; } break; case NOTE_FLASHLIGHT_ON_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteFlashlightOn(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_FLASHLIGHT_OFF_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteFlashlightOff(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_START_CAMERA_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStartCamera(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_STOP_CAMERA_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); int uid = data.readInt32(); noteStopCamera(uid); reply->writeNoException(); return NO_ERROR; } break; case NOTE_RESET_CAMERA_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); noteResetCamera(); reply->writeNoException(); return NO_ERROR; } break; case NOTE_RESET_FLASHLIGHT_TRANSACTION: { CHECK_INTERFACE(IBatteryStats, data, reply); noteResetFlashlight(); reply->writeNoException(); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/binder/IInterface.cpp0100644 0000000 0000000 00000003734 13077405420 014527 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "IInterface" #include #include namespace android { // --------------------------------------------------------------------------- IInterface::IInterface() : RefBase() { } IInterface::~IInterface() { } // static sp IInterface::asBinder(const IInterface* iface) { if (iface == NULL) return NULL; return const_cast(iface)->onAsBinder(); } // static sp IInterface::asBinder(const sp& iface) { if (iface == NULL) return NULL; return iface->onAsBinder(); } // --------------------------------------------------------------------------- }; // namespace android extern "C" { void _ZN7android10IInterface8asBinderEv(void *retval, void* self) { ALOGW("deprecated asBinder call, please update your code"); //ALOGI("self: %p, retval: %p", self, retval); android::sp *ret = new(retval) android::sp; *ret = android::IInterface::asBinder((android::IInterface*)self); } void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) { ALOGW("deprecated asBinder call, please update your code"); //ALOGI("self: %p, retval: %p", self, retval); android::sp *ret = new(retval) android::sp; *ret = android::IInterface::asBinder((android::IInterface*)self); } } // extern "C" libs/binder/IMediaResourceMonitor.cpp0100644 0000000 0000000 00000004211 13077405420 016715 0ustar000000000 0000000 /* * Copyright 2016 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 #include #include #include namespace android { // ---------------------------------------------------------------------- class BpMediaResourceMonitor : public BpInterface { public: BpMediaResourceMonitor(const sp& impl) : BpInterface(impl) {} virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) { Parcel data, reply; data.writeInterfaceToken(IMediaResourceMonitor::getInterfaceDescriptor()); data.writeInt32(pid); data.writeInt32(type); remote()->transact(NOTIFY_RESOURCE_GRANTED, data, &reply, IBinder::FLAG_ONEWAY); } }; IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor"); // ---------------------------------------------------------------------- status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case NOTIFY_RESOURCE_GRANTED: { CHECK_INTERFACE(IMediaResourceMonitor, data, reply); int32_t pid = data.readInt32(); const int32_t type = data.readInt32(); notifyResourceGranted(/*in*/ pid, /*in*/ type); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } // ---------------------------------------------------------------------- }; // namespace android libs/binder/IMemory.cpp0100644 0000000 0000000 00000033661 13077405420 014101 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ #define LOG_TAG "IMemory" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERBOSE 0 namespace android { // --------------------------------------------------------------------------- class HeapCache : public IBinder::DeathRecipient { public: HeapCache(); virtual ~HeapCache(); virtual void binderDied(const wp& who); sp find_heap(const sp& binder); void free_heap(const sp& binder); sp get_heap(const sp& binder); void dump_heaps(); private: // For IMemory.cpp struct heap_info_t { sp heap; int32_t count; }; void free_heap(const wp& binder); Mutex mHeapCacheLock; KeyedVector< wp, heap_info_t > mHeapCache; }; static sp gHeapCache = new HeapCache(); /******************************************************************************/ enum { HEAP_ID = IBinder::FIRST_CALL_TRANSACTION }; class BpMemoryHeap : public BpInterface { public: BpMemoryHeap(const sp& impl); virtual ~BpMemoryHeap(); virtual int getHeapID() const; virtual void* getBase() const; virtual size_t getSize() const; virtual uint32_t getFlags() const; virtual uint32_t getOffset() const; private: friend class IMemory; friend class HeapCache; // for debugging in this module static inline sp find_heap(const sp& binder) { return gHeapCache->find_heap(binder); } static inline void free_heap(const sp& binder) { gHeapCache->free_heap(binder); } static inline sp get_heap(const sp& binder) { return gHeapCache->get_heap(binder); } static inline void dump_heaps() { gHeapCache->dump_heaps(); } void assertMapped() const; void assertReallyMapped() const; mutable volatile int32_t mHeapId; mutable void* mBase; mutable size_t mSize; mutable uint32_t mFlags; mutable uint32_t mOffset; mutable bool mRealHeap; mutable Mutex mLock; }; // ---------------------------------------------------------------------------- enum { GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION }; class BpMemory : public BpInterface { public: BpMemory(const sp& impl); virtual ~BpMemory(); virtual sp getMemory(ssize_t* offset=0, size_t* size=0) const; private: mutable sp mHeap; mutable ssize_t mOffset; mutable size_t mSize; }; /******************************************************************************/ void* IMemory::fastPointer(const sp& binder, ssize_t offset) const { sp realHeap = BpMemoryHeap::get_heap(binder); void* const base = realHeap->base(); if (base == MAP_FAILED) return 0; return static_cast(base) + offset; } void* IMemory::pointer() const { ssize_t offset; sp heap = getMemory(&offset); void* const base = heap!=0 ? heap->base() : MAP_FAILED; if (base == MAP_FAILED) return 0; return static_cast(base) + offset; } size_t IMemory::size() const { size_t size; getMemory(NULL, &size); return size; } ssize_t IMemory::offset() const { ssize_t offset; getMemory(&offset); return offset; } /******************************************************************************/ BpMemory::BpMemory(const sp& impl) : BpInterface(impl), mOffset(0), mSize(0) { } BpMemory::~BpMemory() { } sp BpMemory::getMemory(ssize_t* offset, size_t* size) const { if (mHeap == 0) { Parcel data, reply; data.writeInterfaceToken(IMemory::getInterfaceDescriptor()); if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) { sp heap = reply.readStrongBinder(); ssize_t o = reply.readInt32(); size_t s = reply.readInt32(); if (heap != 0) { mHeap = interface_cast(heap); if (mHeap != 0) { size_t heapSize = mHeap->getSize(); if (s <= heapSize && o >= 0 && (static_cast(o) <= heapSize - s)) { mOffset = o; mSize = s; } else { // Hm. android_errorWriteWithInfoLog(0x534e4554, "26877992", -1, NULL, 0); mOffset = 0; mSize = 0; } } } } } if (offset) *offset = mOffset; if (size) *size = mSize; return (mSize > 0) ? mHeap : 0; } // --------------------------------------------------------------------------- IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory"); BnMemory::BnMemory() { } BnMemory::~BnMemory() { } status_t BnMemory::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case GET_MEMORY: { CHECK_INTERFACE(IMemory, data, reply); ssize_t offset; size_t size; reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) ); reply->writeInt32(offset); reply->writeInt32(size); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } /******************************************************************************/ BpMemoryHeap::BpMemoryHeap(const sp& impl) : BpInterface(impl), mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false) { } BpMemoryHeap::~BpMemoryHeap() { if (mHeapId != -1) { close(mHeapId); if (mRealHeap) { // by construction we're the last one if (mBase != MAP_FAILED) { sp binder = IInterface::asBinder(this); if (VERBOSE) { ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d", binder.get(), this, mSize, mHeapId); CallStack stack(LOG_TAG); } munmap(mBase, mSize); } } else { // remove from list only if it was mapped before sp binder = IInterface::asBinder(this); free_heap(binder); } } } void BpMemoryHeap::assertMapped() const { if (mHeapId == -1) { sp binder(IInterface::asBinder(const_cast(this))); sp heap(static_cast(find_heap(binder).get())); heap->assertReallyMapped(); if (heap->mBase != MAP_FAILED) { Mutex::Autolock _l(mLock); if (mHeapId == -1) { mBase = heap->mBase; mSize = heap->mSize; mOffset = heap->mOffset; android_atomic_write( dup( heap->mHeapId ), &mHeapId ); } } else { // something went wrong free_heap(binder); } } } void BpMemoryHeap::assertReallyMapped() const { if (mHeapId == -1) { // remote call without mLock held, worse case scenario, we end up // calling transact() from multiple threads, but that's not a problem, // only mmap below must be in the critical section. Parcel data, reply; data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor()); status_t err = remote()->transact(HEAP_ID, data, &reply); int parcel_fd = reply.readFileDescriptor(); ssize_t size = reply.readInt32(); uint32_t flags = reply.readInt32(); uint32_t offset = reply.readInt32(); ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)", IInterface::asBinder(this).get(), parcel_fd, size, err, strerror(-err)); Mutex::Autolock _l(mLock); if (mHeapId == -1) { int fd = dup( parcel_fd ); ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)", parcel_fd, size, err, strerror(errno)); int access = PROT_READ; if (!(flags & READ_ONLY)) { access |= PROT_WRITE; } mRealHeap = true; mBase = mmap(0, size, access, MAP_SHARED, fd, offset); if (mBase == MAP_FAILED) { ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)", IInterface::asBinder(this).get(), size, fd, strerror(errno)); close(fd); } else { mSize = size; mFlags = flags; mOffset = offset; android_atomic_write(fd, &mHeapId); } } } } int BpMemoryHeap::getHeapID() const { assertMapped(); return mHeapId; } void* BpMemoryHeap::getBase() const { assertMapped(); return mBase; } size_t BpMemoryHeap::getSize() const { assertMapped(); return mSize; } uint32_t BpMemoryHeap::getFlags() const { assertMapped(); return mFlags; } uint32_t BpMemoryHeap::getOffset() const { assertMapped(); return mOffset; } // --------------------------------------------------------------------------- IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap"); BnMemoryHeap::BnMemoryHeap() { } BnMemoryHeap::~BnMemoryHeap() { } status_t BnMemoryHeap::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case HEAP_ID: { CHECK_INTERFACE(IMemoryHeap, data, reply); reply->writeFileDescriptor(getHeapID()); reply->writeInt32(getSize()); reply->writeInt32(getFlags()); reply->writeInt32(getOffset()); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } /*****************************************************************************/ HeapCache::HeapCache() : DeathRecipient() { } HeapCache::~HeapCache() { } void HeapCache::binderDied(const wp& binder) { //ALOGD("binderDied binder=%p", binder.unsafe_get()); free_heap(binder); } sp HeapCache::find_heap(const sp& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info = mHeapCache.editValueAt(i); ALOGD_IF(VERBOSE, "found binder=%p, heap=%p, size=%zu, fd=%d, count=%d", binder.get(), info.heap.get(), static_cast(info.heap.get())->mSize, static_cast(info.heap.get())->mHeapId, info.count); android_atomic_inc(&info.count); return info.heap; } else { heap_info_t info; info.heap = interface_cast(binder); info.count = 1; //ALOGD("adding binder=%p, heap=%p, count=%d", // binder.get(), info.heap.get(), info.count); mHeapCache.add(binder, info); return info.heap; } } void HeapCache::free_heap(const sp& binder) { free_heap( wp(binder) ); } void HeapCache::free_heap(const wp& binder) { sp rel; { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info(mHeapCache.editValueAt(i)); int32_t c = android_atomic_dec(&info.count); if (c == 1) { ALOGD_IF(VERBOSE, "removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d", binder.unsafe_get(), info.heap.get(), static_cast(info.heap.get())->mSize, static_cast(info.heap.get())->mHeapId, info.count); rel = mHeapCache.valueAt(i).heap; mHeapCache.removeItemsAt(i); } } else { ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get()); } } } sp HeapCache::get_heap(const sp& binder) { sp realHeap; Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) realHeap = mHeapCache.valueAt(i).heap; else realHeap = interface_cast(binder); return realHeap; } void HeapCache::dump_heaps() { Mutex::Autolock _l(mHeapCacheLock); int c = mHeapCache.size(); for (int i=0 ; i(info.heap.get())); ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)", mHeapCache.keyAt(i).unsafe_get(), info.heap.get(), info.count, h->mHeapId, h->mBase, h->mSize); } } // --------------------------------------------------------------------------- }; // namespace android libs/binder/IPCThreadState.cpp0100644 0000000 0000000 00000113204 13077405420 015254 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "IPCThreadState" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LOG_NDEBUG #define IF_LOG_TRANSACTIONS() if (false) #define IF_LOG_COMMANDS() if (false) #define LOG_REMOTEREFS(...) #define IF_LOG_REMOTEREFS() if (false) #define LOG_THREADPOOL(...) #define LOG_ONEWAY(...) #else #define IF_LOG_TRANSACTIONS() IF_ALOG(LOG_VERBOSE, "transact") #define IF_LOG_COMMANDS() IF_ALOG(LOG_VERBOSE, "ipc") #define LOG_REMOTEREFS(...) ALOG(LOG_DEBUG, "remoterefs", __VA_ARGS__) #define IF_LOG_REMOTEREFS() IF_ALOG(LOG_DEBUG, "remoterefs") #define LOG_THREADPOOL(...) ALOG(LOG_DEBUG, "threadpool", __VA_ARGS__) #define LOG_ONEWAY(...) ALOG(LOG_DEBUG, "ipc", __VA_ARGS__) #endif // --------------------------------------------------------------------------- namespace android { static const char* getReturnString(size_t idx); static const void* printReturnCommand(TextOutput& out, const void* _cmd); static const void* printCommand(TextOutput& out, const void* _cmd); // Static const and functions will be optimized out if not used, // when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out. static const char *kReturnStrings[] = { "BR_ERROR", "BR_OK", "BR_TRANSACTION", "BR_REPLY", "BR_ACQUIRE_RESULT", "BR_DEAD_REPLY", "BR_TRANSACTION_COMPLETE", "BR_INCREFS", "BR_ACQUIRE", "BR_RELEASE", "BR_DECREFS", "BR_ATTEMPT_ACQUIRE", "BR_NOOP", "BR_SPAWN_LOOPER", "BR_FINISHED", "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", "BR_FAILED_REPLY" }; static const char *kCommandStrings[] = { "BC_TRANSACTION", "BC_REPLY", "BC_ACQUIRE_RESULT", "BC_FREE_BUFFER", "BC_INCREFS", "BC_ACQUIRE", "BC_RELEASE", "BC_DECREFS", "BC_INCREFS_DONE", "BC_ACQUIRE_DONE", "BC_ATTEMPT_ACQUIRE", "BC_REGISTER_LOOPER", "BC_ENTER_LOOPER", "BC_EXIT_LOOPER", "BC_REQUEST_DEATH_NOTIFICATION", "BC_CLEAR_DEATH_NOTIFICATION", "BC_DEAD_BINDER_DONE" }; static const char* getReturnString(size_t idx) { if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0])) return kReturnStrings[idx]; else return "unknown"; } static const void* printBinderTransactionData(TextOutput& out, const void* data) { const binder_transaction_data* btd = (const binder_transaction_data*)data; if (btd->target.handle < 1024) { /* want to print descriptors in decimal; guess based on value */ out << "target.desc=" << btd->target.handle; } else { out << "target.ptr=" << btd->target.ptr; } out << " (cookie " << btd->cookie << ")" << endl << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(long)btd->flags << endl << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)" << endl << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)"; return btd+1; } static const void* printReturnCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; if (code == BR_ERROR) { out << "BR_ERROR: " << (void*)(long)(*cmd++) << endl; return cmd; } else if (cmdIndex >= N) { out << "Unknown reply: " << code << endl; return cmd; } out << kReturnStrings[cmdIndex]; switch (code) { case BR_TRANSACTION: case BR_REPLY: { out << ": " << indent; cmd = (const int32_t *)printBinderTransactionData(out, cmd); out << dedent; } break; case BR_ACQUIRE_RESULT: { const int32_t res = *cmd++; out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)"); } break; case BR_INCREFS: case BR_ACQUIRE: case BR_RELEASE: case BR_DECREFS: { const int32_t b = *cmd++; const int32_t c = *cmd++; out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BR_ATTEMPT_ACQUIRE: { const int32_t p = *cmd++; const int32_t b = *cmd++; const int32_t c = *cmd++; out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << "), pri=" << p; } break; case BR_DEAD_BINDER: case BR_CLEAR_DEATH_NOTIFICATION_DONE: { const int32_t c = *cmd++; out << ": death cookie " << (void*)(long)c; } break; default: // no details to show for: BR_OK, BR_DEAD_REPLY, // BR_TRANSACTION_COMPLETE, BR_FINISHED break; } out << endl; return cmd; } static const void* printCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; if (cmdIndex >= N) { out << "Unknown command: " << code << endl; return cmd; } out << kCommandStrings[cmdIndex]; switch (code) { case BC_TRANSACTION: case BC_REPLY: { out << ": " << indent; cmd = (const int32_t *)printBinderTransactionData(out, cmd); out << dedent; } break; case BC_ACQUIRE_RESULT: { const int32_t res = *cmd++; out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)"); } break; case BC_FREE_BUFFER: { const int32_t buf = *cmd++; out << ": buffer=" << (void*)(long)buf; } break; case BC_INCREFS: case BC_ACQUIRE: case BC_RELEASE: case BC_DECREFS: { const int32_t d = *cmd++; out << ": desc=" << d; } break; case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { const int32_t b = *cmd++; const int32_t c = *cmd++; out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BC_ATTEMPT_ACQUIRE: { const int32_t p = *cmd++; const int32_t d = *cmd++; out << ": desc=" << d << ", pri=" << p; } break; case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { const int32_t h = *cmd++; const int32_t c = *cmd++; out << ": handle=" << h << " (death cookie " << (void*)(long)c << ")"; } break; case BC_DEAD_BINDER_DONE: { const int32_t c = *cmd++; out << ": death cookie " << (void*)(long)c; } break; default: // no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER, // BC_EXIT_LOOPER break; } out << endl; return cmd; } static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; static bool gHaveTLS = false; static pthread_key_t gTLS = 0; static bool gShutdown = false; static bool gDisableBackgroundScheduling = false; IPCThreadState* IPCThreadState::self() { if (gHaveTLS) { restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; } if (gShutdown) { ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n"); return NULL; } pthread_mutex_lock(&gTLSMutex); if (!gHaveTLS) { int key_create_value = pthread_key_create(&gTLS, threadDestructor); if (key_create_value != 0) { pthread_mutex_unlock(&gTLSMutex); ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n", strerror(key_create_value)); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart; } IPCThreadState* IPCThreadState::selfOrNull() { if (gHaveTLS) { const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); return st; } return NULL; } void IPCThreadState::shutdown() { gShutdown = true; if (gHaveTLS) { // XXX Need to wait for all thread pool threads to exit! IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS); if (st) { delete st; pthread_setspecific(gTLS, NULL); } gHaveTLS = false; } } void IPCThreadState::disableBackgroundScheduling(bool disable) { gDisableBackgroundScheduling = disable; } sp IPCThreadState::process() { return mProcess; } status_t IPCThreadState::clearLastError() { const status_t err = mLastError; mLastError = NO_ERROR; return err; } pid_t IPCThreadState::getCallingPid() const { return mCallingPid; } uid_t IPCThreadState::getCallingUid() const { return mCallingUid; } int64_t IPCThreadState::clearCallingIdentity() { int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid; clearCaller(); return token; } void IPCThreadState::setStrictModePolicy(int32_t policy) { mStrictModePolicy = policy; } int32_t IPCThreadState::getStrictModePolicy() const { return mStrictModePolicy; } void IPCThreadState::setLastTransactionBinderFlags(int32_t flags) { mLastTransactionBinderFlags = flags; } int32_t IPCThreadState::getLastTransactionBinderFlags() const { return mLastTransactionBinderFlags; } void IPCThreadState::restoreCallingIdentity(int64_t token) { mCallingUid = (int)(token>>32); mCallingPid = (int)token; } void IPCThreadState::clearCaller() { mCallingPid = getpid(); mCallingUid = getuid(); } void IPCThreadState::flushCommands() { if (mProcess->mDriverFD <= 0) return; talkWithDriver(false); } void IPCThreadState::blockUntilThreadAvailable() { pthread_mutex_lock(&mProcess->mThreadCountLock); while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n", static_cast(mProcess->mExecutingThreadsCount), static_cast(mProcess->mMaxThreads)); pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); } pthread_mutex_unlock(&mProcess->mThreadCountLock); } status_t IPCThreadState::getAndExecuteCommand() { status_t result; int32_t cmd; result = talkWithDriver(); if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing top-level Command: " << getReturnString(cmd) << endl; } pthread_mutex_lock(&mProcess->mThreadCountLock); mProcess->mExecutingThreadsCount++; if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads && mProcess->mStarvationStartTimeMs == 0) { mProcess->mStarvationStartTimeMs = uptimeMillis(); } pthread_mutex_unlock(&mProcess->mThreadCountLock); result = executeCommand(cmd); pthread_mutex_lock(&mProcess->mThreadCountLock); mProcess->mExecutingThreadsCount--; if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads && mProcess->mStarvationStartTimeMs != 0) { int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs; if (starvationTimeMs > 100) { ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms", mProcess->mMaxThreads, starvationTimeMs); } mProcess->mStarvationStartTimeMs = 0; } pthread_cond_broadcast(&mProcess->mThreadCountDecrement); pthread_mutex_unlock(&mProcess->mThreadCountLock); // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we // need to take care of that here in userspace. Note that we do make // sure to go in the foreground after executing a transaction, but // there are other callbacks into user code that could have changed // our group so we want to make absolutely sure it is put back. set_sched_policy(mMyThreadId, SP_FOREGROUND); } return result; } // When we've cleared the incoming command queue, process any pending derefs void IPCThreadState::processPendingDerefs() { if (mIn.dataPosition() >= mIn.dataSize()) { size_t numPending = mPendingWeakDerefs.size(); if (numPending > 0) { for (size_t i = 0; i < numPending; i++) { RefBase::weakref_type* refs = mPendingWeakDerefs[i]; refs->decWeak(mProcess.get()); } mPendingWeakDerefs.clear(); } numPending = mPendingStrongDerefs.size(); if (numPending > 0) { for (size_t i = 0; i < numPending; i++) { BBinder* obj = mPendingStrongDerefs[i]; obj->decStrong(mProcess.get()); } mPendingStrongDerefs.clear(); } } } void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); // This thread may have been spawned by a thread that was in the background // scheduling group, so first we will make sure it is in the foreground // one to avoid performing an initial transaction in the background. set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result; do { processPendingDerefs(); // now get the next command to be processed, waiting if necessary result = getAndExecuteCommand(); if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) { ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting", mProcess->mDriverFD, result); abort(); } // Let this thread exit the thread pool if it is no longer // needed and it is not the main process thread. if(result == TIMED_OUT && !isMain) { break; } } while (result != -ECONNREFUSED && result != -EBADF); LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n", (void*)pthread_self(), getpid(), (void*)result); mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false); } int IPCThreadState::setupPolling(int* fd) { if (mProcess->mDriverFD <= 0) { return -EBADF; } mOut.writeInt32(BC_ENTER_LOOPER); *fd = mProcess->mDriverFD; return 0; } status_t IPCThreadState::handlePolledCommands() { status_t result; do { result = getAndExecuteCommand(); } while (mIn.dataPosition() < mIn.dataSize()); processPendingDerefs(); flushCommands(); return result; } void IPCThreadState::stopProcess(bool /*immediate*/) { //ALOGI("**** STOPPING PROCESS"); flushCommands(); int fd = mProcess->mDriverFD; mProcess->mDriverFD = -1; close(fd); //kill(getpid(), SIGKILL); } status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand " << handle << " / code " << TypeCode(code) << ": " << indent << data << dedent << endl; } if (err == NO_ERROR) { LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(), (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY"); err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); } if (err != NO_ERROR) { if (reply) reply->setError(err); return (mLastError = err); } if ((flags & TF_ONE_WAY) == 0) { #if 0 if (code == 4) { // relayout ALOGI(">>>>>> CALLING transaction 4"); } else { ALOGI(">>>>>> CALLING transaction %d", code); } #endif if (reply) { err = waitForResponse(reply); } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } #if 0 if (code == 4) { // relayout ALOGI("<<<<<< RETURNING transaction 4"); } else { ALOGI("<<<<<< RETURNING transaction %d", code); } #endif IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand " << handle << ": "; if (reply) alog << indent << *reply << dedent << endl; else alog << "(none requested)" << endl; } } else { err = waitForResponse(NULL, NULL); } return err; } void IPCThreadState::incStrongHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle); mOut.writeInt32(BC_ACQUIRE); mOut.writeInt32(handle); } void IPCThreadState::decStrongHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle); mOut.writeInt32(BC_RELEASE); mOut.writeInt32(handle); } void IPCThreadState::incWeakHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); mOut.writeInt32(BC_INCREFS); mOut.writeInt32(handle); } void IPCThreadState::decWeakHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle); mOut.writeInt32(BC_DECREFS); mOut.writeInt32(handle); } status_t IPCThreadState::attemptIncStrongHandle(int32_t handle) { #if HAS_BC_ATTEMPT_ACQUIRE LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle); mOut.writeInt32(BC_ATTEMPT_ACQUIRE); mOut.writeInt32(0); // xxx was thread priority mOut.writeInt32(handle); status_t result = UNKNOWN_ERROR; waitForResponse(NULL, &result); #if LOG_REFCOUNTS printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n", handle, result == NO_ERROR ? "SUCCESS" : "FAILURE"); #endif return result; #else (void)handle; ALOGE("%s(%d): Not supported\n", __func__, handle); return INVALID_OPERATION; #endif } void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder) { #if LOG_REFCOUNTS printf("IPCThreadState::expungeHandle(%ld)\n", handle); #endif self()->mProcess->expungeHandle(handle, binder); } status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy) { mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION); mOut.writeInt32((int32_t)handle); mOut.writePointer((uintptr_t)proxy); return NO_ERROR; } status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) { mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION); mOut.writeInt32((int32_t)handle); mOut.writePointer((uintptr_t)proxy); return NO_ERROR; } IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), mMyThreadId(gettid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0) { pthread_setspecific(gTLS, this); clearCaller(); mIn.setDataCapacity(256); mOut.setDataCapacity(256); } IPCThreadState::~IPCThreadState() { } status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) { status_t err; status_t statusBuffer; err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer); if (err < NO_ERROR) return err; return waitForResponse(NULL, NULL); } status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { uint32_t cmd; int32_t err; while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; err = mIn.errorCheck(); if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; cmd = (uint32_t)mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing waitForResponse Command: " << getReturnString(cmd) << endl; } switch (cmd) { case BR_TRANSACTION_COMPLETE: if (!reply && !acquireResult) goto finish; break; case BR_DEAD_REPLY: err = DEAD_OBJECT; goto finish; case BR_FAILED_REPLY: err = FAILED_TRANSACTION; goto finish; case BR_ACQUIRE_RESULT: { ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT"); const int32_t result = mIn.readInt32(); if (!acquireResult) continue; *acquireResult = result ? NO_ERROR : INVALID_OPERATION; } goto finish; case BR_REPLY: { binder_transaction_data tr; err = mIn.read(&tr, sizeof(tr)); ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY"); if (err != NO_ERROR) goto finish; if (reply) { if ((tr.flags & TF_STATUS_CODE) == 0) { reply->ipcSetDataReference( reinterpret_cast(tr.data.ptr.buffer), tr.data_size, reinterpret_cast(tr.data.ptr.offsets), tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); } else { err = *reinterpret_cast(tr.data.ptr.buffer); freeBuffer(NULL, reinterpret_cast(tr.data.ptr.buffer), tr.data_size, reinterpret_cast(tr.data.ptr.offsets), tr.offsets_size/sizeof(binder_size_t), this); } } else { freeBuffer(NULL, reinterpret_cast(tr.data.ptr.buffer), tr.data_size, reinterpret_cast(tr.data.ptr.offsets), tr.offsets_size/sizeof(binder_size_t), this); continue; } } goto finish; default: err = executeCommand(cmd); if (err != NO_ERROR) goto finish; break; } } finish: if (err != NO_ERROR) { if (acquireResult) *acquireResult = err; if (reply) reply->setError(err); mLastError = err; } return err; } status_t IPCThreadState::talkWithDriver(bool doReceive) { if (mProcess->mDriverFD <= 0) { return -EBADF; } binder_write_read bwr; // Is the read buffer empty? const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // We don't want to write anything if we are still reading // from data left in the input buffer and the caller // has requested to read the next data. const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; bwr.write_size = outAvail; bwr.write_buffer = (uintptr_t)mOut.data(); // This is what we'll read. if (doReceive && needRead) { bwr.read_size = mIn.dataCapacity(); bwr.read_buffer = (uintptr_t)mIn.data(); } else { bwr.read_size = 0; bwr.read_buffer = 0; } IF_LOG_COMMANDS() { TextOutput::Bundle _b(alog); if (outAvail != 0) { alog << "Sending commands to driver: " << indent; const void* cmds = (const void*)bwr.write_buffer; const void* end = ((const uint8_t*)cmds)+bwr.write_size; alog << HexDump(cmds, bwr.write_size) << endl; while (cmds < end) cmds = printCommand(alog, cmds); alog << dedent; } alog << "Size of receive buffer: " << bwr.read_size << ", needRead: " << needRead << ", doReceive: " << doReceive << endl; } // Return immediately if there is nothing to do. if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; do { IF_LOG_COMMANDS() { alog << "About to read/write, write size = " << mOut.dataSize() << endl; } #if defined(__ANDROID__) if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; else err = -errno; #else err = INVALID_OPERATION; #endif if (mProcess->mDriverFD <= 0) { err = -EBADF; } IF_LOG_COMMANDS() { alog << "Finished read/write, write size = " << mOut.dataSize() << endl; } } while (err == -EINTR); IF_LOG_COMMANDS() { alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: " << bwr.write_consumed << " (of " << mOut.dataSize() << "), read consumed: " << bwr.read_consumed << endl; } if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0); } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); } IF_LOG_COMMANDS() { TextOutput::Bundle _b(alog); alog << "Remaining data size: " << mOut.dataSize() << endl; alog << "Received commands from driver: " << indent; const void* cmds = mIn.data(); const void* end = mIn.data() + mIn.dataSize(); alog << HexDump(cmds, mIn.dataSize()) << endl; while (cmds < end) cmds = printReturnCommand(alog, cmds); alog << dedent; } return NO_ERROR; } return err; } status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer) { binder_transaction_data tr; tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */ tr.target.handle = handle; tr.code = code; tr.flags = binderFlags; tr.cookie = 0; tr.sender_pid = 0; tr.sender_euid = 0; const status_t err = data.errorCheck(); if (err == NO_ERROR) { tr.data_size = data.ipcDataSize(); tr.data.ptr.buffer = data.ipcData(); tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); tr.data.ptr.offsets = data.ipcObjects(); } else if (statusBuffer) { tr.flags |= TF_STATUS_CODE; *statusBuffer = err; tr.data_size = sizeof(status_t); tr.data.ptr.buffer = reinterpret_cast(statusBuffer); tr.offsets_size = 0; tr.data.ptr.offsets = 0; } else { return (mLastError = err); } mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr)); return NO_ERROR; } sp the_context_object; void setTheContextObject(sp obj) { the_context_object = obj; } status_t IPCThreadState::executeCommand(int32_t cmd) { BBinder* obj; RefBase::weakref_type* refs; status_t result = NO_ERROR; switch ((uint32_t)cmd) { case BR_ERROR: result = mIn.readInt32(); break; case BR_OK: break; case BR_ACQUIRE: refs = (RefBase::weakref_type*)mIn.readPointer(); obj = (BBinder*)mIn.readPointer(); ALOG_ASSERT(refs->refBase() == obj, "BR_ACQUIRE: object %p does not match cookie %p (expected %p)", refs, obj, refs->refBase()); obj->incStrong(mProcess.get()); IF_LOG_REMOTEREFS() { LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj); obj->printRefs(); } mOut.writeInt32(BC_ACQUIRE_DONE); mOut.writePointer((uintptr_t)refs); mOut.writePointer((uintptr_t)obj); break; case BR_RELEASE: refs = (RefBase::weakref_type*)mIn.readPointer(); obj = (BBinder*)mIn.readPointer(); ALOG_ASSERT(refs->refBase() == obj, "BR_RELEASE: object %p does not match cookie %p (expected %p)", refs, obj, refs->refBase()); IF_LOG_REMOTEREFS() { LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj); obj->printRefs(); } mPendingStrongDerefs.push(obj); break; case BR_INCREFS: refs = (RefBase::weakref_type*)mIn.readPointer(); obj = (BBinder*)mIn.readPointer(); refs->incWeak(mProcess.get()); mOut.writeInt32(BC_INCREFS_DONE); mOut.writePointer((uintptr_t)refs); mOut.writePointer((uintptr_t)obj); break; case BR_DECREFS: refs = (RefBase::weakref_type*)mIn.readPointer(); obj = (BBinder*)mIn.readPointer(); // NOTE: This assertion is not valid, because the object may no // longer exist (thus the (BBinder*)cast above resulting in a different // memory address). //ALOG_ASSERT(refs->refBase() == obj, // "BR_DECREFS: object %p does not match cookie %p (expected %p)", // refs, obj, refs->refBase()); mPendingWeakDerefs.push(refs); break; case BR_ATTEMPT_ACQUIRE: refs = (RefBase::weakref_type*)mIn.readPointer(); obj = (BBinder*)mIn.readPointer(); { const bool success = refs->attemptIncStrong(mProcess.get()); ALOG_ASSERT(success && refs->refBase() == obj, "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)", refs, obj, refs->refBase()); mOut.writeInt32(BC_ACQUIRE_RESULT); mOut.writeInt32((int32_t)success); } break; case BR_TRANSACTION: { binder_transaction_data tr; result = mIn.read(&tr, sizeof(tr)); ALOG_ASSERT(result == NO_ERROR, "Not enough command data for brTRANSACTION"); if (result != NO_ERROR) break; Parcel buffer; buffer.ipcSetDataReference( reinterpret_cast(tr.data.ptr.buffer), tr.data_size, reinterpret_cast(tr.data.ptr.offsets), tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); const pid_t origPid = mCallingPid; const uid_t origUid = mCallingUid; const int32_t origStrictModePolicy = mStrictModePolicy; const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags; mCallingPid = tr.sender_pid; mCallingUid = tr.sender_euid; mLastTransactionBinderFlags = tr.flags; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId); if (gDisableBackgroundScheduling) { if (curPrio > ANDROID_PRIORITY_NORMAL) { // We have inherited a reduced priority from the caller, but do not // want to run in that state in this process. The driver set our // priority already (though not our scheduling class), so bounce // it back to the default before invoking the transaction. setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL); } } else { if (curPrio >= ANDROID_PRIORITY_BACKGROUND) { // We want to use the inherited priority from the caller. // Ensure this thread is in the background scheduling class, // since the driver won't modify scheduling classes for us. // The scheduling group is reset to default by the caller // once this method returns after the transaction is complete. set_sched_policy(mMyThreadId, SP_BACKGROUND); } } //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply; status_t error; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BR_TRANSACTION thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << " / code " << TypeCode(tr.code) << ": " << indent << buffer << dedent << endl << "Data addr = " << reinterpret_cast(tr.data.ptr.buffer) << ", offsets addr=" << reinterpret_cast(tr.data.ptr.offsets) << endl; } if (tr.target.ptr) { // We only have a weak reference on the target object, so we must first try to // safely acquire a strong reference before doing anything else with it. if (reinterpret_cast( tr.target.ptr)->attemptIncStrong(this)) { error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags); reinterpret_cast(tr.cookie)->decStrong(this); } else { error = UNKNOWN_TRANSACTION; } } else { error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); } //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n", // mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == 0) { LOG_ONEWAY("Sending reply to %d!", mCallingPid); if (error < NO_ERROR) reply.setError(error); sendReply(reply, 0); } else { LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); } mCallingPid = origPid; mCallingUid = origUid; mStrictModePolicy = origStrictModePolicy; mLastTransactionBinderFlags = origTransactionBinderFlags; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << ": " << indent << reply << dedent << endl; } } break; case BR_DEAD_BINDER: { BpBinder *proxy = (BpBinder*)mIn.readPointer(); proxy->sendObituary(); mOut.writeInt32(BC_DEAD_BINDER_DONE); mOut.writePointer((uintptr_t)proxy); } break; case BR_CLEAR_DEATH_NOTIFICATION_DONE: { BpBinder *proxy = (BpBinder*)mIn.readPointer(); proxy->getWeakRefs()->decWeak(proxy); } break; case BR_FINISHED: result = TIMED_OUT; break; case BR_NOOP: break; case BR_SPAWN_LOOPER: mProcess->spawnPooledThread(false); break; default: printf("*** BAD COMMAND %d received from Binder driver\n", cmd); result = UNKNOWN_ERROR; break; } if (result != NO_ERROR) { mLastError = result; } return result; } void IPCThreadState::threadDestructor(void *st) { IPCThreadState* const self = static_cast(st); if (self) { self->flushCommands(); #if defined(__ANDROID__) if (self->mProcess->mDriverFD > 0) { ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0); } #endif delete self; } } void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t /*dataSize*/, const binder_size_t* /*objects*/, size_t /*objectsSize*/, void* /*cookie*/) { //ALOGI("Freeing parcel %p", &parcel); IF_LOG_COMMANDS() { alog << "Writing BC_FREE_BUFFER for " << data << endl; } ALOG_ASSERT(data != NULL, "Called with NULL data"); if (parcel != NULL) parcel->closeFileDescriptors(); IPCThreadState* state = self(); state->mOut.writeInt32(BC_FREE_BUFFER); state->mOut.writePointer((uintptr_t)data); } }; // namespace android libs/binder/IPermissionController.cpp0100644 0000000 0000000 00000010474 13077405420 017022 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "PermissionController" #include #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpPermissionController : public BpInterface { public: BpPermissionController(const sp& impl) : BpInterface(impl) { } virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) { Parcel data, reply; data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); data.writeString16(permission); data.writeInt32(pid); data.writeInt32(uid); remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return 0; return reply.readInt32() != 0; } virtual void getPackagesForUid(const uid_t uid, Vector& packages) { Parcel data, reply; data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); data.writeInt32(uid); remote()->transact(GET_PACKAGES_FOR_UID_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) { return; } const int32_t size = reply.readInt32(); if (size <= 0) { return; } for (int i = 0; i < size; i++) { packages.push(reply.readString16()); } } virtual bool isRuntimePermission(const String16& permission) { Parcel data, reply; data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); data.writeString16(permission); remote()->transact(IS_RUNTIME_PERMISSION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return false; return reply.readInt32() != 0; } }; IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); // ---------------------------------------------------------------------- status_t BnPermissionController::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case CHECK_PERMISSION_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); String16 permission = data.readString16(); int32_t pid = data.readInt32(); int32_t uid = data.readInt32(); bool res = checkPermission(permission, pid, uid); reply->writeNoException(); reply->writeInt32(res ? 1 : 0); return NO_ERROR; } break; case GET_PACKAGES_FOR_UID_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); int32_t uid = data.readInt32(); Vector packages; getPackagesForUid(uid, packages); reply->writeNoException(); size_t size = packages.size(); reply->writeInt32(size); for (size_t i = 0; i < size; i++) { reply->writeString16(packages[i]); } return NO_ERROR; } break; case IS_RUNTIME_PERMISSION_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); String16 permission = data.readString16(); const bool res = isRuntimePermission(permission); reply->writeNoException(); reply->writeInt32(res ? 1 : 0); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/binder/IProcessInfoService.cpp0100644 0000000 0000000 00000006515 13077405420 016402 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpProcessInfoService : public BpInterface { public: BpProcessInfoService(const sp& impl) : BpInterface(impl) {} virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states) { Parcel data, reply; data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor()); data.writeInt32Array(length, pids); data.writeInt32(length); // write length of output array, used by java AIDL stubs status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply); if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { return err; } int32_t replyLen = reply.readInt32(); if (static_cast(replyLen) != length) { return NOT_ENOUGH_DATA; } if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) { return err; } return reply.readInt32(); } virtual status_t getProcessStatesAndOomScoresFromPids(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states, /*out*/ int32_t* scores) { Parcel data, reply; data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor()); data.writeInt32Array(length, pids); // write length of output arrays, used by java AIDL stubs data.writeInt32(length); data.writeInt32(length); status_t err = remote()->transact( GET_PROCESS_STATES_AND_OOM_SCORES_FROM_PIDS, data, &reply); if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { return err; } int32_t replyLen = reply.readInt32(); if (static_cast(replyLen) != length) { return NOT_ENOUGH_DATA; } if (replyLen > 0 && (err = reply.read( states, length * sizeof(*states))) != NO_ERROR) { return err; } replyLen = reply.readInt32(); if (static_cast(replyLen) != length) { return NOT_ENOUGH_DATA; } if (replyLen > 0 && (err = reply.read( scores, length * sizeof(*scores))) != NO_ERROR) { return err; } return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService"); // ---------------------------------------------------------------------- }; // namespace android libs/binder/IResultReceiver.cpp0100644 0000000 0000000 00000003774 13077405420 015576 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "ResultReceiver" #include #include #include #include #include namespace android { // ---------------------------------------------------------------------- class BpResultReceiver : public BpInterface { public: BpResultReceiver(const sp& impl) : BpInterface(impl) { } virtual void send(int32_t resultCode) { Parcel data; data.writeInterfaceToken(IResultReceiver::getInterfaceDescriptor()); data.writeInt32(resultCode); remote()->transact(OP_SEND, data, NULL, IBinder::FLAG_ONEWAY); } }; IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver"); // ---------------------------------------------------------------------- status_t BnResultReceiver::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case OP_SEND: { CHECK_INTERFACE(IResultReceiver, data, reply); int32_t resultCode = data.readInt32(); send(resultCode); if (reply != NULL) { reply->writeNoException(); } return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/binder/IServiceManager.cpp0100644 0000000 0000000 00000013740 13077405420 015520 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "ServiceManager" #include #include #include #include #include #include #include #include namespace android { sp defaultServiceManager() { if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); while (gDefaultServiceManager == NULL) { gDefaultServiceManager = interface_cast( ProcessState::self()->getContextObject(NULL)); if (gDefaultServiceManager == NULL) sleep(1); } } return gDefaultServiceManager; } bool checkCallingPermission(const String16& permission) { return checkCallingPermission(permission, NULL, NULL); } static String16 _permission("permission"); bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid) { IPCThreadState* ipcState = IPCThreadState::self(); pid_t pid = ipcState->getCallingPid(); uid_t uid = ipcState->getCallingUid(); if (outPid) *outPid = pid; if (outUid) *outUid = uid; return checkPermission(permission, pid, uid); } bool checkPermission(const String16& permission, pid_t pid, uid_t uid) { #ifdef __BRILLO__ // Brillo doesn't currently run ActivityManager or support framework permissions. return true; #endif sp pc; gDefaultServiceManagerLock.lock(); pc = gPermissionController; gDefaultServiceManagerLock.unlock(); int64_t startTime = 0; while (true) { if (pc != NULL) { bool res = pc->checkPermission(permission, pid, uid); if (res) { if (startTime != 0) { ALOGI("Check passed after %d seconds for %s from uid=%d pid=%d", (int)((uptimeMillis()-startTime)/1000), String8(permission).string(), uid, pid); } return res; } // Is this a permission failure, or did the controller go away? if (IInterface::asBinder(pc)->isBinderAlive()) { ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(), uid, pid); return false; } // Object is dead! gDefaultServiceManagerLock.lock(); if (gPermissionController == pc) { gPermissionController = NULL; } gDefaultServiceManagerLock.unlock(); } // Need to retrieve the permission controller. sp binder = defaultServiceManager()->checkService(_permission); if (binder == NULL) { // Wait for the permission controller to come back... if (startTime == 0) { startTime = uptimeMillis(); ALOGI("Waiting to check permission %s from uid=%d pid=%d", String8(permission).string(), uid, pid); } sleep(1); } else { pc = interface_cast(binder); // Install the new permission controller, and try again. gDefaultServiceManagerLock.lock(); gPermissionController = pc; gDefaultServiceManagerLock.unlock(); } } } // ---------------------------------------------------------------------- class BpServiceManager : public BpInterface { public: BpServiceManager(const sp& impl) : BpInterface(impl) { } virtual sp getService(const String16& name) const { unsigned n; for (n = 0; n < 5; n++){ sp svc = checkService(name); if (svc != NULL) return svc; ALOGI("Waiting for service %s...\n", String8(name).string()); sleep(1); } return NULL; } virtual sp checkService( const String16& name) const { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); return reply.readStrongBinder(); } virtual status_t addService(const String16& name, const sp& service, bool allowIsolated) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; } virtual Vector listServices() { Vector res; int n = 0; for (;;) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeInt32(n++); status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); if (err != NO_ERROR) break; res.add(reply.readString16()); } return res; } }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); }; // namespace android libs/binder/MemoryBase.cpp0100644 0000000 0000000 00000002325 13077405420 014554 0ustar000000000 0000000 /* * Copyright (C) 2008 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 #include #include namespace android { // --------------------------------------------------------------------------- MemoryBase::MemoryBase(const sp& heap, ssize_t offset, size_t size) : mSize(size), mOffset(offset), mHeap(heap) { } sp MemoryBase::getMemory(ssize_t* offset, size_t* size) const { if (offset) *offset = mOffset; if (size) *size = mSize; return mHeap; } MemoryBase::~MemoryBase() { } // --------------------------------------------------------------------------- }; // namespace android libs/binder/MemoryDealer.cpp0100644 0000000 0000000 00000032245 13077405420 015102 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "MemoryDealer" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- /* * A simple templatized doubly linked-list implementation */ template class LinkedList { NODE* mFirst; NODE* mLast; public: LinkedList() : mFirst(0), mLast(0) { } bool isEmpty() const { return mFirst == 0; } NODE const* head() const { return mFirst; } NODE* head() { return mFirst; } NODE const* tail() const { return mLast; } NODE* tail() { return mLast; } void insertAfter(NODE* node, NODE* newNode) { newNode->prev = node; newNode->next = node->next; if (node->next == 0) mLast = newNode; else node->next->prev = newNode; node->next = newNode; } void insertBefore(NODE* node, NODE* newNode) { newNode->prev = node->prev; newNode->next = node; if (node->prev == 0) mFirst = newNode; else node->prev->next = newNode; node->prev = newNode; } void insertHead(NODE* newNode) { if (mFirst == 0) { mFirst = mLast = newNode; newNode->prev = newNode->next = 0; } else { newNode->prev = 0; newNode->next = mFirst; mFirst->prev = newNode; mFirst = newNode; } } void insertTail(NODE* newNode) { if (mLast == 0) { insertHead(newNode); } else { newNode->prev = mLast; newNode->next = 0; mLast->next = newNode; mLast = newNode; } } NODE* remove(NODE* node) { if (node->prev == 0) mFirst = node->next; else node->prev->next = node->next; if (node->next == 0) mLast = node->prev; else node->next->prev = node->prev; return node; } }; // ---------------------------------------------------------------------------- class Allocation : public MemoryBase { public: Allocation(const sp& dealer, const sp& heap, ssize_t offset, size_t size); virtual ~Allocation(); private: sp mDealer; }; // ---------------------------------------------------------------------------- class SimpleBestFitAllocator { enum { PAGE_ALIGNED = 0x00000001 }; public: SimpleBestFitAllocator(size_t size); ~SimpleBestFitAllocator(); size_t allocate(size_t size, uint32_t flags = 0); status_t deallocate(size_t offset); size_t size() const; void dump(const char* what) const; void dump(String8& res, const char* what) const; static size_t getAllocationAlignment() { return kMemoryAlign; } private: struct chunk_t { chunk_t(size_t start, size_t size) : start(start), size(size), free(1), prev(0), next(0) { } size_t start; size_t size : 28; int free : 4; mutable chunk_t* prev; mutable chunk_t* next; }; ssize_t alloc(size_t size, uint32_t flags); chunk_t* dealloc(size_t start); void dump_l(const char* what) const; void dump_l(String8& res, const char* what) const; static const int kMemoryAlign; mutable Mutex mLock; LinkedList mList; size_t mHeapSize; }; // ---------------------------------------------------------------------------- Allocation::Allocation( const sp& dealer, const sp& heap, ssize_t offset, size_t size) : MemoryBase(heap, offset, size), mDealer(dealer) { #ifndef NDEBUG void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); memset(start_ptr, 0xda, size); #endif } Allocation::~Allocation() { size_t freedOffset = getOffset(); size_t freedSize = getSize(); if (freedSize) { /* NOTE: it's VERY important to not free allocations of size 0 because * they're special as they don't have any record in the allocator * and could alias some real allocation (their offset is zero). */ // keep the size to unmap in excess size_t pagesize = getpagesize(); size_t start = freedOffset; size_t end = start + freedSize; start &= ~(pagesize-1); end = (end + pagesize-1) & ~(pagesize-1); // give back to the kernel the pages we don't need size_t free_start = freedOffset; size_t free_end = free_start + freedSize; if (start < free_start) start = free_start; if (end > free_end) end = free_end; start = (start + pagesize-1) & ~(pagesize-1); end &= ~(pagesize-1); if (start < end) { void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start); size_t size = end-start; #ifndef NDEBUG memset(start_ptr, 0xdf, size); #endif // MADV_REMOVE is not defined on Dapper based Goobuntu #ifdef MADV_REMOVE if (size) { int err = madvise(start_ptr, size, MADV_REMOVE); ALOGW_IF(err, "madvise(%p, %zu, MADV_REMOVE) returned %s", start_ptr, size, err<0 ? strerror(errno) : "Ok"); } #endif } // This should be done after madvise(MADV_REMOVE), otherwise madvise() // might kick out the memory region that's allocated and/or written // right after the deallocation. mDealer->deallocate(freedOffset); } } // ---------------------------------------------------------------------------- MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags) : mHeap(new MemoryHeapBase(size, flags, name)), mAllocator(new SimpleBestFitAllocator(size)) { } MemoryDealer::~MemoryDealer() { delete mAllocator; } sp MemoryDealer::allocate(size_t size) { sp memory; const ssize_t offset = allocator()->allocate(size); if (offset >= 0) { memory = new Allocation(this, heap(), offset, size); } return memory; } void MemoryDealer::deallocate(size_t offset) { allocator()->deallocate(offset); } void MemoryDealer::dump(const char* what) const { allocator()->dump(what); } const sp& MemoryDealer::heap() const { return mHeap; } SimpleBestFitAllocator* MemoryDealer::allocator() const { return mAllocator; } // static size_t MemoryDealer::getAllocationAlignment() { return SimpleBestFitAllocator::getAllocationAlignment(); } // ---------------------------------------------------------------------------- // align all the memory blocks on a cache-line boundary const int SimpleBestFitAllocator::kMemoryAlign = 32; SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) { size_t pagesize = getpagesize(); mHeapSize = ((size + pagesize-1) & ~(pagesize-1)); chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign); mList.insertHead(node); } SimpleBestFitAllocator::~SimpleBestFitAllocator() { while(!mList.isEmpty()) { delete mList.remove(mList.head()); } } size_t SimpleBestFitAllocator::size() const { return mHeapSize; } size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) { Mutex::Autolock _l(mLock); ssize_t offset = alloc(size, flags); return offset; } status_t SimpleBestFitAllocator::deallocate(size_t offset) { Mutex::Autolock _l(mLock); chunk_t const * const freed = dealloc(offset); if (freed) { return NO_ERROR; } return NAME_NOT_FOUND; } ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) { if (size == 0) { return 0; } size = (size + kMemoryAlign-1) / kMemoryAlign; chunk_t* free_chunk = 0; chunk_t* cur = mList.head(); size_t pagesize = getpagesize(); while (cur) { int extra = 0; if (flags & PAGE_ALIGNED) extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ; // best fit if (cur->free && (cur->size >= (size+extra))) { if ((!free_chunk) || (cur->size < free_chunk->size)) { free_chunk = cur; } if (cur->size == size) { break; } } cur = cur->next; } if (free_chunk) { const size_t free_size = free_chunk->size; free_chunk->free = 0; free_chunk->size = size; if (free_size > size) { int extra = 0; if (flags & PAGE_ALIGNED) extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ; if (extra) { chunk_t* split = new chunk_t(free_chunk->start, extra); free_chunk->start += extra; mList.insertBefore(free_chunk, split); } ALOGE_IF((flags&PAGE_ALIGNED) && ((free_chunk->start*kMemoryAlign)&(pagesize-1)), "PAGE_ALIGNED requested, but page is not aligned!!!"); const ssize_t tail_free = free_size - (size+extra); if (tail_free > 0) { chunk_t* split = new chunk_t( free_chunk->start + free_chunk->size, tail_free); mList.insertAfter(free_chunk, split); } } return (free_chunk->start)*kMemoryAlign; } return NO_MEMORY; } SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) { start = start / kMemoryAlign; chunk_t* cur = mList.head(); while (cur) { if (cur->start == start) { LOG_FATAL_IF(cur->free, "block at offset 0x%08lX of size 0x%08lX already freed", cur->start*kMemoryAlign, cur->size*kMemoryAlign); // merge freed blocks together chunk_t* freed = cur; cur->free = 1; do { chunk_t* const p = cur->prev; chunk_t* const n = cur->next; if (p && (p->free || !cur->size)) { freed = p; p->size += cur->size; mList.remove(cur); delete cur; } cur = n; } while (cur && cur->free); #ifndef NDEBUG if (!freed->free) { dump_l("dealloc (!freed->free)"); } #endif LOG_FATAL_IF(!freed->free, "freed block at offset 0x%08lX of size 0x%08lX is not free!", freed->start * kMemoryAlign, freed->size * kMemoryAlign); return freed; } cur = cur->next; } return 0; } void SimpleBestFitAllocator::dump(const char* what) const { Mutex::Autolock _l(mLock); dump_l(what); } void SimpleBestFitAllocator::dump_l(const char* what) const { String8 result; dump_l(result, what); ALOGD("%s", result.string()); } void SimpleBestFitAllocator::dump(String8& result, const char* what) const { Mutex::Autolock _l(mLock); dump_l(result, what); } void SimpleBestFitAllocator::dump_l(String8& result, const char* what) const { size_t size = 0; int32_t i = 0; chunk_t const* cur = mList.head(); const size_t SIZE = 256; char buffer[SIZE]; snprintf(buffer, SIZE, " %s (%p, size=%u)\n", what, this, (unsigned int)mHeapSize); result.append(buffer); while (cur) { const char* errs[] = {"", "| link bogus NP", "| link bogus PN", "| link bogus NP+PN" }; int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0; int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0; snprintf(buffer, SIZE, " %3u: %p | 0x%08X | 0x%08X | %s %s\n", i, cur, int(cur->start*kMemoryAlign), int(cur->size*kMemoryAlign), int(cur->free) ? "F" : "A", errs[np|pn]); result.append(buffer); if (!cur->free) size += cur->size*kMemoryAlign; i++; cur = cur->next; } snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024)); result.append(buffer); } }; // namespace android libs/binder/MemoryHeapBase.cpp0100644 0000000 0000000 00000011224 13077405420 015350 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ #define LOG_TAG "MemoryHeapBase" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- MemoryHeapBase::MemoryHeapBase() : mFD(-1), mSize(0), mBase(MAP_FAILED), mDevice(NULL), mNeedUnmap(false), mOffset(0) { } MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size); ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno)); if (fd >= 0) { if (mapfd(fd, size) == NO_ERROR) { if (flags & READ_ONLY) { ashmem_set_prot_region(fd, PROT_READ); } } } } MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(0), mNeedUnmap(false), mOffset(0) { int open_flags = O_RDWR; if (flags & NO_CACHING) open_flags |= O_SYNC; int fd = open(device, open_flags); ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno)); if (fd >= 0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); if (mapfd(fd, size) == NO_ERROR) { mDevice = device; } } } MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); mapfd(dup(fd), size, offset); } status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device) { if (mFD != -1) { return INVALID_OPERATION; } mFD = fd; mBase = base; mSize = size; mFlags = flags; mDevice = device; return NO_ERROR; } status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset) { if (size == 0) { // try to figure out the size automatically struct stat sb; if (fstat(fd, &sb) == 0) size = sb.st_size; // if it didn't work, let mmap() fail. } if ((mFlags & DONT_MAP_LOCALLY) == 0) { void* base = (uint8_t*)mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); if (base == MAP_FAILED) { ALOGE("mmap(fd=%d, size=%u) failed (%s)", fd, uint32_t(size), strerror(errno)); close(fd); return -errno; } //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size); mBase = base; mNeedUnmap = true; } else { mBase = 0; // not MAP_FAILED mNeedUnmap = false; } mFD = fd; mSize = size; mOffset = offset; return NO_ERROR; } MemoryHeapBase::~MemoryHeapBase() { dispose(); } void MemoryHeapBase::dispose() { int fd = android_atomic_or(-1, &mFD); if (fd >= 0) { if (mNeedUnmap) { //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize); munmap(mBase, mSize); } mBase = 0; mSize = 0; close(fd); } } int MemoryHeapBase::getHeapID() const { return mFD; } void* MemoryHeapBase::getBase() const { return mBase; } size_t MemoryHeapBase::getSize() const { return mSize; } uint32_t MemoryHeapBase::getFlags() const { return mFlags; } const char* MemoryHeapBase::getDevice() const { return mDevice; } uint32_t MemoryHeapBase::getOffset() const { return mOffset; } // --------------------------------------------------------------------------- }; // namespace android libs/binder/Parcel.cpp0100644 0000000 0000000 00000214675 13077405420 013734 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "Parcel" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef INT32_MAX #define INT32_MAX ((int32_t)(2147483647)) #endif #define LOG_REFS(...) //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_ALLOC(...) //#define LOG_ALLOC(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) // --------------------------------------------------------------------------- // This macro should never be used at runtime, as a too large value // of s could cause an integer overflow. Instead, you should always // use the wrapper function pad_size() #define PAD_SIZE_UNSAFE(s) (((s)+3)&~3) static size_t pad_size(size_t s) { if (s > (SIZE_T_MAX - 3)) { abort(); } return PAD_SIZE_UNSAFE(s); } // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER #define STRICT_MODE_PENALTY_GATHER (0x40 << 16) // XXX This can be made public if we want to provide // support for typed data. struct small_flat_data { uint32_t type; uint32_t data; }; namespace android { static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocCount = 0; static size_t gMaxFds = 0; // Maximum size of a blob to transfer in-place. static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; enum { BLOB_INPLACE = 0, BLOB_ASHMEM_IMMUTABLE = 1, BLOB_ASHMEM_MUTABLE = 2, }; static dev_t ashmem_rdev() { static dev_t __ashmem_rdev; static pthread_mutex_t __ashmem_rdev_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&__ashmem_rdev_lock); dev_t rdev = __ashmem_rdev; if (!rdev) { int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDONLY)); if (fd >= 0) { struct stat st; int ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); close(fd); if ((ret >= 0) && S_ISCHR(st.st_mode)) { rdev = __ashmem_rdev = st.st_rdev; } } } pthread_mutex_unlock(&__ashmem_rdev_lock); return rdev; } void acquire_object(const sp& proc, const flat_binder_object& obj, const void* who, size_t* outAshmemSize) { switch (obj.type) { case BINDER_TYPE_BINDER: if (obj.binder) { LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie); reinterpret_cast(obj.cookie)->incStrong(who); } return; case BINDER_TYPE_WEAK_BINDER: if (obj.binder) reinterpret_cast(obj.binder)->incWeak(who); return; case BINDER_TYPE_HANDLE: { const sp b = proc->getStrongProxyForHandle(obj.handle); if (b != NULL) { LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get()); b->incStrong(who); } return; } case BINDER_TYPE_WEAK_HANDLE: { const wp b = proc->getWeakProxyForHandle(obj.handle); if (b != NULL) b.get_refs()->incWeak(who); return; } case BINDER_TYPE_FD: { if ((obj.cookie != 0) && (outAshmemSize != NULL)) { struct stat st; int ret = fstat(obj.handle, &st); if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) { // If we own an ashmem fd, keep track of how much memory it refers to. int size = ashmem_get_size_region(obj.handle); if (size > 0) { *outAshmemSize += size; } } } return; } } ALOGD("Invalid object type 0x%08x", obj.type); } void acquire_object(const sp& proc, const flat_binder_object& obj, const void* who) { acquire_object(proc, obj, who, NULL); } static void release_object(const sp& proc, const flat_binder_object& obj, const void* who, size_t* outAshmemSize) { switch (obj.type) { case BINDER_TYPE_BINDER: if (obj.binder) { LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie); reinterpret_cast(obj.cookie)->decStrong(who); } return; case BINDER_TYPE_WEAK_BINDER: if (obj.binder) reinterpret_cast(obj.binder)->decWeak(who); return; case BINDER_TYPE_HANDLE: { const sp b = proc->getStrongProxyForHandle(obj.handle); if (b != NULL) { LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get()); b->decStrong(who); } return; } case BINDER_TYPE_WEAK_HANDLE: { const wp b = proc->getWeakProxyForHandle(obj.handle); if (b != NULL) b.get_refs()->decWeak(who); return; } case BINDER_TYPE_FD: { if (obj.cookie != 0) { // owned if (outAshmemSize != NULL) { struct stat st; int ret = fstat(obj.handle, &st); if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) { int size = ashmem_get_size_region(obj.handle); if (size > 0) { *outAshmemSize -= size; } } } close(obj.handle); } return; } } ALOGE("Invalid object type 0x%08x", obj.type); } void release_object(const sp& proc, const flat_binder_object& obj, const void* who) { release_object(proc, obj, who, NULL); } inline static status_t finish_flatten_binder( const sp& /*binder*/, const flat_binder_object& flat, Parcel* out) { return out->writeObject(flat, false); } status_t flatten_binder(const sp& /*proc*/, const sp& binder, Parcel* out) { flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { IBinder *local = binder->localBinder(); if (!local) { BpBinder *proxy = binder->remoteBinder(); if (proxy == NULL) { ALOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.type = BINDER_TYPE_HANDLE; obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ obj.handle = handle; obj.cookie = 0; } else { obj.type = BINDER_TYPE_BINDER; obj.binder = reinterpret_cast(local->getWeakRefs()); obj.cookie = reinterpret_cast(local); } } else { obj.type = BINDER_TYPE_BINDER; obj.binder = 0; obj.cookie = 0; } return finish_flatten_binder(binder, obj, out); } status_t flatten_binder(const sp& /*proc*/, const wp& binder, Parcel* out) { flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { sp real = binder.promote(); if (real != NULL) { IBinder *local = real->localBinder(); if (!local) { BpBinder *proxy = real->remoteBinder(); if (proxy == NULL) { ALOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.type = BINDER_TYPE_WEAK_HANDLE; obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ obj.handle = handle; obj.cookie = 0; } else { obj.type = BINDER_TYPE_WEAK_BINDER; obj.binder = reinterpret_cast(binder.get_refs()); obj.cookie = reinterpret_cast(binder.unsafe_get()); } return finish_flatten_binder(real, obj, out); } // XXX How to deal? In order to flatten the given binder, // we need to probe it for information, which requires a primary // reference... but we don't have one. // // The OpenBinder implementation uses a dynamic_cast<> here, // but we can't do that with the different reference counting // implementation we are using. ALOGE("Unable to unflatten Binder weak reference!"); obj.type = BINDER_TYPE_BINDER; obj.binder = 0; obj.cookie = 0; return finish_flatten_binder(NULL, obj, out); } else { obj.type = BINDER_TYPE_BINDER; obj.binder = 0; obj.cookie = 0; return finish_flatten_binder(NULL, obj, out); } } inline static status_t finish_unflatten_binder( BpBinder* /*proxy*/, const flat_binder_object& /*flat*/, const Parcel& /*in*/) { return NO_ERROR; } status_t unflatten_binder(const sp& proc, const Parcel& in, sp* out) { const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: *out = reinterpret_cast(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: *out = proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast(out->get()), *flat, in); } } return BAD_TYPE; } status_t unflatten_binder(const sp& proc, const Parcel& in, wp* out) { const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: *out = reinterpret_cast(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_WEAK_BINDER: if (flat->binder != 0) { out->set_object_and_refs( reinterpret_cast(flat->cookie), reinterpret_cast(flat->binder)); } else { *out = NULL; } return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: *out = proc->getWeakProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast(out->unsafe_get()), *flat, in); } } return BAD_TYPE; } // --------------------------------------------------------------------------- Parcel::Parcel() { LOG_ALLOC("Parcel %p: constructing", this); initState(); } Parcel::~Parcel() { freeDataNoInit(); LOG_ALLOC("Parcel %p: destroyed", this); } size_t Parcel::getGlobalAllocSize() { pthread_mutex_lock(&gParcelGlobalAllocSizeLock); size_t size = gParcelGlobalAllocSize; pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); return size; } size_t Parcel::getGlobalAllocCount() { pthread_mutex_lock(&gParcelGlobalAllocSizeLock); size_t count = gParcelGlobalAllocCount; pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); return count; } const uint8_t* Parcel::data() const { return mData; } size_t Parcel::dataSize() const { return (mDataSize > mDataPos ? mDataSize : mDataPos); } size_t Parcel::dataAvail() const { size_t result = dataSize() - dataPosition(); if (result > INT32_MAX) { abort(); } return result; } size_t Parcel::dataPosition() const { return mDataPos; } size_t Parcel::dataCapacity() const { return mDataCapacity; } status_t Parcel::setDataSize(size_t size) { if (size > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } status_t err; err = continueWrite(size); if (err == NO_ERROR) { mDataSize = size; ALOGV("setDataSize Setting data size of %p to %zu", this, mDataSize); } return err; } void Parcel::setDataPosition(size_t pos) const { if (pos > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. abort(); } mDataPos = pos; mNextObjectHint = 0; } status_t Parcel::setDataCapacity(size_t size) { if (size > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } status_t Parcel::setData(const uint8_t* buffer, size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } status_t err = restartWrite(len); if (err == NO_ERROR) { memcpy(const_cast(data()), buffer, len); mDataSize = len; mFdsKnown = false; } return err; } status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) { const sp proc(ProcessState::self()); status_t err; const uint8_t *data = parcel->mData; const binder_size_t *objects = parcel->mObjects; size_t size = parcel->mObjectsSize; int startPos = mDataPos; int firstIndex = -1, lastIndex = -2; if (len == 0) { return NO_ERROR; } if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } // range checks against the source parcel size if ((offset > parcel->mDataSize) || (len > parcel->mDataSize) || (offset + len > parcel->mDataSize)) { return BAD_VALUE; } // Count objects in range for (int i = 0; i < (int) size; i++) { size_t off = objects[i]; if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) { if (firstIndex == -1) { firstIndex = i; } lastIndex = i; } } int numObjects = lastIndex - firstIndex + 1; if ((mDataSize+len) > mDataCapacity) { // grow data err = growData(len); if (err != NO_ERROR) { return err; } } // append data memcpy(mData + mDataPos, data + offset, len); mDataPos += len; mDataSize += len; err = NO_ERROR; if (numObjects > 0) { // grow objects if (mObjectsCapacity < mObjectsSize + numObjects) { size_t newSize = ((mObjectsSize + numObjects)*3)/2; if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow binder_size_t *objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == (binder_size_t*)0) { return NO_MEMORY; } mObjects = objects; mObjectsCapacity = newSize; } // append and acquire objects int idx = mObjectsSize; for (int i = firstIndex; i <= lastIndex; i++) { size_t off = objects[i] - offset + startPos; mObjects[idx++] = off; mObjectsSize++; flat_binder_object* flat = reinterpret_cast(mData + off); acquire_object(proc, *flat, this, &mOpenAshmemSize); if (flat->type == BINDER_TYPE_FD) { // If this is a file descriptor, we need to dup it so the // new Parcel now owns its own fd, and can declare that we // officially know we have fds. flat->handle = dup(flat->handle); flat->cookie = 1; mHasFds = mFdsKnown = true; if (!mAllowFds) { err = FDS_NOT_ALLOWED; } } } } return err; } bool Parcel::allowFds() const { return mAllowFds; } bool Parcel::pushAllowFds(bool allowFds) { const bool origValue = mAllowFds; if (!allowFds) { mAllowFds = false; } return origValue; } void Parcel::restoreAllowFds(bool lastValue) { mAllowFds = lastValue; } bool Parcel::hasFileDescriptors() const { if (!mFdsKnown) { scanForFds(); } return mHasFds; } // Write RPC headers. (previously just the interface token) status_t Parcel::writeInterfaceToken(const String16& interface) { writeInt32(IPCThreadState::self()->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER); // currently the interface identification token is just its name as a string return writeString16(interface); } bool Parcel::checkInterface(IBinder* binder) const { return enforceInterface(binder->getInterfaceDescriptor()); } bool Parcel::enforceInterface(const String16& interface, IPCThreadState* threadState) const { int32_t strictPolicy = readInt32(); if (threadState == NULL) { threadState = IPCThreadState::self(); } if ((threadState->getLastTransactionBinderFlags() & IBinder::FLAG_ONEWAY) != 0) { // For one-way calls, the callee is running entirely // disconnected from the caller, so disable StrictMode entirely. // Not only does disk/network usage not impact the caller, but // there's no way to commuicate back any violations anyway. threadState->setStrictModePolicy(0); } else { threadState->setStrictModePolicy(strictPolicy); } const String16 str(readString16()); if (str == interface) { return true; } else { ALOGW("**** enforceInterface() expected '%s' but read '%s'", String8(interface).string(), String8(str).string()); return false; } } const binder_size_t* Parcel::objects() const { return mObjects; } size_t Parcel::objectsCount() const { return mObjectsSize; } status_t Parcel::errorCheck() const { return mError; } void Parcel::setError(status_t err) { mError = err; } status_t Parcel::finishWrite(size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } //printf("Finish write of %d\n", len); mDataPos += len; ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos); if (mDataPos > mDataSize) { mDataSize = mDataPos; ALOGV("finishWrite Setting data size of %p to %zu", this, mDataSize); } //printf("New pos=%d, size=%d\n", mDataPos, mDataSize); return NO_ERROR; } status_t Parcel::writeUnpadded(const void* data, size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } size_t end = mDataPos + len; if (end < mDataPos) { // integer overflow return BAD_VALUE; } if (end <= mDataCapacity) { restart_write: memcpy(mData+mDataPos, data, len); return finishWrite(len); } status_t err = growData(len); if (err == NO_ERROR) goto restart_write; return err; } status_t Parcel::write(const void* data, size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } void* const d = writeInplace(len); if (d) { memcpy(d, data, len); return NO_ERROR; } return mError; } void* Parcel::writeInplace(size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return NULL; } const size_t padded = pad_size(len); // sanity check for integer overflow if (mDataPos+padded < mDataPos) { return NULL; } if ((mDataPos+padded) <= mDataCapacity) { restart_write: //printf("Writing %ld bytes, padded to %ld\n", len, padded); uint8_t* const data = mData+mDataPos; // Need to pad at end? if (padded != len) { #if BYTE_ORDER == BIG_ENDIAN static const uint32_t mask[4] = { 0x00000000, 0xffffff00, 0xffff0000, 0xff000000 }; #endif #if BYTE_ORDER == LITTLE_ENDIAN static const uint32_t mask[4] = { 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff }; #endif //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len], // *reinterpret_cast(data+padded-4)); *reinterpret_cast(data+padded-4) &= mask[padded-len]; } finishWrite(padded); return data; } status_t err = growData(padded); if (err == NO_ERROR) goto restart_write; return NULL; } status_t Parcel::writeUtf8AsUtf16(const std::string& str) { const uint8_t* strData = (uint8_t*)str.data(); const size_t strLen= str.length(); const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen); if (utf16Len < 0 || utf16Len> std::numeric_limits::max()) { return BAD_VALUE; } status_t err = writeInt32(utf16Len); if (err) { return err; } // Allocate enough bytes to hold our converted string and its terminating NULL. void* dst = writeInplace((utf16Len + 1) * sizeof(char16_t)); if (!dst) { return NO_MEMORY; } utf8_to_utf16(strData, strLen, (char16_t*)dst); return NO_ERROR; } status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr& str) { if (!str) { return writeInt32(-1); } return writeUtf8AsUtf16(*str); } namespace { template status_t writeByteVectorInternal(Parcel* parcel, const std::vector& val) { status_t status; if (val.size() > std::numeric_limits::max()) { status = BAD_VALUE; return status; } status = parcel->writeInt32(val.size()); if (status != OK) { return status; } void* data = parcel->writeInplace(val.size()); if (!data) { status = BAD_VALUE; return status; } memcpy(data, val.data(), val.size()); return status; } template status_t writeByteVectorInternalPtr(Parcel* parcel, const std::unique_ptr>& val) { if (!val) { return parcel->writeInt32(-1); } return writeByteVectorInternal(parcel, *val); } } // namespace status_t Parcel::writeByteVector(const std::vector& val) { return writeByteVectorInternal(this, val); } status_t Parcel::writeByteVector(const std::unique_ptr>& val) { return writeByteVectorInternalPtr(this, val); } status_t Parcel::writeByteVector(const std::vector& val) { return writeByteVectorInternal(this, val); } status_t Parcel::writeByteVector(const std::unique_ptr>& val) { return writeByteVectorInternalPtr(this, val); } status_t Parcel::writeInt32Vector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeInt32); } status_t Parcel::writeInt32Vector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeInt32); } status_t Parcel::writeInt64Vector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeInt64); } status_t Parcel::writeInt64Vector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeInt64); } status_t Parcel::writeFloatVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeFloat); } status_t Parcel::writeFloatVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeFloat); } status_t Parcel::writeDoubleVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeDouble); } status_t Parcel::writeDoubleVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeDouble); } status_t Parcel::writeBoolVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeBool); } status_t Parcel::writeBoolVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeBool); } status_t Parcel::writeCharVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeChar); } status_t Parcel::writeCharVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeChar); } status_t Parcel::writeString16Vector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeString16); } status_t Parcel::writeString16Vector( const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeString16); } status_t Parcel::writeUtf8VectorAsUtf16Vector( const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16); } status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeUtf8AsUtf16); } status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); } status_t Parcel::writeUint32(uint32_t val) { return writeAligned(val); } status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } if (!val) { return writeInt32(-1); } status_t ret = writeInt32(static_cast(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } return ret; } status_t Parcel::writeByteArray(size_t len, const uint8_t *val) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } if (!val) { return writeInt32(-1); } status_t ret = writeInt32(static_cast(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } return ret; } status_t Parcel::writeBool(bool val) { return writeInt32(int32_t(val)); } status_t Parcel::writeChar(char16_t val) { return writeInt32(int32_t(val)); } status_t Parcel::writeByte(int8_t val) { return writeInt32(int32_t(val)); } status_t Parcel::writeInt64(int64_t val) { return writeAligned(val); } status_t Parcel::writeUint64(uint64_t val) { return writeAligned(val); } status_t Parcel::writePointer(uintptr_t val) { return writeAligned(val); } status_t Parcel::writeFloat(float val) { return writeAligned(val); } #if defined(__mips__) && defined(__mips_hard_float) status_t Parcel::writeDouble(double val) { union { double d; unsigned long long ll; } u; u.d = val; return writeAligned(u.ll); } #else status_t Parcel::writeDouble(double val) { return writeAligned(val); } #endif status_t Parcel::writeCString(const char* str) { return write(str, strlen(str)+1); } status_t Parcel::writeString8(const String8& str) { status_t err = writeInt32(str.bytes()); // only write string if its length is more than zero characters, // as readString8 will only read if the length field is non-zero. // this is slightly different from how writeString16 works. if (str.bytes() > 0 && err == NO_ERROR) { err = write(str.string(), str.bytes()+1); } return err; } status_t Parcel::writeString16(const std::unique_ptr& str) { if (!str) { return writeInt32(-1); } return writeString16(*str); } status_t Parcel::writeString16(const String16& str) { return writeString16(str.string(), str.size()); } status_t Parcel::writeString16(const char16_t* str, size_t len) { if (str == NULL) return writeInt32(-1); status_t err = writeInt32(len); if (err == NO_ERROR) { len *= sizeof(char16_t); uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t)); if (data) { memcpy(data, str, len); *reinterpret_cast(data+len) = 0; return NO_ERROR; } err = mError; } return err; } status_t Parcel::writeStrongBinder(const sp& val) { return flatten_binder(ProcessState::self(), val, this); } status_t Parcel::writeStrongBinderVector(const std::vector>& val) { return writeTypedVector(val, &Parcel::writeStrongBinder); } status_t Parcel::writeStrongBinderVector(const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeStrongBinder); } status_t Parcel::readStrongBinderVector(std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readStrongBinder); } status_t Parcel::readStrongBinderVector(std::vector>* val) const { return readTypedVector(val, &Parcel::readStrongBinder); } status_t Parcel::writeWeakBinder(const wp& val) { return flatten_binder(ProcessState::self(), val, this); } status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) { if (!parcelable) { return writeInt32(0); } return writeParcelable(*parcelable); } status_t Parcel::writeParcelable(const Parcelable& parcelable) { status_t status = writeInt32(1); // parcelable is not null. if (status != OK) { return status; } return parcelable.writeToParcel(this); } status_t Parcel::writeNativeHandle(const native_handle* handle) { if (!handle || handle->version != sizeof(native_handle)) return BAD_TYPE; status_t err; err = writeInt32(handle->numFds); if (err != NO_ERROR) return err; err = writeInt32(handle->numInts); if (err != NO_ERROR) return err; for (int i=0 ; err==NO_ERROR && inumFds ; i++) err = writeDupFileDescriptor(handle->data[i]); if (err != NO_ERROR) { ALOGD("write native handle, write dup fd failed"); return err; } err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts); return err; } status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { flat_binder_object obj; obj.type = BINDER_TYPE_FD; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ obj.handle = fd; obj.cookie = takeOwnership ? 1 : 0; return writeObject(obj, true); } status_t Parcel::writeDupFileDescriptor(int fd) { int dupFd = dup(fd); if (dupFd < 0) { return -errno; } status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/); if (err != OK) { close(dupFd); } return err; } status_t Parcel::writeUniqueFileDescriptor(const ScopedFd& fd) { return writeDupFileDescriptor(fd.get()); } status_t Parcel::writeUniqueFileDescriptorVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor); } status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor); } status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } status_t status; if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) { ALOGV("writeBlob: write in place"); status = writeInt32(BLOB_INPLACE); if (status) return status; void* ptr = writeInplace(len); if (!ptr) return NO_MEMORY; outBlob->init(-1, ptr, len, false); return NO_ERROR; } ALOGV("writeBlob: write to ashmem"); int fd = ashmem_create_region("Parcel Blob", len); if (fd < 0) return NO_MEMORY; int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); if (result < 0) { status = result; } else { void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { status = -errno; } else { if (!mutableCopy) { result = ashmem_set_prot_region(fd, PROT_READ); } if (result < 0) { status = result; } else { status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE); if (!status) { status = writeFileDescriptor(fd, true /*takeOwnership*/); if (!status) { outBlob->init(fd, ptr, len, mutableCopy); return NO_ERROR; } } } } ::munmap(ptr, len); } ::close(fd); return status; } status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd) { // Must match up with what's done in writeBlob. if (!mAllowFds) return FDS_NOT_ALLOWED; status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE); if (status) return status; return writeDupFileDescriptor(fd); } status_t Parcel::write(const FlattenableHelperInterface& val) { status_t err; // size if needed const size_t len = val.getFlattenedSize(); const size_t fd_count = val.getFdCount(); if ((len > INT32_MAX) || (fd_count >= gMaxFds)) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } err = this->writeInt32(len); if (err) return err; err = this->writeInt32(fd_count); if (err) return err; // payload void* const buf = this->writeInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; int* fds = NULL; if (fd_count) { fds = new (std::nothrow) int[fd_count]; if (fds == nullptr) { ALOGE("write: failed to allocate requested %zu fds", fd_count); return BAD_VALUE; } } err = val.flatten(buf, len, fds, fd_count); for (size_t i=0 ; iwriteDupFileDescriptor( fds[i] ); } if (fd_count) { delete [] fds; } return err; } status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) { const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; const bool enoughObjects = mObjectsSize < mObjectsCapacity; if (enoughData && enoughObjects) { restart_write: *reinterpret_cast(mData+mDataPos) = val; // remember if it's a file descriptor if (val.type == BINDER_TYPE_FD) { if (!mAllowFds) { // fail before modifying our object index return FDS_NOT_ALLOWED; } mHasFds = mFdsKnown = true; } // Need to write meta-data? if (nullMetaData || val.binder != 0) { mObjects[mObjectsSize] = mDataPos; acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize); mObjectsSize++; } return finishWrite(sizeof(flat_binder_object)); } if (!enoughData) { const status_t err = growData(sizeof(val)); if (err != NO_ERROR) return err; } if (!enoughObjects) { size_t newSize = ((mObjectsSize+2)*3)/2; if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == NULL) return NO_MEMORY; mObjects = objects; mObjectsCapacity = newSize; } goto restart_write; } status_t Parcel::writeNoException() { binder::Status status; return status.writeToParcel(this); } void Parcel::remove(size_t /*start*/, size_t /*amt*/) { LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); } status_t Parcel::read(void* outData, size_t len) const { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { memcpy(outData, mData+mDataPos, len); mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); return NO_ERROR; } return NOT_ENOUGH_DATA; } const void* Parcel::readInplace(size_t len) const { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return NULL; } if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { const void* data = mData+mDataPos; mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); return data; } return NULL; } template status_t Parcel::readAligned(T *pArg) const { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; mDataPos += sizeof(T); *pArg = *reinterpret_cast(data); return NO_ERROR; } else { return NOT_ENOUGH_DATA; } } template T Parcel::readAligned() const { T result; if (readAligned(&result) != NO_ERROR) { result = 0; } return result; } template status_t Parcel::writeAligned(T val) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: *reinterpret_cast(mData+mDataPos) = val; return finishWrite(sizeof(val)); } status_t err = growData(sizeof(val)); if (err == NO_ERROR) goto restart_write; return err; } namespace { template status_t readByteVectorInternal(const Parcel* parcel, std::vector* val) { val->clear(); int32_t size; status_t status = parcel->readInt32(&size); if (status != OK) { return status; } if (size < 0) { status = UNEXPECTED_NULL; return status; } if (size_t(size) > parcel->dataAvail()) { status = BAD_VALUE; return status; } const void* data = parcel->readInplace(size); if (!data) { status = BAD_VALUE; return status; } val->resize(size); memcpy(val->data(), data, size); return status; } template status_t readByteVectorInternalPtr( const Parcel* parcel, std::unique_ptr>* val) { const int32_t start = parcel->dataPosition(); int32_t size; status_t status = parcel->readInt32(&size); val->reset(); if (status != OK || size < 0) { return status; } parcel->setDataPosition(start); val->reset(new (std::nothrow) std::vector()); status = readByteVectorInternal(parcel, val->get()); if (status != OK) { val->reset(); } return status; } } // namespace status_t Parcel::readByteVector(std::vector* val) const { return readByteVectorInternal(this, val); } status_t Parcel::readByteVector(std::vector* val) const { return readByteVectorInternal(this, val); } status_t Parcel::readByteVector(std::unique_ptr>* val) const { return readByteVectorInternalPtr(this, val); } status_t Parcel::readByteVector(std::unique_ptr>* val) const { return readByteVectorInternalPtr(this, val); } status_t Parcel::readInt32Vector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readInt32); } status_t Parcel::readInt32Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readInt32); } status_t Parcel::readInt64Vector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readInt64); } status_t Parcel::readInt64Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readInt64); } status_t Parcel::readFloatVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readFloat); } status_t Parcel::readFloatVector(std::vector* val) const { return readTypedVector(val, &Parcel::readFloat); } status_t Parcel::readDoubleVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readDouble); } status_t Parcel::readDoubleVector(std::vector* val) const { return readTypedVector(val, &Parcel::readDouble); } status_t Parcel::readBoolVector(std::unique_ptr>* val) const { const int32_t start = dataPosition(); int32_t size; status_t status = readInt32(&size); val->reset(); if (status != OK || size < 0) { return status; } setDataPosition(start); val->reset(new (std::nothrow) std::vector()); status = readBoolVector(val->get()); if (status != OK) { val->reset(); } return status; } status_t Parcel::readBoolVector(std::vector* val) const { int32_t size; status_t status = readInt32(&size); if (status != OK) { return status; } if (size < 0) { return UNEXPECTED_NULL; } val->resize(size); /* C++ bool handling means a vector of bools isn't necessarily addressable * (we might use individual bits) */ bool data; for (int32_t i = 0; i < size; ++i) { status = readBool(&data); (*val)[i] = data; if (status != OK) { return status; } } return OK; } status_t Parcel::readCharVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readChar); } status_t Parcel::readCharVector(std::vector* val) const { return readTypedVector(val, &Parcel::readChar); } status_t Parcel::readString16Vector( std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readString16); } status_t Parcel::readString16Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readString16); } status_t Parcel::readUtf8VectorFromUtf16Vector( std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16); } status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readUtf8FromUtf16); } status_t Parcel::readInt32(int32_t *pArg) const { return readAligned(pArg); } int32_t Parcel::readInt32() const { return readAligned(); } status_t Parcel::readUint32(uint32_t *pArg) const { return readAligned(pArg); } uint32_t Parcel::readUint32() const { return readAligned(); } status_t Parcel::readInt64(int64_t *pArg) const { return readAligned(pArg); } int64_t Parcel::readInt64() const { return readAligned(); } status_t Parcel::readUint64(uint64_t *pArg) const { return readAligned(pArg); } uint64_t Parcel::readUint64() const { return readAligned(); } status_t Parcel::readPointer(uintptr_t *pArg) const { status_t ret; binder_uintptr_t ptr; ret = readAligned(&ptr); if (!ret) *pArg = ptr; return ret; } uintptr_t Parcel::readPointer() const { return readAligned(); } status_t Parcel::readFloat(float *pArg) const { return readAligned(pArg); } float Parcel::readFloat() const { return readAligned(); } #if defined(__mips__) && defined(__mips_hard_float) status_t Parcel::readDouble(double *pArg) const { union { double d; unsigned long long ll; } u; u.d = 0; status_t status; status = readAligned(&u.ll); *pArg = u.d; return status; } double Parcel::readDouble() const { union { double d; unsigned long long ll; } u; u.ll = readAligned(); return u.d; } #else status_t Parcel::readDouble(double *pArg) const { return readAligned(pArg); } double Parcel::readDouble() const { return readAligned(); } #endif status_t Parcel::readIntPtr(intptr_t *pArg) const { return readAligned(pArg); } intptr_t Parcel::readIntPtr() const { return readAligned(); } status_t Parcel::readBool(bool *pArg) const { int32_t tmp; status_t ret = readInt32(&tmp); *pArg = (tmp != 0); return ret; } bool Parcel::readBool() const { return readInt32() != 0; } status_t Parcel::readChar(char16_t *pArg) const { int32_t tmp; status_t ret = readInt32(&tmp); *pArg = char16_t(tmp); return ret; } char16_t Parcel::readChar() const { return char16_t(readInt32()); } status_t Parcel::readByte(int8_t *pArg) const { int32_t tmp; status_t ret = readInt32(&tmp); *pArg = int8_t(tmp); return ret; } int8_t Parcel::readByte() const { return int8_t(readInt32()); } status_t Parcel::readUtf8FromUtf16(std::string* str) const { size_t utf16Size = 0; const char16_t* src = readString16Inplace(&utf16Size); if (!src) { return UNEXPECTED_NULL; } // Save ourselves the trouble, we're done. if (utf16Size == 0u) { str->clear(); return NO_ERROR; } // Allow for closing '\0' ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size) + 1; if (utf8Size < 1) { return BAD_VALUE; } // Note that while it is probably safe to assume string::resize keeps a // spare byte around for the trailing null, we still pass the size including the trailing null str->resize(utf8Size); utf16_to_utf8(src, utf16Size, &((*str)[0]), utf8Size); str->resize(utf8Size - 1); return NO_ERROR; } status_t Parcel::readUtf8FromUtf16(std::unique_ptr* str) const { const int32_t start = dataPosition(); int32_t size; status_t status = readInt32(&size); str->reset(); if (status != OK || size < 0) { return status; } setDataPosition(start); str->reset(new (std::nothrow) std::string()); return readUtf8FromUtf16(str->get()); } const char* Parcel::readCString() const { const size_t avail = mDataSize-mDataPos; if (avail > 0) { const char* str = reinterpret_cast(mData+mDataPos); // is the string's trailing NUL within the parcel's valid bounds? const char* eos = reinterpret_cast(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; mDataPos += pad_size(len+1); ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos); return str; } } return NULL; } String8 Parcel::readString8() const { int32_t size = readInt32(); // watch for potential int overflow adding 1 for trailing NUL if (size > 0 && size < INT32_MAX) { const char* str = (const char*)readInplace(size+1); if (str) return String8(str, size); } return String8(); } String16 Parcel::readString16() const { size_t len; const char16_t* str = readString16Inplace(&len); if (str) return String16(str, len); ALOGE("Reading a NULL string not supported here."); return String16(); } status_t Parcel::readString16(std::unique_ptr* pArg) const { const int32_t start = dataPosition(); int32_t size; status_t status = readInt32(&size); pArg->reset(); if (status != OK || size < 0) { return status; } setDataPosition(start); pArg->reset(new (std::nothrow) String16()); status = readString16(pArg->get()); if (status != OK) { pArg->reset(); } return status; } status_t Parcel::readString16(String16* pArg) const { size_t len; const char16_t* str = readString16Inplace(&len); if (str) { pArg->setTo(str, len); return 0; } else { *pArg = String16(); return UNEXPECTED_NULL; } } const char16_t* Parcel::readString16Inplace(size_t* outLen) const { int32_t size = readInt32(); // watch for potential int overflow from size+1 if (size >= 0 && size < INT32_MAX) { *outLen = size; const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t)); if (str != NULL) { return str; } } *outLen = 0; return NULL; } status_t Parcel::readStrongBinder(sp* val) const { return unflatten_binder(ProcessState::self(), *this, val); } sp Parcel::readStrongBinder() const { sp val; readStrongBinder(&val); return val; } wp Parcel::readWeakBinder() const { wp val; unflatten_binder(ProcessState::self(), *this, &val); return val; } status_t Parcel::readParcelable(Parcelable* parcelable) const { int32_t have_parcelable = 0; status_t status = readInt32(&have_parcelable); if (status != OK) { return status; } if (!have_parcelable) { return UNEXPECTED_NULL; } return parcelable->readFromParcel(this); } int32_t Parcel::readExceptionCode() const { binder::Status status; status.readFromParcel(*this); return status.exceptionCode(); } native_handle* Parcel::readNativeHandle() const { int numFds, numInts; status_t err; err = readInt32(&numFds); if (err != NO_ERROR) return 0; err = readInt32(&numInts); if (err != NO_ERROR) return 0; native_handle* h = native_handle_create(numFds, numInts); if (!h) { return 0; } for (int i=0 ; err==NO_ERROR && idata[i] = dup(readFileDescriptor()); if (h->data[i] < 0) { for (int j = 0; j < i; j++) { close(h->data[j]); } native_handle_delete(h); return 0; } } err = read(h->data + numFds, sizeof(int)*numInts); if (err != NO_ERROR) { native_handle_close(h); native_handle_delete(h); h = 0; } return h; } int Parcel::readFileDescriptor() const { const flat_binder_object* flat = readObject(true); if (flat && flat->type == BINDER_TYPE_FD) { return flat->handle; } return BAD_TYPE; } status_t Parcel::readUniqueFileDescriptor(ScopedFd* val) const { int got = readFileDescriptor(); if (got == BAD_TYPE) { return BAD_TYPE; } val->reset(dup(got)); if (val->get() < 0) { return BAD_VALUE; } return OK; } status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor); } status_t Parcel::readUniqueFileDescriptorVector(std::vector* val) const { return readTypedVector(val, &Parcel::readUniqueFileDescriptor); } status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const { int32_t blobType; status_t status = readInt32(&blobType); if (status) return status; if (blobType == BLOB_INPLACE) { ALOGV("readBlob: read in place"); const void* ptr = readInplace(len); if (!ptr) return BAD_VALUE; outBlob->init(-1, const_cast(ptr), len, false); return NO_ERROR; } ALOGV("readBlob: read from ashmem"); bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE); int fd = readFileDescriptor(); if (fd == int(BAD_TYPE)) return BAD_VALUE; void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) return NO_MEMORY; outBlob->init(fd, ptr, len, isMutable); return NO_ERROR; } status_t Parcel::read(FlattenableHelperInterface& val) const { // size const size_t len = this->readInt32(); const size_t fd_count = this->readInt32(); if ((len > INT32_MAX) || (fd_count >= gMaxFds)) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } // payload void const* const buf = this->readInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; int* fds = NULL; if (fd_count) { fds = new (std::nothrow) int[fd_count]; if (fds == nullptr) { ALOGE("read: failed to allocate requested %zu fds", fd_count); return BAD_VALUE; } } status_t err = NO_ERROR; for (size_t i=0 ; ireadFileDescriptor()); if (fds[i] < 0) { err = BAD_VALUE; ALOGE("dup() failed in Parcel::read, i is %zu, fds[i] is %d, fd_count is %zu, error: %s", i, fds[i], fd_count, strerror(errno)); } } if (err == NO_ERROR) { err = val.unflatten(buf, len, fds, fd_count); } if (fd_count) { delete [] fds; } return err; } const flat_binder_object* Parcel::readObject(bool nullMetaData) const { const size_t DPOS = mDataPos; if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) { const flat_binder_object* obj = reinterpret_cast(mData+DPOS); mDataPos = DPOS + sizeof(flat_binder_object); if (!nullMetaData && (obj->cookie == 0 && obj->binder == 0)) { // When transferring a NULL object, we don't write it into // the object list, so we don't want to check for it when // reading. ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos); return obj; } // Ensure that this object is valid... binder_size_t* const OBJS = mObjects; const size_t N = mObjectsSize; size_t opos = mNextObjectHint; if (N > 0) { ALOGV("Parcel %p looking for obj at %zu, hint=%zu", this, DPOS, opos); // Start at the current hint position, looking for an object at // the current data position. if (opos < N) { while (opos < (N-1) && OBJS[opos] < DPOS) { opos++; } } else { opos = N-1; } if (OBJS[opos] == DPOS) { // Found it! ALOGV("Parcel %p found obj %zu at index %zu with forward search", this, DPOS, opos); mNextObjectHint = opos+1; ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos); return obj; } // Look backwards for it... while (opos > 0 && OBJS[opos] > DPOS) { opos--; } if (OBJS[opos] == DPOS) { // Found it! ALOGV("Parcel %p found obj %zu at index %zu with backward search", this, DPOS, opos); mNextObjectHint = opos+1; ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos); return obj; } } ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object list", this, DPOS); } return NULL; } void Parcel::closeFileDescriptors() { size_t i = mObjectsSize; if (i > 0) { //ALOGI("Closing file descriptors for %zu objects...", i); } while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast(mData+mObjects[i]); if (flat->type == BINDER_TYPE_FD) { //ALOGI("Closing fd: %ld", flat->handle); close(flat->handle); } } } uintptr_t Parcel::ipcData() const { return reinterpret_cast(mData); } size_t Parcel::ipcDataSize() const { return (mDataSize > mDataPos ? mDataSize : mDataPos); } uintptr_t Parcel::ipcObjects() const { return reinterpret_cast(mObjects); } size_t Parcel::ipcObjectsCount() const { return mObjectsSize; } void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) { binder_size_t minOffset = 0; freeDataNoInit(); mError = NO_ERROR; mData = const_cast(data); mDataSize = mDataCapacity = dataSize; //ALOGI("setDataReference Setting data size of %p to %lu (pid=%d)", this, mDataSize, getpid()); mDataPos = 0; ALOGV("setDataReference Setting data pos of %p to %zu", this, mDataPos); mObjects = const_cast(objects); mObjectsSize = mObjectsCapacity = objectsCount; mNextObjectHint = 0; mOwner = relFunc; mOwnerCookie = relCookie; for (size_t i = 0; i < mObjectsSize; i++) { binder_size_t offset = mObjects[i]; if (offset < minOffset) { ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n", __func__, (uint64_t)offset, (uint64_t)minOffset); mObjectsSize = 0; break; } minOffset = offset + sizeof(flat_binder_object); } scanForFds(); } void Parcel::print(TextOutput& to, uint32_t /*flags*/) const { to << "Parcel("; if (errorCheck() != NO_ERROR) { const status_t err = errorCheck(); to << "Error: " << (void*)(intptr_t)err << " \"" << strerror(-err) << "\""; } else if (dataSize() > 0) { const uint8_t* DATA = data(); to << indent << HexDump(DATA, dataSize()) << dedent; const binder_size_t* OBJS = objects(); const size_t N = objectsCount(); for (size_t i=0; i(DATA+OBJS[i]); to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": " << TypeCode(flat->type & 0x7f7f7f00) << " = " << flat->binder; } } else { to << "NULL"; } to << ")"; } void Parcel::releaseObjects() { const sp proc(ProcessState::self()); size_t i = mObjectsSize; uint8_t* const data = mData; binder_size_t* const objects = mObjects; while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast(data+objects[i]); release_object(proc, *flat, this, &mOpenAshmemSize); } } void Parcel::acquireObjects() { const sp proc(ProcessState::self()); size_t i = mObjectsSize; uint8_t* const data = mData; binder_size_t* const objects = mObjects; while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast(data+objects[i]); acquire_object(proc, *flat, this, &mOpenAshmemSize); } } void Parcel::freeData() { freeDataNoInit(); initState(); } void Parcel::freeDataNoInit() { if (mOwner) { LOG_ALLOC("Parcel %p: freeing other owner data", this); //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); } else { LOG_ALLOC("Parcel %p: freeing allocated data", this); releaseObjects(); if (mData) { LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity); pthread_mutex_lock(&gParcelGlobalAllocSizeLock); if (mDataCapacity <= gParcelGlobalAllocSize) { gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity; } else { gParcelGlobalAllocSize = 0; } if (gParcelGlobalAllocCount > 0) { gParcelGlobalAllocCount--; } pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); free(mData); } if (mObjects) free(mObjects); } } status_t Parcel::growData(size_t len) { if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY : continueWrite(newSize); } status_t Parcel::restartWrite(size_t desired) { if (desired > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } if (mOwner) { freeData(); return continueWrite(desired); } uint8_t* data = (uint8_t*)realloc(mData, desired); if (!data && desired > mDataCapacity) { mError = NO_MEMORY; return NO_MEMORY; } releaseObjects(); if (data) { LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired); pthread_mutex_lock(&gParcelGlobalAllocSizeLock); gParcelGlobalAllocSize += desired; gParcelGlobalAllocSize -= mDataCapacity; if (!mData) { gParcelGlobalAllocCount++; } pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); mData = data; mDataCapacity = desired; } mDataSize = mDataPos = 0; ALOGV("restartWrite Setting data size of %p to %zu", this, mDataSize); ALOGV("restartWrite Setting data pos of %p to %zu", this, mDataPos); free(mObjects); mObjects = NULL; mObjectsSize = mObjectsCapacity = 0; mNextObjectHint = 0; mHasFds = false; mFdsKnown = true; mAllowFds = true; return NO_ERROR; } status_t Parcel::continueWrite(size_t desired) { if (desired > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. return BAD_VALUE; } // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; if (desired < mDataSize) { if (desired == 0) { objectsSize = 0; } else { while (objectsSize > 0) { if (mObjects[objectsSize-1] < desired) break; objectsSize--; } } } if (mOwner) { // If the size is going to zero, just release the owner's data. if (desired == 0) { freeData(); return NO_ERROR; } // If there is a different owner, we need to take // posession. uint8_t* data = (uint8_t*)malloc(desired); if (!data) { mError = NO_MEMORY; return NO_MEMORY; } binder_size_t* objects = NULL; if (objectsSize) { objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t)); if (!objects) { free(data); mError = NO_MEMORY; return NO_MEMORY; } // Little hack to only acquire references on objects // we will be keeping. size_t oldObjectsSize = mObjectsSize; mObjectsSize = objectsSize; acquireObjects(); mObjectsSize = oldObjectsSize; } if (mData) { memcpy(data, mData, mDataSize < desired ? mDataSize : desired); } if (objects && mObjects) { memcpy(objects, mObjects, objectsSize*sizeof(binder_size_t)); } //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); mOwner = NULL; LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired); pthread_mutex_lock(&gParcelGlobalAllocSizeLock); gParcelGlobalAllocSize += desired; gParcelGlobalAllocCount++; pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); mData = data; mObjects = objects; mDataSize = (mDataSize < desired) ? mDataSize : desired; ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize); mDataCapacity = desired; mObjectsSize = mObjectsCapacity = objectsSize; mNextObjectHint = 0; } else if (mData) { if (objectsSize < mObjectsSize) { // Need to release refs on any objects we are dropping. const sp proc(ProcessState::self()); for (size_t i=objectsSize; i(mData+mObjects[i]); if (flat->type == BINDER_TYPE_FD) { // will need to rescan because we may have lopped off the only FDs mFdsKnown = false; } release_object(proc, *flat, this, &mOpenAshmemSize); } binder_size_t* objects = (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t)); if (objects) { mObjects = objects; } mObjectsSize = objectsSize; mNextObjectHint = 0; } // We own the data, so we can just do a realloc(). if (desired > mDataCapacity) { uint8_t* data = (uint8_t*)realloc(mData, desired); if (data) { LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity, desired); pthread_mutex_lock(&gParcelGlobalAllocSizeLock); gParcelGlobalAllocSize += desired; gParcelGlobalAllocSize -= mDataCapacity; pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); mData = data; mDataCapacity = desired; } else if (desired > mDataCapacity) { mError = NO_MEMORY; return NO_MEMORY; } } else { if (mDataSize > desired) { mDataSize = desired; ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize); } if (mDataPos > desired) { mDataPos = desired; ALOGV("continueWrite Setting data pos of %p to %zu", this, mDataPos); } } } else { // This is the first data. Easy! uint8_t* data = (uint8_t*)malloc(desired); if (!data) { mError = NO_MEMORY; return NO_MEMORY; } if(!(mDataCapacity == 0 && mObjects == NULL && mObjectsCapacity == 0)) { ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired); } LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired); pthread_mutex_lock(&gParcelGlobalAllocSizeLock); gParcelGlobalAllocSize += desired; gParcelGlobalAllocCount++; pthread_mutex_unlock(&gParcelGlobalAllocSizeLock); mData = data; mDataSize = mDataPos = 0; ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize); ALOGV("continueWrite Setting data pos of %p to %zu", this, mDataPos); mDataCapacity = desired; } return NO_ERROR; } void Parcel::initState() { LOG_ALLOC("Parcel %p: initState", this); mError = NO_ERROR; mData = 0; mDataSize = 0; mDataCapacity = 0; mDataPos = 0; ALOGV("initState Setting data size of %p to %zu", this, mDataSize); ALOGV("initState Setting data pos of %p to %zu", this, mDataPos); mObjects = NULL; mObjectsSize = 0; mObjectsCapacity = 0; mNextObjectHint = 0; mHasFds = false; mFdsKnown = true; mAllowFds = true; mOwner = NULL; mOpenAshmemSize = 0; // racing multiple init leads only to multiple identical write if (gMaxFds == 0) { struct rlimit result; if (!getrlimit(RLIMIT_NOFILE, &result)) { gMaxFds = (size_t)result.rlim_cur; //ALOGI("parcel fd limit set to %zu", gMaxFds); } else { ALOGW("Unable to getrlimit: %s", strerror(errno)); gMaxFds = 1024; } } } void Parcel::scanForFds() const { bool hasFds = false; for (size_t i=0; i(mData + mObjects[i]); if (flat->type == BINDER_TYPE_FD) { hasFds = true; break; } } mHasFds = hasFds; mFdsKnown = true; } size_t Parcel::getBlobAshmemSize() const { // This used to return the size of all blobs that were written to ashmem, now we're returning // the ashmem currently referenced by this Parcel, which should be equivalent. // TODO: Remove method once ABI can be changed. return mOpenAshmemSize; } size_t Parcel::getOpenAshmemSize() const { return mOpenAshmemSize; } // --- Parcel::Blob --- Parcel::Blob::Blob() : mFd(-1), mData(NULL), mSize(0), mMutable(false) { } Parcel::Blob::~Blob() { release(); } void Parcel::Blob::release() { if (mFd != -1 && mData) { ::munmap(mData, mSize); } clear(); } void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) { mFd = fd; mData = data; mSize = size; mMutable = isMutable; } void Parcel::Blob::clear() { mFd = -1; mData = NULL; mSize = 0; mMutable = false; } }; // namespace android libs/binder/PermissionCache.cpp0100644 0000000 0000000 00000006700 13077405420 015566 0ustar000000000 0000000 /* * Copyright (C) 2009 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. */ #define LOG_TAG "PermissionCache" #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ; // ---------------------------------------------------------------------------- PermissionCache::PermissionCache() { } status_t PermissionCache::check(bool* granted, const String16& permission, uid_t uid) const { Mutex::Autolock _l(mLock); Entry e; e.name = permission; e.uid = uid; ssize_t index = mCache.indexOf(e); if (index >= 0) { *granted = mCache.itemAt(index).granted; return NO_ERROR; } return NAME_NOT_FOUND; } void PermissionCache::cache(const String16& permission, uid_t uid, bool granted) { Mutex::Autolock _l(mLock); Entry e; ssize_t index = mPermissionNamesPool.indexOf(permission); if (index > 0) { e.name = mPermissionNamesPool.itemAt(index); } else { mPermissionNamesPool.add(permission); e.name = permission; } // note, we don't need to store the pid, which is not actually used in // permission checks e.uid = uid; e.granted = granted; index = mCache.indexOf(e); if (index < 0) { mCache.add(e); } } void PermissionCache::purge() { Mutex::Autolock _l(mLock); mCache.clear(); } bool PermissionCache::checkCallingPermission(const String16& permission) { return PermissionCache::checkCallingPermission(permission, NULL, NULL); } bool PermissionCache::checkCallingPermission( const String16& permission, int32_t* outPid, int32_t* outUid) { IPCThreadState* ipcState = IPCThreadState::self(); pid_t pid = ipcState->getCallingPid(); uid_t uid = ipcState->getCallingUid(); if (outPid) *outPid = pid; if (outUid) *outUid = uid; return PermissionCache::checkPermission(permission, pid, uid); } bool PermissionCache::checkPermission( const String16& permission, pid_t pid, uid_t uid) { if ((uid == 0) || (pid == getpid())) { // root and ourselves is always okay return true; } PermissionCache& pc(PermissionCache::getInstance()); bool granted = false; if (pc.check(&granted, permission, uid) != NO_ERROR) { nsecs_t t = -systemTime(); granted = android::checkPermission(permission, pid, uid); t += systemTime(); ALOGD("checking %s for uid=%d => %s (%d us)", String8(permission).string(), uid, granted?"granted":"denied", (int)ns2us(t)); pc.cache(permission, uid, granted); } return granted; } // --------------------------------------------------------------------------- }; // namespace android libs/binder/PersistableBundle.cpp0100644 0000000 0000000 00000035614 13077405420 016127 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "PersistableBundle" #include #include #include #include #include #include using android::BAD_TYPE; using android::BAD_VALUE; using android::NO_ERROR; using android::Parcel; using android::sp; using android::status_t; using android::UNEXPECTED_NULL; enum { // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java. BUNDLE_MAGIC = 0x4C444E42, }; enum { // Keep in sync with frameworks/base/core/java/android/os/Parcel.java. VAL_STRING = 0, VAL_INTEGER = 1, VAL_LONG = 6, VAL_DOUBLE = 8, VAL_BOOLEAN = 9, VAL_STRINGARRAY = 14, VAL_INTARRAY = 18, VAL_LONGARRAY = 19, VAL_BOOLEANARRAY = 23, VAL_PERSISTABLEBUNDLE = 25, VAL_DOUBLEARRAY = 28, }; namespace { template bool getValue(const android::String16& key, T* out, const std::map& map) { const auto& it = map.find(key); if (it == map.end()) return false; *out = it->second; return true; } } // namespace namespace android { namespace os { #define RETURN_IF_FAILED(calledOnce) \ { \ status_t returnStatus = calledOnce; \ if (returnStatus) { \ ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ return returnStatus; \ } \ } #define RETURN_IF_ENTRY_ERASED(map, key) \ { \ size_t num_erased = map.erase(key); \ if (num_erased) { \ ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ return num_erased; \ } \ } status_t PersistableBundle::writeToParcel(Parcel* parcel) const { /* * Keep implementation in sync with writeToParcelInner() in * frameworks/base/core/java/android/os/BaseBundle.java. */ // Special case for empty bundles. if (empty()) { RETURN_IF_FAILED(parcel->writeInt32(0)); return NO_ERROR; } size_t length_pos = parcel->dataPosition(); RETURN_IF_FAILED(parcel->writeInt32(1)); // dummy, will hold length RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC)); size_t start_pos = parcel->dataPosition(); RETURN_IF_FAILED(writeToParcelInner(parcel)); size_t end_pos = parcel->dataPosition(); // Backpatch length. This length value includes the length header. parcel->setDataPosition(length_pos); size_t length = end_pos - start_pos; if (length > std::numeric_limits::max()) { ALOGE("Parcel length (%zu) too large to store in 32-bit signed int", length); return BAD_VALUE; } RETURN_IF_FAILED(parcel->writeInt32(static_cast(length))); parcel->setDataPosition(end_pos); return NO_ERROR; } status_t PersistableBundle::readFromParcel(const Parcel* parcel) { /* * Keep implementation in sync with readFromParcelInner() in * frameworks/base/core/java/android/os/BaseBundle.java. */ int32_t length = parcel->readInt32(); if (length < 0) { ALOGE("Bad length in parcel: %d", length); return UNEXPECTED_NULL; } return readFromParcelInner(parcel, static_cast(length)); } bool PersistableBundle::empty() const { return size() == 0u; } size_t PersistableBundle::size() const { return (mBoolMap.size() + mIntMap.size() + mLongMap.size() + mDoubleMap.size() + mStringMap.size() + mBoolVectorMap.size() + mIntVectorMap.size() + mLongVectorMap.size() + mDoubleVectorMap.size() + mStringVectorMap.size() + mPersistableBundleMap.size()); } size_t PersistableBundle::erase(const String16& key) { RETURN_IF_ENTRY_ERASED(mBoolMap, key); RETURN_IF_ENTRY_ERASED(mIntMap, key); RETURN_IF_ENTRY_ERASED(mLongMap, key); RETURN_IF_ENTRY_ERASED(mDoubleMap, key); RETURN_IF_ENTRY_ERASED(mStringMap, key); RETURN_IF_ENTRY_ERASED(mBoolVectorMap, key); RETURN_IF_ENTRY_ERASED(mIntVectorMap, key); RETURN_IF_ENTRY_ERASED(mLongVectorMap, key); RETURN_IF_ENTRY_ERASED(mDoubleVectorMap, key); RETURN_IF_ENTRY_ERASED(mStringVectorMap, key); return mPersistableBundleMap.erase(key); } void PersistableBundle::putBoolean(const String16& key, bool value) { erase(key); mBoolMap[key] = value; } void PersistableBundle::putInt(const String16& key, int32_t value) { erase(key); mIntMap[key] = value; } void PersistableBundle::putLong(const String16& key, int64_t value) { erase(key); mLongMap[key] = value; } void PersistableBundle::putDouble(const String16& key, double value) { erase(key); mDoubleMap[key] = value; } void PersistableBundle::putString(const String16& key, const String16& value) { erase(key); mStringMap[key] = value; } void PersistableBundle::putBooleanVector(const String16& key, const std::vector& value) { erase(key); mBoolVectorMap[key] = value; } void PersistableBundle::putIntVector(const String16& key, const std::vector& value) { erase(key); mIntVectorMap[key] = value; } void PersistableBundle::putLongVector(const String16& key, const std::vector& value) { erase(key); mLongVectorMap[key] = value; } void PersistableBundle::putDoubleVector(const String16& key, const std::vector& value) { erase(key); mDoubleVectorMap[key] = value; } void PersistableBundle::putStringVector(const String16& key, const std::vector& value) { erase(key); mStringVectorMap[key] = value; } void PersistableBundle::putPersistableBundle(const String16& key, const PersistableBundle& value) { erase(key); mPersistableBundleMap[key] = value; } bool PersistableBundle::getBoolean(const String16& key, bool* out) const { return getValue(key, out, mBoolMap); } bool PersistableBundle::getInt(const String16& key, int32_t* out) const { return getValue(key, out, mIntMap); } bool PersistableBundle::getLong(const String16& key, int64_t* out) const { return getValue(key, out, mLongMap); } bool PersistableBundle::getDouble(const String16& key, double* out) const { return getValue(key, out, mDoubleMap); } bool PersistableBundle::getString(const String16& key, String16* out) const { return getValue(key, out, mStringMap); } bool PersistableBundle::getBooleanVector(const String16& key, std::vector* out) const { return getValue(key, out, mBoolVectorMap); } bool PersistableBundle::getIntVector(const String16& key, std::vector* out) const { return getValue(key, out, mIntVectorMap); } bool PersistableBundle::getLongVector(const String16& key, std::vector* out) const { return getValue(key, out, mLongVectorMap); } bool PersistableBundle::getDoubleVector(const String16& key, std::vector* out) const { return getValue(key, out, mDoubleVectorMap); } bool PersistableBundle::getStringVector(const String16& key, std::vector* out) const { return getValue(key, out, mStringVectorMap); } bool PersistableBundle::getPersistableBundle(const String16& key, PersistableBundle* out) const { return getValue(key, out, mPersistableBundleMap); } status_t PersistableBundle::writeToParcelInner(Parcel* parcel) const { /* * To keep this implementation in sync with writeArrayMapInternal() in * frameworks/base/core/java/android/os/Parcel.java, the number of key * value pairs must be written into the parcel before writing the key-value * pairs themselves. */ size_t num_entries = size(); if (num_entries > std::numeric_limits::max()) { ALOGE("The size of this PersistableBundle (%zu) too large to store in 32-bit signed int", num_entries); return BAD_VALUE; } RETURN_IF_FAILED(parcel->writeInt32(static_cast(num_entries))); for (const auto& key_val_pair : mBoolMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_BOOLEAN)); RETURN_IF_FAILED(parcel->writeBool(key_val_pair.second)); } for (const auto& key_val_pair : mIntMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_INTEGER)); RETURN_IF_FAILED(parcel->writeInt32(key_val_pair.second)); } for (const auto& key_val_pair : mLongMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_LONG)); RETURN_IF_FAILED(parcel->writeInt64(key_val_pair.second)); } for (const auto& key_val_pair : mDoubleMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_DOUBLE)); RETURN_IF_FAILED(parcel->writeDouble(key_val_pair.second)); } for (const auto& key_val_pair : mStringMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_STRING)); RETURN_IF_FAILED(parcel->writeString16(key_val_pair.second)); } for (const auto& key_val_pair : mBoolVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_BOOLEANARRAY)); RETURN_IF_FAILED(parcel->writeBoolVector(key_val_pair.second)); } for (const auto& key_val_pair : mIntVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_INTARRAY)); RETURN_IF_FAILED(parcel->writeInt32Vector(key_val_pair.second)); } for (const auto& key_val_pair : mLongVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_LONGARRAY)); RETURN_IF_FAILED(parcel->writeInt64Vector(key_val_pair.second)); } for (const auto& key_val_pair : mDoubleVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_DOUBLEARRAY)); RETURN_IF_FAILED(parcel->writeDoubleVector(key_val_pair.second)); } for (const auto& key_val_pair : mStringVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_STRINGARRAY)); RETURN_IF_FAILED(parcel->writeString16Vector(key_val_pair.second)); } for (const auto& key_val_pair : mPersistableBundleMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_PERSISTABLEBUNDLE)); RETURN_IF_FAILED(key_val_pair.second.writeToParcel(parcel)); } return NO_ERROR; } status_t PersistableBundle::readFromParcelInner(const Parcel* parcel, size_t length) { /* * Note: we don't actually use length for anything other than an empty PersistableBundle * check, since we do not actually need to copy in an entire Parcel, unlike in the Java * implementation. */ if (length == 0) { // Empty PersistableBundle or end of data. return NO_ERROR; } int32_t magic; RETURN_IF_FAILED(parcel->readInt32(&magic)); if (magic != BUNDLE_MAGIC) { ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic); return BAD_VALUE; } /* * To keep this implementation in sync with unparcel() in * frameworks/base/core/java/android/os/BaseBundle.java, the number of * key-value pairs must be read from the parcel before reading the key-value * pairs themselves. */ int32_t num_entries; RETURN_IF_FAILED(parcel->readInt32(&num_entries)); for (; num_entries > 0; --num_entries) { size_t start_pos = parcel->dataPosition(); String16 key; int32_t value_type; RETURN_IF_FAILED(parcel->readString16(&key)); RETURN_IF_FAILED(parcel->readInt32(&value_type)); /* * We assume that both the C++ and Java APIs ensure that all keys in a PersistableBundle * are unique. */ switch (value_type) { case VAL_STRING: { RETURN_IF_FAILED(parcel->readString16(&mStringMap[key])); break; } case VAL_INTEGER: { RETURN_IF_FAILED(parcel->readInt32(&mIntMap[key])); break; } case VAL_LONG: { RETURN_IF_FAILED(parcel->readInt64(&mLongMap[key])); break; } case VAL_DOUBLE: { RETURN_IF_FAILED(parcel->readDouble(&mDoubleMap[key])); break; } case VAL_BOOLEAN: { RETURN_IF_FAILED(parcel->readBool(&mBoolMap[key])); break; } case VAL_STRINGARRAY: { RETURN_IF_FAILED(parcel->readString16Vector(&mStringVectorMap[key])); break; } case VAL_INTARRAY: { RETURN_IF_FAILED(parcel->readInt32Vector(&mIntVectorMap[key])); break; } case VAL_LONGARRAY: { RETURN_IF_FAILED(parcel->readInt64Vector(&mLongVectorMap[key])); break; } case VAL_BOOLEANARRAY: { RETURN_IF_FAILED(parcel->readBoolVector(&mBoolVectorMap[key])); break; } case VAL_PERSISTABLEBUNDLE: { RETURN_IF_FAILED(mPersistableBundleMap[key].readFromParcel(parcel)); break; } case VAL_DOUBLEARRAY: { RETURN_IF_FAILED(parcel->readDoubleVector(&mDoubleVectorMap[key])); break; } default: { ALOGE("Unrecognized type: %d", value_type); return BAD_TYPE; break; } } } return NO_ERROR; } } // namespace os } // namespace android libs/binder/ProcessInfoService.cpp0100644 0000000 0000000 00000004160 13077405420 016263 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace android { ProcessInfoService::ProcessInfoService() { updateBinderLocked(); } status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states) { status_t err = NO_ERROR; sp pis; mProcessInfoLock.lock(); pis = mProcessInfoService; mProcessInfoLock.unlock(); for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) { if (pis != NULL) { err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states); if (err == NO_ERROR) return NO_ERROR; // success if (IInterface::asBinder(pis)->isBinderAlive()) return err; } sleep(1); mProcessInfoLock.lock(); if (pis == mProcessInfoService) { updateBinderLocked(); } pis = mProcessInfoService; mProcessInfoLock.unlock(); } ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.", __FUNCTION__, BINDER_ATTEMPT_LIMIT); return TIMED_OUT; } void ProcessInfoService::updateBinderLocked() { const sp sm(defaultServiceManager()); if (sm != NULL) { const String16 name("processinfo"); mProcessInfoService = interface_cast(sm->checkService(name)); } } ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService); }; // namespace android libs/binder/ProcessState.cpp0100644 0000000 0000000 00000026263 13077405420 015137 0ustar000000000 0000000 /* * Copyright (C) 2005 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. */ #define LOG_TAG "ProcessState" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) #define DEFAULT_MAX_BINDER_THREADS 15 // ------------------------------------------------------------------------- namespace android { class PoolThread : public Thread { public: PoolThread(bool isMain) : mIsMain(isMain) { } protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; } const bool mIsMain; }; sp ProcessState::self() { Mutex::Autolock _l(gProcessMutex); if (gProcess != NULL) { return gProcess; } gProcess = new ProcessState; return gProcess; } void ProcessState::setContextObject(const sp& object) { setContextObject(object, String16("default")); } sp ProcessState::getContextObject(const sp& /*caller*/) { return getStrongProxyForHandle(0); } void ProcessState::setContextObject(const sp& object, const String16& name) { AutoMutex _l(mLock); mContexts.add(name, object); } sp ProcessState::getContextObject(const String16& name, const sp& caller) { mLock.lock(); sp object( mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL); mLock.unlock(); //printf("Getting context object %s for %p\n", String8(name).string(), caller.get()); if (object != NULL) return object; // Don't attempt to retrieve contexts if we manage them if (mManagesContexts) { ALOGE("getContextObject(%s) failed, but we manage the contexts!\n", String8(name).string()); return NULL; } IPCThreadState* ipc = IPCThreadState::self(); { Parcel data, reply; // no interface token on this magic transaction data.writeString16(name); data.writeStrongBinder(caller); status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0); if (result == NO_ERROR) { object = reply.readStrongBinder(); } } ipc->flushCommands(); if (object != NULL) setContextObject(object, name); return object; } void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } } bool ProcessState::isContextManager(void) const { return mManagesContexts; } bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData) { if (!mManagesContexts) { AutoMutex _l(mLock); mBinderContextCheckFunc = checkFunc; mBinderContextUserData = userData; int dummy = 0; status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); if (result == 0) { mManagesContexts = true; } else if (result == -1) { mBinderContextCheckFunc = NULL; mBinderContextUserData = NULL; ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); } } return mManagesContexts; } ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle) { const size_t N=mHandleToObject.size(); if (N <= (size_t)handle) { handle_entry e; e.binder = NULL; e.refs = NULL; status_t err = mHandleToObject.insertAt(e, N, handle+1-N); if (err < NO_ERROR) return NULL; } return &mHandleToObject.editItemAt(handle); } sp ProcessState::getStrongProxyForHandle(int32_t handle) { sp result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { // We need to create a new BpBinder if there isn't currently one, OR we // are unable to acquire a weak reference on this current one. See comment // in getWeakProxyForHandle() for more info about this. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { if (handle == 0) { // Special case for context manager... // The context manager is the only object for which we create // a BpBinder proxy without already holding a reference. // Perform a dummy transaction to ensure the context manager // is registered before we create the first local reference // to it (which will occur when creating the BpBinder). // If a local reference is created for the BpBinder when the // context manager is not present, the driver will fail to // provide a reference to the context manager, but the // driver API does not return status. // // Note that this is not race-free if the context manager // dies while this code runs. // // TODO: add a driver API to wait for context manager, or // stop special casing handle 0 for context manager and add // a driver API to get a handle to the context manager with // proper reference counting. Parcel data; status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, NULL, 0); if (status == DEAD_OBJECT) return NULL; } b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { // This little bit of nastyness is to allow us to add a primary // reference to the remote proxy when this team doesn't have one // but another team is sending the handle to us. result.force_set(b); e->refs->decWeak(this); } } return result; } wp ProcessState::getWeakProxyForHandle(int32_t handle) { wp result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { // We need to create a new BpBinder if there isn't currently one, OR we // are unable to acquire a weak reference on this current one. The // attemptIncWeak() is safe because we know the BpBinder destructor will always // call expungeHandle(), which acquires the same lock we are holding now. // We need to do this because there is a race condition between someone // releasing a reference on this BpBinder, and a new reference on its handle // arriving from the driver. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); } else { result = b; e->refs->decWeak(this); } } return result; } void ProcessState::expungeHandle(int32_t handle, IBinder* binder) { AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); // This handle may have already been replaced with a new BpBinder // (if someone failed the AttemptIncWeak() above); we don't want // to overwrite it. if (e && e->binder == binder) e->binder = NULL; } String8 ProcessState::makeBinderThreadName() { int32_t s = android_atomic_add(1, &mThreadPoolSeq); pid_t pid = getpid(); String8 name; name.appendFormat("Binder:%d_%X", pid, s); return name; } void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); sp t = new PoolThread(isMain); t->run(name.string()); } } status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t result = NO_ERROR; if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) { mMaxThreads = maxThreads; } else { result = -errno; ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); } return result; } void ProcessState::giveThreadPoolName() { androidSetThreadName( makeBinderThreadName().string() ); } static int open_driver() { int fd = open("/dev/binder", O_RDWR | O_CLOEXEC); if (fd >= 0) { int vers = 0; status_t result = ioctl(fd, BINDER_VERSION, &vers); if (result == -1) { ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); fd = -1; } if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { ALOGE("Binder driver protocol does not match user space protocol!"); close(fd); fd = -1; } size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } } else { ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno)); } return fd; } ProcessState::ProcessState() : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mStarvationStartTimeMs(0) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; } } LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); } ProcessState::~ProcessState() { } }; // namespace android libs/binder/Static.cpp0100644 0000000 0000000 00000004663 13077405420 013747 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ // All static variables go here, to control initialization and // destruction order in the library. #include #include #include #include namespace android { // ------------ Text output streams Vector gTextBuffers; class LogTextOutput : public BufferedTextOutput { public: LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } virtual ~LogTextOutput() { }; protected: virtual status_t writeLines(const struct iovec& vec, size_t N) { //android_writevLog(&vec, N); <-- this is now a no-op if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N); ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base); return NO_ERROR; } }; class FdTextOutput : public BufferedTextOutput { public: FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } virtual ~FdTextOutput() { }; protected: virtual status_t writeLines(const struct iovec& vec, size_t N) { writev(mFD, &vec, N); return NO_ERROR; } private: int mFD; }; static LogTextOutput gLogTextOutput; static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); static FdTextOutput gStderrTextOutput(STDERR_FILENO); TextOutput& alog(gLogTextOutput); TextOutput& aout(gStdoutTextOutput); TextOutput& aerr(gStderrTextOutput); // ------------ ProcessState.cpp Mutex gProcessMutex; sp gProcess; class LibBinderIPCtStatics { public: LibBinderIPCtStatics() { } ~LibBinderIPCtStatics() { IPCThreadState::shutdown(); } }; static LibBinderIPCtStatics gIPCStatics; // ------------ IServiceManager.cpp Mutex gDefaultServiceManagerLock; sp gDefaultServiceManager; sp gPermissionController; } // namespace android libs/binder/Status.cpp0100644 0000000 0000000 00000011351 13077405420 013773 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace android { namespace binder { Status Status::ok() { return Status(); } Status Status::fromExceptionCode(int32_t exceptionCode) { return Status(exceptionCode, OK); } Status Status::fromExceptionCode(int32_t exceptionCode, const String8& message) { return Status(exceptionCode, OK, message); } Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode) { return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode); } Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode, const String8& message) { return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode, message); } Status Status::fromStatusT(status_t status) { Status ret; ret.setFromStatusT(status); return ret; } Status::Status(int32_t exceptionCode, int32_t errorCode) : mException(exceptionCode), mErrorCode(errorCode) {} Status::Status(int32_t exceptionCode, int32_t errorCode, const String8& message) : mException(exceptionCode), mErrorCode(errorCode), mMessage(message) {} status_t Status::readFromParcel(const Parcel& parcel) { status_t status = parcel.readInt32(&mException); if (status != OK) { setFromStatusT(status); return status; } // Skip over fat response headers. Not used (or propagated) in native code. if (mException == EX_HAS_REPLY_HEADER) { // Note that the header size includes the 4 byte size field. const int32_t header_start = parcel.dataPosition(); int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } parcel.setDataPosition(header_start + header_size); // And fat response headers are currently only used when there are no // exceptions, so act like there was no error. mException = EX_NONE; } if (mException == EX_NONE) { return status; } // The remote threw an exception. Get the message back. String16 message; status = parcel.readString16(&message); if (status != OK) { setFromStatusT(status); return status; } mMessage = String8(message); if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } if (status != OK) { setFromStatusT(status); return status; } return status; } status_t Status::writeToParcel(Parcel* parcel) const { // Something really bad has happened, and we're not going to even // try returning rich error data. if (mException == EX_TRANSACTION_FAILED) { return mErrorCode; } status_t status = parcel->writeInt32(mException); if (status != OK) { return status; } if (mException == EX_NONE) { // We have no more information to write. return status; } status = parcel->writeString16(String16(mMessage)); if (mException != EX_SERVICE_SPECIFIC) { // We have no more information to write. return status; } status = parcel->writeInt32(mErrorCode); return status; } void Status::setException(int32_t ex, const String8& message) { mException = ex; mErrorCode = NO_ERROR; // an exception, not a transaction failure. mMessage.setTo(message); } void Status::setServiceSpecificError(int32_t errorCode, const String8& message) { setException(EX_SERVICE_SPECIFIC, message); mErrorCode = errorCode; } void Status::setFromStatusT(status_t status) { mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED; mErrorCode = status; mMessage.clear(); } String8 Status::toString8() const { String8 ret; if (mException == EX_NONE) { ret.append("No error"); } else { ret.appendFormat("Status(%d): '", mException); if (mException == EX_SERVICE_SPECIFIC || mException == EX_TRANSACTION_FAILED) { ret.appendFormat("%d: ", mErrorCode); } ret.append(String8(mMessage)); ret.append("'"); } return ret; } } // namespace binder } // namespace android libs/binder/TextOutput.cpp0100644 0000000 0000000 00000007364 13077405420 014666 0ustar000000000 0000000 /* * Copyright (C) 2005 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 #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- TextOutput::TextOutput() { } TextOutput::~TextOutput() { } // --------------------------------------------------------------------------- TextOutput& operator<<(TextOutput& to, bool val) { if (val) to.print("true", 4); else to.print("false", 5); return to; } TextOutput& operator<<(TextOutput& to, int val) { char buf[16]; sprintf(buf, "%d", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, long val) { char buf[16]; sprintf(buf, "%ld", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, unsigned int val) { char buf[16]; sprintf(buf, "%u", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, unsigned long val) { char buf[16]; sprintf(buf, "%lu", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, long long val) { char buf[32]; sprintf(buf, "%Ld", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, unsigned long long val) { char buf[32]; sprintf(buf, "%Lu", val); to.print(buf, strlen(buf)); return to; } static TextOutput& print_float(TextOutput& to, double value) { char buf[64]; sprintf(buf, "%g", value); if( !strchr(buf, '.') && !strchr(buf, 'e') && !strchr(buf, 'E') ) { strncat(buf, ".0", sizeof(buf)-1); } to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, float val) { return print_float(to,val); } TextOutput& operator<<(TextOutput& to, double val) { return print_float(to,val); } TextOutput& operator<<(TextOutput& to, const void* val) { char buf[32]; snprintf(buf, sizeof(buf), "%p", val); to.print(buf, strlen(buf)); return to; } TextOutput& operator<<(TextOutput& to, const String8& val) { to << val.string(); return to; } TextOutput& operator<<(TextOutput& to, const String16& val) { to << String8(val).string(); return to; } static void textOutputPrinter(void* cookie, const char* txt) { ((TextOutput*)cookie)->print(txt, strlen(txt)); } TextOutput& operator<<(TextOutput& to, const TypeCode& val) { printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to); return to; } HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine) : mBuffer(buf) , mSize(size) , mBytesPerLine(bytesPerLine) , mSingleLineCutoff(16) , mAlignment(4) , mCArrayStyle(false) { if (bytesPerLine >= 16) mAlignment = 4; else if (bytesPerLine >= 8) mAlignment = 2; else mAlignment = 1; } TextOutput& operator<<(TextOutput& to, const HexDump& val) { printHexData(0, val.buffer(), val.size(), val.bytesPerLine(), val.singleLineCutoff(), val.alignment(), val.carrayStyle(), textOutputPrinter, (void*)&to); return to; } }; // namespace android libs/binder/tests/0040755 0000000 0000000 00000000000 13077405420 013150 5ustar000000000 0000000 libs/binder/tests/Android.mk0100644 0000000 0000000 00000002521 13077405420 015056 0ustar000000000 0000000 # # Copyright (C) 2014 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) ifneq ($(TARGET_USES_64_BIT_BINDER),true) ifneq ($(TARGET_IS_64_BIT),true) LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 endif endif LOCAL_MODULE := binderDriverInterfaceTest LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_MODULE := binderLibTest LOCAL_SRC_FILES := binderLibTest.cpp LOCAL_SHARED_LIBRARIES := libbinder libutils include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_MODULE := binderThroughputTest LOCAL_SRC_FILES := binderThroughputTest.cpp LOCAL_SHARED_LIBRARIES := libbinder libutils LOCAL_CLANG := true LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3 include $(BUILD_NATIVE_TEST) libs/binder/tests/binderDriverInterfaceTest.cpp0100644 0000000 0000000 00000025414 13077405420 020757 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #define BINDER_DEV_NAME "/dev/binder" testing::Environment* binder_env; class BinderDriverInterfaceTestEnv : public ::testing::Environment { virtual void SetUp() { int ret; uint32_t max_threads = 0; m_binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC); ASSERT_GE(m_binderFd, 0); m_buffer = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0); ASSERT_NE(m_buffer, (void *)NULL); ret = ioctl(m_binderFd, BINDER_SET_MAX_THREADS, &max_threads); EXPECT_EQ(0, ret); EnterLooper(); } virtual void TearDown() { close(m_binderFd); } private: int m_binderFd; void *m_buffer; public: int getBinderFd(void) { return m_binderFd; } void EnterLooper(void) { int ret; const uint32_t bc[] = { BC_ENTER_LOOPER, }; struct binder_write_read bwr = binder_write_read(); bwr.write_buffer = (uintptr_t)bc; bwr.write_size = sizeof(bc); ret = ioctl(m_binderFd, BINDER_WRITE_READ, &bwr); EXPECT_EQ(0, ret); if (ret < 0) { EXPECT_EQ(0, errno); } EXPECT_EQ(sizeof(bc), bwr.write_consumed); } }; class BinderDriverInterfaceTest : public ::testing::Test { public: virtual void SetUp() { m_binderFd = static_cast(binder_env)->getBinderFd(); } virtual void TearDown() { } protected: void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) { int ret; ret = ioctl(m_binderFd, cmd, arg); EXPECT_EQ(expect_ret, ret); if (ret < 0) { if (errno != accept_errno) EXPECT_EQ(expect_errno, errno); } } void binderTestIoctlErr2(int cmd, void *arg, int expect_errno, int accept_errno) { binderTestIoctlRetErr2(cmd, arg, -1, expect_errno, accept_errno); } void binderTestIoctlErr1(int cmd, void *arg, int expect_errno) { binderTestIoctlErr2(cmd, arg, expect_errno, expect_errno); } void binderTestIoctl(int cmd, void *arg) { binderTestIoctlRetErr2(cmd, arg, 0, 0, 0); } void binderTestIoctlUnimplemented(int cmd, void *arg) { int ret; ret = ioctl(m_binderFd, cmd, arg); if (ret < 0) { /* Not currently implmented. Allow ret == -1, errno == EINVAL */ EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); } } void binderTestReadEmpty(void) { size_t i; uint32_t br[32]; struct binder_write_read bwr = binder_write_read(); SCOPED_TRACE("TestReadEmpty"); bwr.read_buffer = (uintptr_t)br; bwr.read_size = sizeof(br); binderTestIoctlErr1(BINDER_WRITE_READ, &bwr, EAGAIN); EXPECT_EQ(0u, bwr.read_consumed); for (i = 0; i * sizeof(uint32_t) < bwr.read_consumed; i++) { SCOPED_TRACE(testing::Message() << "i = " << i); EXPECT_EQ(BR_NOOP, br[i]); } } void binderWaitForReadData(int timeout_ms) { int ret; pollfd pfd = pollfd(); pfd.fd = m_binderFd; pfd.events = POLLIN; ret = poll(&pfd, 1, timeout_ms); EXPECT_EQ(1, ret); } private: int m_binderFd; }; TEST_F(BinderDriverInterfaceTest, Version) { struct binder_version version; binderTestIoctl(BINDER_VERSION, &version); ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version); } TEST_F(BinderDriverInterfaceTest, WriteReadNull) { binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT); } TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) { binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, NULL, EFAULT, EINVAL); } TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) { binderTestIoctlErr2(BINDER_SET_MAX_THREADS, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ } TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) { binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, NULL, EFAULT, EINVAL); } TEST_F(BinderDriverInterfaceTest, VersionNull) { binderTestIoctlErr2(BINDER_VERSION, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ } TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNoTest) { int64_t idle_timeout = 100000; binderTestIoctlUnimplemented(BINDER_SET_IDLE_TIMEOUT, &idle_timeout); } TEST_F(BinderDriverInterfaceTest, SetMaxThreads) { uint32_t max_threads = 0; binderTestIoctl(BINDER_SET_MAX_THREADS, &max_threads); } TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNoTest) { int idle_priority = 0; binderTestIoctlUnimplemented(BINDER_SET_IDLE_PRIORITY, &idle_priority); } TEST_F(BinderDriverInterfaceTest, SetContextMgrBusy) { int32_t dummy = 0; binderTestIoctlErr1(BINDER_SET_CONTEXT_MGR, &dummy, EBUSY); } TEST_F(BinderDriverInterfaceTest, ThreadExit) { int32_t dummy = 0; binderTestIoctl(BINDER_THREAD_EXIT, &dummy); static_cast(binder_env)->EnterLooper(); } TEST_F(BinderDriverInterfaceTest, WriteReadEmpty) { struct binder_write_read bwr = binder_write_read(); binderTestIoctl(BINDER_WRITE_READ, &bwr); } TEST_F(BinderDriverInterfaceTest, Read) { binderTestReadEmpty(); } TEST_F(BinderDriverInterfaceTest, IncRefsAcquireReleaseDecRefs) { const uint32_t bc[] = { BC_INCREFS, 0, BC_ACQUIRE, 0, BC_RELEASE, 0, BC_DECREFS, 0, }; struct binder_write_read bwr = binder_write_read(); bwr.write_buffer = (uintptr_t)bc; bwr.write_size = sizeof(bc); binderTestIoctl(BINDER_WRITE_READ, &bwr); EXPECT_EQ(sizeof(bc), bwr.write_consumed); binderTestReadEmpty(); } TEST_F(BinderDriverInterfaceTest, Transaction) { binder_uintptr_t cookie = 1234; struct { uint32_t cmd1; struct binder_transaction_data arg1; } __attribute__((packed)) bc1 = { .cmd1 = BC_TRANSACTION, .arg1 = { .target = { 0 }, .cookie = 0, .code = android::IBinder::PING_TRANSACTION, .flags = 0, .sender_pid = 0, .sender_euid = 0, .data_size = 0, .offsets_size = 0, .data = {0, 0}, }, }; struct { uint32_t cmd0; uint32_t cmd1; uint32_t cmd2; binder_transaction_data arg2; uint32_t pad[16]; } __attribute__((packed)) br; struct binder_write_read bwr = binder_write_read(); bwr.write_buffer = (uintptr_t)&bc1; bwr.write_size = sizeof(bc1); bwr.read_buffer = (uintptr_t)&br; bwr.read_size = sizeof(br); { SCOPED_TRACE("1st WriteRead"); binderTestIoctl(BINDER_WRITE_READ, &bwr); } EXPECT_EQ(sizeof(bc1), bwr.write_consumed); if (bwr.read_consumed < offsetof(typeof(br), pad)) { SCOPED_TRACE("2nd WriteRead"); binderWaitForReadData(10000); binderTestIoctl(BINDER_WRITE_READ, &bwr); } EXPECT_EQ(offsetof(typeof(br), pad), bwr.read_consumed); if (bwr.read_consumed > offsetof(typeof(br), cmd0)) EXPECT_EQ(BR_NOOP, br.cmd0); if (bwr.read_consumed > offsetof(typeof(br), cmd1)) EXPECT_EQ(BR_TRANSACTION_COMPLETE, br.cmd1); if (bwr.read_consumed > offsetof(typeof(br), cmd2)) EXPECT_EQ(BR_REPLY, br.cmd2); if (bwr.read_consumed >= offsetof(typeof(br), pad)) { EXPECT_EQ(0u, br.arg2.target.ptr); EXPECT_EQ(0u, br.arg2.cookie); EXPECT_EQ(0u, br.arg2.code); EXPECT_EQ(0u, br.arg2.flags); EXPECT_EQ(0u, br.arg2.data_size); EXPECT_EQ(0u, br.arg2.offsets_size); SCOPED_TRACE("3rd WriteRead"); binderTestReadEmpty(); struct { uint32_t cmd1; binder_uintptr_t arg1; } __attribute__((packed)) bc2 = { .cmd1 = BC_FREE_BUFFER, .arg1 = br.arg2.data.ptr.buffer, }; bwr.write_buffer = (uintptr_t)&bc2; bwr.write_size = sizeof(bc2); bwr.write_consumed = 0; bwr.read_size = 0; binderTestIoctl(BINDER_WRITE_READ, &bwr); EXPECT_EQ(sizeof(bc2), bwr.write_consumed); } binderTestReadEmpty(); } TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { binder_uintptr_t cookie = 1234; struct { uint32_t cmd0; uint32_t arg0; uint32_t cmd1; struct binder_handle_cookie arg1; uint32_t cmd2; struct binder_handle_cookie arg2; uint32_t cmd3; uint32_t arg3; } __attribute__((packed)) bc = { .cmd0 = BC_INCREFS, .arg0 = 0, .cmd1 = BC_REQUEST_DEATH_NOTIFICATION, .arg1 = { .handle = 0, .cookie = cookie, }, .cmd2 = BC_CLEAR_DEATH_NOTIFICATION, .arg2 = { .handle = 0, .cookie = cookie, }, .cmd3 = BC_DECREFS, .arg3 = 0, }; struct { uint32_t cmd0; uint32_t cmd1; binder_uintptr_t arg1; uint32_t pad[16]; } __attribute__((packed)) br; struct binder_write_read bwr = binder_write_read(); bwr.write_buffer = (uintptr_t)&bc; bwr.write_size = sizeof(bc); bwr.read_buffer = (uintptr_t)&br; bwr.read_size = sizeof(br); binderTestIoctl(BINDER_WRITE_READ, &bwr); EXPECT_EQ(sizeof(bc), bwr.write_consumed); EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed); EXPECT_EQ(BR_NOOP, br.cmd0); EXPECT_EQ(BR_CLEAR_DEATH_NOTIFICATION_DONE, br.cmd1); EXPECT_EQ(cookie, br.arg1); binderTestReadEmpty(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv()); return RUN_ALL_TESTS(); } libs/binder/tests/binderLibTest.cpp0100644 0000000 0000000 00000071726 13077405420 016420 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) using namespace android; static testing::Environment* binder_env; static char *binderservername; static char binderserverarg[] = "--binderserver"; static String16 binderLibTestServiceName = String16("test.binderLib"); enum BinderLibTestTranscationCode { BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, BINDER_LIB_TEST_REGISTER_SERVER, BINDER_LIB_TEST_ADD_SERVER, BINDER_LIB_TEST_CALL_BACK, BINDER_LIB_TEST_NOP_CALL_BACK, BINDER_LIB_TEST_GET_ID_TRANSACTION, BINDER_LIB_TEST_INDIRECT_TRANSACTION, BINDER_LIB_TEST_SET_ERROR_TRANSACTION, BINDER_LIB_TEST_GET_STATUS_TRANSACTION, BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, BINDER_LIB_TEST_EXIT_TRANSACTION, BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION, BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, }; pid_t start_server_process(int arg2) { int ret; pid_t pid; status_t status; int pipefd[2]; char stri[16]; char strpipefd1[16]; char *childargv[] = { binderservername, binderserverarg, stri, strpipefd1, NULL }; ret = pipe(pipefd); if (ret < 0) return ret; snprintf(stri, sizeof(stri), "%d", arg2); snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]); pid = fork(); if (pid == -1) return pid; if (pid == 0) { close(pipefd[0]); execv(binderservername, childargv); status = -errno; write(pipefd[1], &status, sizeof(status)); fprintf(stderr, "execv failed, %s\n", strerror(errno)); _exit(EXIT_FAILURE); } close(pipefd[1]); ret = read(pipefd[0], &status, sizeof(status)); //printf("pipe read returned %d, status %d\n", ret, status); close(pipefd[0]); if (ret == sizeof(status)) { ret = status; } else { kill(pid, SIGKILL); if (ret >= 0) { ret = NO_INIT; } } if (ret < 0) { wait(NULL); return ret; } return pid; } class BinderLibTestEnv : public ::testing::Environment { public: BinderLibTestEnv() {} sp getServer(void) { return m_server; } private: virtual void SetUp() { m_serverpid = start_server_process(0); //printf("m_serverpid %d\n", m_serverpid); ASSERT_GT(m_serverpid, 0); sp sm = defaultServiceManager(); //printf("%s: pid %d, get service\n", __func__, m_pid); m_server = sm->getService(binderLibTestServiceName); ASSERT_TRUE(m_server != NULL); //printf("%s: pid %d, get service done\n", __func__, m_pid); } virtual void TearDown() { status_t ret; Parcel data, reply; int exitStatus; pid_t pid; //printf("%s: pid %d\n", __func__, m_pid); if (m_server != NULL) { ret = m_server->transact(BINDER_LIB_TEST_GET_STATUS_TRANSACTION, data, &reply); EXPECT_EQ(0, ret); ret = m_server->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); EXPECT_EQ(0, ret); } if (m_serverpid > 0) { //printf("wait for %d\n", m_pids[i]); pid = wait(&exitStatus); EXPECT_EQ(m_serverpid, pid); EXPECT_TRUE(WIFEXITED(exitStatus)); EXPECT_EQ(0, WEXITSTATUS(exitStatus)); } } pid_t m_serverpid; sp m_server; }; class BinderLibTest : public ::testing::Test { public: virtual void SetUp() { m_server = static_cast(binder_env)->getServer(); } virtual void TearDown() { } protected: sp addServer(int32_t *idPtr = NULL) { int ret; int32_t id; Parcel data, reply; sp binder; ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply); EXPECT_EQ(NO_ERROR, ret); EXPECT_FALSE(binder != NULL); binder = reply.readStrongBinder(); EXPECT_TRUE(binder != NULL); ret = reply.readInt32(&id); EXPECT_EQ(NO_ERROR, ret); if (idPtr) *idPtr = id; return binder; } void waitForReadData(int fd, int timeout_ms) { int ret; pollfd pfd = pollfd(); pfd.fd = fd; pfd.events = POLLIN; ret = poll(&pfd, 1, timeout_ms); EXPECT_EQ(1, ret); } sp m_server; }; class BinderLibTestBundle : public Parcel { public: BinderLibTestBundle(void) {} BinderLibTestBundle(const Parcel *source) : m_isValid(false) { int32_t mark; int32_t bundleLen; size_t pos; if (source->readInt32(&mark)) return; if (mark != MARK_START) return; if (source->readInt32(&bundleLen)) return; pos = source->dataPosition(); if (Parcel::appendFrom(source, pos, bundleLen)) return; source->setDataPosition(pos + bundleLen); if (source->readInt32(&mark)) return; if (mark != MARK_END) return; m_isValid = true; setDataPosition(0); } void appendTo(Parcel *dest) { dest->writeInt32(MARK_START); dest->writeInt32(dataSize()); dest->appendFrom(this, 0, dataSize()); dest->writeInt32(MARK_END); }; bool isValid(void) { return m_isValid; } private: enum { MARK_START = B_PACK_CHARS('B','T','B','S'), MARK_END = B_PACK_CHARS('B','T','B','E'), }; bool m_isValid; }; class BinderLibTestEvent { public: BinderLibTestEvent(void) : m_eventTriggered(false) { pthread_mutex_init(&m_waitMutex, NULL); pthread_cond_init(&m_waitCond, NULL); } int waitEvent(int timeout_s) { int ret; pthread_mutex_lock(&m_waitMutex); if (!m_eventTriggered) { #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) pthread_cond_timeout_np(&m_waitCond, &m_waitMutex, timeout_s * 1000); #else struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += timeout_s; pthread_cond_timedwait(&m_waitCond, &m_waitMutex, &ts); #endif } ret = m_eventTriggered ? NO_ERROR : TIMED_OUT; pthread_mutex_unlock(&m_waitMutex); return ret; } protected: void triggerEvent(void) { pthread_mutex_lock(&m_waitMutex); pthread_cond_signal(&m_waitCond); m_eventTriggered = true; pthread_mutex_unlock(&m_waitMutex); }; private: pthread_mutex_t m_waitMutex; pthread_cond_t m_waitCond; bool m_eventTriggered; }; class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent { public: BinderLibTestCallBack() : m_result(NOT_ENOUGH_DATA) { } status_t getResult(void) { return m_result; } private: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) { (void)reply; (void)flags; switch(code) { case BINDER_LIB_TEST_CALL_BACK: m_result = data.readInt32(); triggerEvent(); return NO_ERROR; default: return UNKNOWN_TRANSACTION; } } status_t m_result; }; class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent { private: virtual void binderDied(const wp& who) { (void)who; triggerEvent(); }; }; TEST_F(BinderLibTest, NopTransaction) { status_t ret; Parcel data, reply; ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply); EXPECT_EQ(NO_ERROR, ret); } TEST_F(BinderLibTest, SetError) { int32_t testValue[] = { 0, -123, 123 }; for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) { status_t ret; Parcel data, reply; data.writeInt32(testValue[i]); ret = m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply); EXPECT_EQ(testValue[i], ret); } } TEST_F(BinderLibTest, GetId) { status_t ret; int32_t id; Parcel data, reply; ret = m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply); EXPECT_EQ(NO_ERROR, ret); ret = reply.readInt32(&id); EXPECT_EQ(NO_ERROR, ret); EXPECT_EQ(0, id); } TEST_F(BinderLibTest, PtrSize) { status_t ret; int32_t ptrsize; Parcel data, reply; sp server = addServer(); ASSERT_TRUE(server != NULL); ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply); EXPECT_EQ(NO_ERROR, ret); ret = reply.readInt32(&ptrsize); EXPECT_EQ(NO_ERROR, ret); RecordProperty("TestPtrSize", sizeof(void *)); RecordProperty("ServerPtrSize", sizeof(void *)); } TEST_F(BinderLibTest, IndirectGetId2) { status_t ret; int32_t id; int32_t count; Parcel data, reply; int32_t serverId[3]; data.writeInt32(ARRAY_SIZE(serverId)); for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { sp server; BinderLibTestBundle datai; server = addServer(&serverId[i]); ASSERT_TRUE(server != NULL); data.writeStrongBinder(server); data.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); datai.appendTo(&data); } ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); ASSERT_EQ(NO_ERROR, ret); ret = reply.readInt32(&id); ASSERT_EQ(NO_ERROR, ret); EXPECT_EQ(0, id); ret = reply.readInt32(&count); ASSERT_EQ(NO_ERROR, ret); EXPECT_EQ(ARRAY_SIZE(serverId), count); for (size_t i = 0; i < (size_t)count; i++) { BinderLibTestBundle replyi(&reply); EXPECT_TRUE(replyi.isValid()); ret = replyi.readInt32(&id); EXPECT_EQ(NO_ERROR, ret); EXPECT_EQ(serverId[i], id); EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); } EXPECT_EQ(reply.dataSize(), reply.dataPosition()); } TEST_F(BinderLibTest, IndirectGetId3) { status_t ret; int32_t id; int32_t count; Parcel data, reply; int32_t serverId[3]; data.writeInt32(ARRAY_SIZE(serverId)); for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { sp server; BinderLibTestBundle datai; BinderLibTestBundle datai2; server = addServer(&serverId[i]); ASSERT_TRUE(server != NULL); data.writeStrongBinder(server); data.writeInt32(BINDER_LIB_TEST_INDIRECT_TRANSACTION); datai.writeInt32(1); datai.writeStrongBinder(m_server); datai.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); datai2.appendTo(&datai); datai.appendTo(&data); } ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); ASSERT_EQ(NO_ERROR, ret); ret = reply.readInt32(&id); ASSERT_EQ(NO_ERROR, ret); EXPECT_EQ(0, id); ret = reply.readInt32(&count); ASSERT_EQ(NO_ERROR, ret); EXPECT_EQ(ARRAY_SIZE(serverId), count); for (size_t i = 0; i < (size_t)count; i++) { int32_t counti; BinderLibTestBundle replyi(&reply); EXPECT_TRUE(replyi.isValid()); ret = replyi.readInt32(&id); EXPECT_EQ(NO_ERROR, ret); EXPECT_EQ(serverId[i], id); ret = replyi.readInt32(&counti); ASSERT_EQ(NO_ERROR, ret); EXPECT_EQ(1, counti); BinderLibTestBundle replyi2(&replyi); EXPECT_TRUE(replyi2.isValid()); ret = replyi2.readInt32(&id); EXPECT_EQ(NO_ERROR, ret); EXPECT_EQ(0, id); EXPECT_EQ(replyi2.dataSize(), replyi2.dataPosition()); EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); } EXPECT_EQ(reply.dataSize(), reply.dataPosition()); } TEST_F(BinderLibTest, CallBack) { status_t ret; Parcel data, reply; sp callBack = new BinderLibTestCallBack(); data.writeStrongBinder(callBack); ret = m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY); EXPECT_EQ(NO_ERROR, ret); ret = callBack->waitEvent(5); EXPECT_EQ(NO_ERROR, ret); ret = callBack->getResult(); EXPECT_EQ(NO_ERROR, ret); } TEST_F(BinderLibTest, AddServer) { sp server = addServer(); ASSERT_TRUE(server != NULL); } TEST_F(BinderLibTest, DeathNotificationNoRefs) { status_t ret; sp testDeathRecipient = new TestDeathRecipient(); { sp binder = addServer(); ASSERT_TRUE(binder != NULL); ret = binder->linkToDeath(testDeathRecipient); EXPECT_EQ(NO_ERROR, ret); } IPCThreadState::self()->flushCommands(); ret = testDeathRecipient->waitEvent(5); EXPECT_EQ(NO_ERROR, ret); #if 0 /* Is there an unlink api that does not require a strong reference? */ ret = binder->unlinkToDeath(testDeathRecipient); EXPECT_EQ(NO_ERROR, ret); #endif } TEST_F(BinderLibTest, DeathNotificationWeakRef) { status_t ret; wp wbinder; sp testDeathRecipient = new TestDeathRecipient(); { sp binder = addServer(); ASSERT_TRUE(binder != NULL); ret = binder->linkToDeath(testDeathRecipient); EXPECT_EQ(NO_ERROR, ret); wbinder = binder; } IPCThreadState::self()->flushCommands(); ret = testDeathRecipient->waitEvent(5); EXPECT_EQ(NO_ERROR, ret); #if 0 /* Is there an unlink api that does not require a strong reference? */ ret = binder->unlinkToDeath(testDeathRecipient); EXPECT_EQ(NO_ERROR, ret); #endif } TEST_F(BinderLibTest, DeathNotificationStrongRef) { status_t ret; sp sbinder; sp testDeathRecipient = new TestDeathRecipient(); { sp binder = addServer(); ASSERT_TRUE(binder != NULL); ret = binder->linkToDeath(testDeathRecipient); EXPECT_EQ(NO_ERROR, ret); sbinder = binder; } { Parcel data, reply; ret = sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); EXPECT_EQ(0, ret); } IPCThreadState::self()->flushCommands(); ret = testDeathRecipient->waitEvent(5); EXPECT_EQ(NO_ERROR, ret); ret = sbinder->unlinkToDeath(testDeathRecipient); EXPECT_EQ(DEAD_OBJECT, ret); } TEST_F(BinderLibTest, DeathNotificationMultiple) { status_t ret; const int clientcount = 2; sp target; sp linkedclient[clientcount]; sp callBack[clientcount]; sp passiveclient[clientcount]; target = addServer(); ASSERT_TRUE(target != NULL); for (int i = 0; i < clientcount; i++) { { Parcel data, reply; linkedclient[i] = addServer(); ASSERT_TRUE(linkedclient[i] != NULL); callBack[i] = new BinderLibTestCallBack(); data.writeStrongBinder(target); data.writeStrongBinder(callBack[i]); ret = linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY); EXPECT_EQ(NO_ERROR, ret); } { Parcel data, reply; passiveclient[i] = addServer(); ASSERT_TRUE(passiveclient[i] != NULL); data.writeStrongBinder(target); ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY); EXPECT_EQ(NO_ERROR, ret); } } { Parcel data, reply; ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); EXPECT_EQ(0, ret); } for (int i = 0; i < clientcount; i++) { ret = callBack[i]->waitEvent(5); EXPECT_EQ(NO_ERROR, ret); ret = callBack[i]->getResult(); EXPECT_EQ(NO_ERROR, ret); } } TEST_F(BinderLibTest, PassFile) { int ret; int pipefd[2]; uint8_t buf[1] = { 0 }; uint8_t write_value = 123; ret = pipe2(pipefd, O_NONBLOCK); ASSERT_EQ(0, ret); { Parcel data, reply; uint8_t writebuf[1] = { write_value }; ret = data.writeFileDescriptor(pipefd[1], true); EXPECT_EQ(NO_ERROR, ret); ret = data.writeInt32(sizeof(writebuf)); EXPECT_EQ(NO_ERROR, ret); ret = data.write(writebuf, sizeof(writebuf)); EXPECT_EQ(NO_ERROR, ret); ret = m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply); EXPECT_EQ(NO_ERROR, ret); } ret = read(pipefd[0], buf, sizeof(buf)); EXPECT_EQ(sizeof(buf), ret); EXPECT_EQ(write_value, buf[0]); waitForReadData(pipefd[0], 5000); /* wait for other proccess to close pipe */ ret = read(pipefd[0], buf, sizeof(buf)); EXPECT_EQ(0, ret); close(pipefd[0]); } TEST_F(BinderLibTest, PromoteLocal) { sp strong = new BBinder(); wp weak = strong; sp strong_from_weak = weak.promote(); EXPECT_TRUE(strong != NULL); EXPECT_EQ(strong, strong_from_weak); strong = NULL; strong_from_weak = NULL; strong_from_weak = weak.promote(); EXPECT_TRUE(strong_from_weak == NULL); } TEST_F(BinderLibTest, PromoteRemote) { int ret; Parcel data, reply; sp strong = new BBinder(); sp server = addServer(); ASSERT_TRUE(server != NULL); ASSERT_TRUE(strong != NULL); ret = data.writeWeakBinder(strong); EXPECT_EQ(NO_ERROR, ret); ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply); EXPECT_GE(ret, 0); } class BinderLibTestService : public BBinder { public: BinderLibTestService(int32_t id) : m_id(id) , m_nextServerId(id + 1) , m_serverStartRequested(false) { pthread_mutex_init(&m_serverWaitMutex, NULL); pthread_cond_init(&m_serverWaitCond, NULL); } ~BinderLibTestService() { exit(EXIT_SUCCESS); } virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) { //printf("%s: code %d\n", __func__, code); (void)flags; if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) { return PERMISSION_DENIED; } switch (code) { case BINDER_LIB_TEST_REGISTER_SERVER: { int32_t id; sp binder; id = data.readInt32(); binder = data.readStrongBinder(); if (binder == NULL) { return BAD_VALUE; } if (m_id != 0) return INVALID_OPERATION; pthread_mutex_lock(&m_serverWaitMutex); if (m_serverStartRequested) { m_serverStartRequested = false; m_serverStarted = binder; pthread_cond_signal(&m_serverWaitCond); } pthread_mutex_unlock(&m_serverWaitMutex); return NO_ERROR; } case BINDER_LIB_TEST_ADD_SERVER: { int ret; uint8_t buf[1] = { 0 }; int serverid; if (m_id != 0) { return INVALID_OPERATION; } pthread_mutex_lock(&m_serverWaitMutex); if (m_serverStartRequested) { ret = -EBUSY; } else { serverid = m_nextServerId++; m_serverStartRequested = true; pthread_mutex_unlock(&m_serverWaitMutex); ret = start_server_process(serverid); pthread_mutex_lock(&m_serverWaitMutex); } if (ret > 0) { if (m_serverStartRequested) { #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) ret = pthread_cond_timeout_np(&m_serverWaitCond, &m_serverWaitMutex, 5000); #else struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 5; ret = pthread_cond_timedwait(&m_serverWaitCond, &m_serverWaitMutex, &ts); #endif } if (m_serverStartRequested) { m_serverStartRequested = false; ret = -ETIMEDOUT; } else { reply->writeStrongBinder(m_serverStarted); reply->writeInt32(serverid); m_serverStarted = NULL; ret = NO_ERROR; } } else if (ret >= 0) { m_serverStartRequested = false; ret = UNKNOWN_ERROR; } pthread_mutex_unlock(&m_serverWaitMutex); return ret; } case BINDER_LIB_TEST_NOP_TRANSACTION: return NO_ERROR; case BINDER_LIB_TEST_NOP_CALL_BACK: { Parcel data2, reply2; sp binder; binder = data.readStrongBinder(); if (binder == NULL) { return BAD_VALUE; } reply2.writeInt32(NO_ERROR); binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); return NO_ERROR; } case BINDER_LIB_TEST_GET_ID_TRANSACTION: reply->writeInt32(m_id); return NO_ERROR; case BINDER_LIB_TEST_INDIRECT_TRANSACTION: { int32_t count; uint32_t indirect_code; sp binder; count = data.readInt32(); reply->writeInt32(m_id); reply->writeInt32(count); for (int i = 0; i < count; i++) { binder = data.readStrongBinder(); if (binder == NULL) { return BAD_VALUE; } indirect_code = data.readInt32(); BinderLibTestBundle data2(&data); if (!data2.isValid()) { return BAD_VALUE; } BinderLibTestBundle reply2; binder->transact(indirect_code, data2, &reply2); reply2.appendTo(reply); } return NO_ERROR; } case BINDER_LIB_TEST_SET_ERROR_TRANSACTION: reply->setError(data.readInt32()); return NO_ERROR; case BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION: reply->writeInt32(sizeof(void *)); return NO_ERROR; case BINDER_LIB_TEST_GET_STATUS_TRANSACTION: return NO_ERROR; case BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION: m_strongRef = data.readStrongBinder(); return NO_ERROR; case BINDER_LIB_TEST_LINK_DEATH_TRANSACTION: { int ret; Parcel data2, reply2; sp testDeathRecipient = new TestDeathRecipient(); sp target; sp callback; target = data.readStrongBinder(); if (target == NULL) { return BAD_VALUE; } callback = data.readStrongBinder(); if (callback == NULL) { return BAD_VALUE; } ret = target->linkToDeath(testDeathRecipient); if (ret == NO_ERROR) ret = testDeathRecipient->waitEvent(5); data2.writeInt32(ret); callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); return NO_ERROR; } case BINDER_LIB_TEST_WRITE_FILE_TRANSACTION: { int ret; int32_t size; const void *buf; int fd; fd = data.readFileDescriptor(); if (fd < 0) { return BAD_VALUE; } ret = data.readInt32(&size); if (ret != NO_ERROR) { return ret; } buf = data.readInplace(size); if (buf == NULL) { return BAD_VALUE; } ret = write(fd, buf, size); if (ret != size) return UNKNOWN_ERROR; return NO_ERROR; } case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: { int ret; wp weak; sp strong; Parcel data2, reply2; sp sm = defaultServiceManager(); sp server = sm->getService(binderLibTestServiceName); weak = data.readWeakBinder(); if (weak == NULL) { return BAD_VALUE; } strong = weak.promote(); ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2); if (ret != NO_ERROR) exit(EXIT_FAILURE); if (strong == NULL) { reply->setError(1); } return NO_ERROR; } case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION: alarm(10); return NO_ERROR; case BINDER_LIB_TEST_EXIT_TRANSACTION: while (wait(NULL) != -1 || errno != ECHILD) ; exit(EXIT_SUCCESS); default: return UNKNOWN_TRANSACTION; }; } private: int32_t m_id; int32_t m_nextServerId; pthread_mutex_t m_serverWaitMutex; pthread_cond_t m_serverWaitCond; bool m_serverStartRequested; sp m_serverStarted; sp m_strongRef; }; int run_server(int index, int readypipefd) { status_t ret; sp sm = defaultServiceManager(); { sp testService = new BinderLibTestService(index); if (index == 0) { ret = sm->addService(binderLibTestServiceName, testService); } else { sp server = sm->getService(binderLibTestServiceName); Parcel data, reply; data.writeInt32(index); data.writeStrongBinder(testService); ret = server->transact(BINDER_LIB_TEST_REGISTER_SERVER, data, &reply); } } write(readypipefd, &ret, sizeof(ret)); close(readypipefd); //printf("%s: ret %d\n", __func__, ret); if (ret) return 1; //printf("%s: joinThreadPool\n", __func__); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); //printf("%s: joinThreadPool returned\n", __func__); return 1; /* joinThreadPool should not return */ } int main(int argc, char **argv) { int ret; if (argc == 3 && !strcmp(argv[1], "--servername")) { binderservername = argv[2]; } else { binderservername = argv[0]; } if (argc == 4 && !strcmp(argv[1], binderserverarg)) { return run_server(atoi(argv[2]), atoi(argv[3])); } ::testing::InitGoogleTest(&argc, argv); binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv()); ProcessState::self()->startThreadPool(); return RUN_ALL_TESTS(); } libs/binder/tests/binderThroughputTest.cpp0100644 0000000 0000000 00000022012 13077405420 020043 0ustar000000000 0000000 #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace android; enum BinderWorkerServiceCode { BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION, }; #define ASSERT_TRUE(cond) \ do { \ if (!(cond)) {\ cerr << __func__ << ":" << __LINE__ << " condition:" << #cond << " failed\n" << endl; \ exit(EXIT_FAILURE); \ } \ } while (0) class BinderWorkerService : public BBinder { public: BinderWorkerService() {} ~BinderWorkerService() {} virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) { (void)flags; (void)data; (void)reply; switch (code) { case BINDER_NOP: return NO_ERROR; default: return UNKNOWN_TRANSACTION; }; } }; class Pipe { int m_readFd; int m_writeFd; Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {} Pipe(const Pipe &) = delete; Pipe& operator=(const Pipe &) = delete; Pipe& operator=(const Pipe &&) = delete; public: Pipe(Pipe&& rval) noexcept { m_readFd = rval.m_readFd; m_writeFd = rval.m_writeFd; rval.m_readFd = 0; rval.m_writeFd = 0; } ~Pipe() { if (m_readFd) close(m_readFd); if (m_writeFd) close(m_writeFd); } void signal() { bool val = true; int error = write(m_writeFd, &val, sizeof(val)); ASSERT_TRUE(error >= 0); }; void wait() { bool val = false; int error = read(m_readFd, &val, sizeof(val)); ASSERT_TRUE(error >= 0); } template void send(const T& v) { int error = write(m_writeFd, &v, sizeof(T)); ASSERT_TRUE(error >= 0); } template void recv(T& v) { int error = read(m_readFd, &v, sizeof(T)); ASSERT_TRUE(error >= 0); } static tuple createPipePair() { int a[2]; int b[2]; int error1 = pipe(a); int error2 = pipe(b); ASSERT_TRUE(error1 >= 0); ASSERT_TRUE(error2 >= 0); return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1])); } }; static const uint32_t num_buckets = 128; static const uint64_t max_time_bucket = 50ull * 1000000; static const uint64_t time_per_bucket = max_time_bucket / num_buckets; static constexpr float time_per_bucket_ms = time_per_bucket / 1.0E6; struct ProcResults { uint64_t m_best = max_time_bucket; uint64_t m_worst = 0; uint32_t m_buckets[num_buckets] = {0}; uint64_t m_transactions = 0; uint64_t m_total_time = 0; void add_time(uint64_t time) { m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1; m_best = min(time, m_best); m_worst = max(time, m_worst); m_transactions += 1; m_total_time += time; } static ProcResults combine(const ProcResults& a, const ProcResults& b) { ProcResults ret; for (int i = 0; i < num_buckets; i++) { ret.m_buckets[i] = a.m_buckets[i] + b.m_buckets[i]; } ret.m_worst = max(a.m_worst, b.m_worst); ret.m_best = min(a.m_best, b.m_best); ret.m_transactions = a.m_transactions + b.m_transactions; ret.m_total_time = a.m_total_time + b.m_total_time; return ret; } void dump() { double best = (double)m_best / 1.0E6; double worst = (double)m_worst / 1.0E6; double average = (double)m_total_time / m_transactions / 1.0E6; cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl; uint64_t cur_total = 0; for (int i = 0; i < num_buckets; i++) { float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms; if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) { cout << "50%: " << cur_time << " "; } if ((cur_total < 0.9f * m_transactions) && (cur_total + m_buckets[i] >= 0.9f * m_transactions)) { cout << "90%: " << cur_time << " "; } if ((cur_total < 0.95f * m_transactions) && (cur_total + m_buckets[i] >= 0.95f * m_transactions)) { cout << "95%: " << cur_time << " "; } if ((cur_total < 0.99f * m_transactions) && (cur_total + m_buckets[i] >= 0.99f * m_transactions)) { cout << "99%: " << cur_time << " "; } cur_total += m_buckets[i]; } cout << endl; } }; String16 generateServiceName(int num) { char num_str[32]; snprintf(num_str, sizeof(num_str), "%d", num); String16 serviceName = String16("binderWorker") + String16(num_str); return serviceName; } void worker_fx( int num, int worker_count, int iterations, Pipe p) { // Create BinderWorkerService and for go. ProcessState::self()->startThreadPool(); sp serviceMgr = defaultServiceManager(); sp service = new BinderWorkerService; serviceMgr->addService(generateServiceName(num), service); srand(num); p.signal(); p.wait(); // Get references to other binder services. cout << "Created BinderWorker" << num << endl; (void)worker_count; vector > workers; for (int i = 0; i < worker_count; i++) { if (num == i) continue; workers.push_back(serviceMgr->getService(generateServiceName(i))); } // Run the benchmark. ProcResults results; chrono::time_point start, end; for (int i = 0; i < iterations; i++) { int target = rand() % workers.size(); Parcel data, reply; start = chrono::high_resolution_clock::now(); status_t ret = workers[target]->transact(BINDER_NOP, data, &reply); end = chrono::high_resolution_clock::now(); uint64_t cur_time = uint64_t(chrono::duration_cast(end - start).count()); results.add_time(cur_time); if (ret != NO_ERROR) { cout << "thread " << num << " failed " << ret << "i : " << i << endl; exit(EXIT_FAILURE); } } // Signal completion to master and wait. p.signal(); p.wait(); // Send results to master and wait for go to exit. p.send(results); p.wait(); exit(EXIT_SUCCESS); } Pipe make_worker(int num, int iterations, int worker_count) { auto pipe_pair = Pipe::createPipePair(); pid_t pid = fork(); if (pid) { /* parent */ return move(get<0>(pipe_pair)); } else { /* child */ worker_fx(num, worker_count, iterations, move(get<1>(pipe_pair))); /* never get here */ return move(get<0>(pipe_pair)); } } void wait_all(vector& v) { for (int i = 0; i < v.size(); i++) { v[i].wait(); } } void signal_all(vector& v) { for (int i = 0; i < v.size(); i++) { v[i].signal(); } } int main(int argc, char *argv[]) { int workers = 2; int iterations = 10000; (void)argc; (void)argv; vector pipes; // Parse arguments. for (int i = 1; i < argc; i++) { if (string(argv[i]) == "-w") { workers = atoi(argv[i+1]); i++; continue; } if (string(argv[i]) == "-i") { iterations = atoi(argv[i+1]); i++; continue; } } // Create all the workers and wait for them to spawn. for (int i = 0; i < workers; i++) { pipes.push_back(make_worker(i, iterations, workers)); } wait_all(pipes); // Run the workers and wait for completion. chrono::time_point start, end; cout << "waiting for workers to complete" << endl; start = chrono::high_resolution_clock::now(); signal_all(pipes); wait_all(pipes); end = chrono::high_resolution_clock::now(); // Calculate overall throughput. double iterations_per_sec = double(iterations * workers) / (chrono::duration_cast(end - start).count() / 1.0E9); cout << "iterations per sec: " << iterations_per_sec << endl; // Collect all results from the workers. cout << "collecting results" << endl; signal_all(pipes); ProcResults tot_results; for (int i = 0; i < workers; i++) { ProcResults tmp_results; pipes[i].recv(tmp_results); tot_results = ProcResults::combine(tot_results, tmp_results); } tot_results.dump(); // Kill all the workers. cout << "killing workers" << endl; signal_all(pipes); for (int i = 0; i < workers; i++) { int status; wait(&status); if (status != 0) { cout << "nonzero child status" << status << endl; } } return 0; } libs/diskusage/0040755 0000000 0000000 00000000000 13077405420 012522 5ustar000000000 0000000 libs/diskusage/Android.mk0100644 0000000 0000000 00000001406 13077405420 014431 0ustar000000000 0000000 # Copyright (C) 2010 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libdiskusage LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := dirsize.c include $(BUILD_STATIC_LIBRARY)libs/diskusage/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 015642 0ustar000000000 0000000 libs/diskusage/dirsize.c0100644 0000000 0000000 00000003477 13077405420 014347 0ustar000000000 0000000 /* * * Copyright (C) 2008, 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 #include #include #include #include int64_t stat_size(struct stat *s) { return s->st_blocks * 512; } int64_t calculate_dir_size(int dfd) { int64_t size = 0; struct stat s; DIR *d; struct dirent *de; d = fdopendir(dfd); if (d == NULL) { close(dfd); return 0; } while ((de = readdir(d))) { const char *name = de->d_name; if (de->d_type == DT_DIR) { int subfd; /* always skip "." and ".." */ if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { size += stat_size(&s); } subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); if (subfd >= 0) { size += calculate_dir_size(subfd); } } else { if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { size += stat_size(&s); } } } closedir(d); return size; } libs/gui/0040755 0000000 0000000 00000000000 13077405420 011327 5ustar000000000 0000000 libs/gui/Android.mk0100644 0000000 0000000 00000005104 13077405420 013235 0ustar000000000 0000000 # Copyright 2010 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. LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror # The static constructors and destructors in this library have not been noted to # introduce significant overheads LOCAL_CPPFLAGS += -Wno-exit-time-destructors LOCAL_CPPFLAGS += -Wno-global-constructors # We only care about compiling as C++14 LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic # We don't need to enumerate every case in a switch as long as a default case # is present LOCAL_CPPFLAGS += -Wno-switch-enum # Allow calling variadic macros without a __VA_ARGS__ list LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments # Don't warn about struct padding LOCAL_CPPFLAGS += -Wno-padded LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0) LOCAL_SRC_FILES := \ IGraphicBufferConsumer.cpp \ IConsumerListener.cpp \ BitTube.cpp \ BufferItem.cpp \ BufferItemConsumer.cpp \ BufferQueue.cpp \ BufferQueueConsumer.cpp \ BufferQueueCore.cpp \ BufferQueueProducer.cpp \ BufferSlot.cpp \ ConsumerBase.cpp \ CpuConsumer.cpp \ DisplayEventReceiver.cpp \ GLConsumer.cpp \ GraphicBufferAlloc.cpp \ GuiConfig.cpp \ IDisplayEventConnection.cpp \ IGraphicBufferAlloc.cpp \ IGraphicBufferProducer.cpp \ IProducerListener.cpp \ ISensorEventConnection.cpp \ ISensorServer.cpp \ ISurfaceComposer.cpp \ ISurfaceComposerClient.cpp \ LayerState.cpp \ Sensor.cpp \ SensorEventQueue.cpp \ SensorManager.cpp \ StreamSplitter.cpp \ Surface.cpp \ SurfaceControl.cpp \ SurfaceComposerClient.cpp \ SyncFeatures.cpp \ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libEGL \ libGLESv2 \ libsync \ libui \ libutils \ liblog LOCAL_MODULE := libgui ifeq ($(TARGET_BOARD_PLATFORM), tegra) LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC endif ifeq ($(TARGET_BOARD_PLATFORM), tegra3) LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC endif include $(BUILD_SHARED_LIBRARY) ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif libs/gui/BitTube.cpp0100644 0000000 0000000 00000012133 13077405420 013366 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- // Socket buffer size. The default is typically about 128KB, which is much larger than // we really need. So we make it smaller. static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024; BitTube::BitTube() : mSendFd(-1), mReceiveFd(-1) { init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE); } BitTube::BitTube(size_t bufsize) : mSendFd(-1), mReceiveFd(-1) { init(bufsize, bufsize); } BitTube::BitTube(const Parcel& data) : mSendFd(-1), mReceiveFd(-1) { mReceiveFd = dup(data.readFileDescriptor()); if (mReceiveFd < 0) { mReceiveFd = -errno; ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)", strerror(-mReceiveFd)); } } BitTube::~BitTube() { if (mSendFd >= 0) close(mSendFd); if (mReceiveFd >= 0) close(mReceiveFd); } void BitTube::init(size_t rcvbuf, size_t sndbuf) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { size_t size = DEFAULT_SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); // sine we don't use the "return channel", we keep it small... setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(sockets[0], F_SETFL, O_NONBLOCK); fcntl(sockets[1], F_SETFL, O_NONBLOCK); mReceiveFd = sockets[0]; mSendFd = sockets[1]; } else { mReceiveFd = -errno; ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd)); } } status_t BitTube::initCheck() const { if (mReceiveFd < 0) { return status_t(mReceiveFd); } return NO_ERROR; } int BitTube::getFd() const { return mReceiveFd; } int BitTube::getSendFd() const { return mSendFd; } ssize_t BitTube::write(void const* vaddr, size_t size) { ssize_t err, len; do { len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL); // cannot return less than size, since we're using SOCK_SEQPACKET err = len < 0 ? errno : 0; } while (err == EINTR); return err == 0 ? len : -err; } ssize_t BitTube::read(void* vaddr, size_t size) { ssize_t err, len; do { len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT); err = len < 0 ? errno : 0; } while (err == EINTR); if (err == EAGAIN || err == EWOULDBLOCK) { // EAGAIN means that we have non-blocking I/O but there was // no data to be read. Nothing the client should care about. return 0; } return err == 0 ? len : -err; } status_t BitTube::writeToParcel(Parcel* reply) const { if (mReceiveFd < 0) return -EINVAL; status_t result = reply->writeDupFileDescriptor(mReceiveFd); close(mReceiveFd); mReceiveFd = -1; return result; } ssize_t BitTube::sendObjects(const sp& tube, void const* events, size_t count, size_t objSize) { const char* vaddr = reinterpret_cast(events); ssize_t size = tube->write(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast(objSize)), "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)", count, objSize, size); //ALOGE_IF(size<0, "error %d sending %d events", size, count); return size < 0 ? size : size / static_cast(objSize); } ssize_t BitTube::recvObjects(const sp& tube, void* events, size_t count, size_t objSize) { char* vaddr = reinterpret_cast(events); ssize_t size = tube->read(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast(objSize)), "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)", count, objSize, size); //ALOGE_IF(size<0, "error %d receiving %d events", size, count); return size < 0 ? size : size / static_cast(objSize); } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/BufferItem.cpp0100644 0000000 0000000 00000015161 13077405420 014064 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace android { BufferItem::BufferItem() : mGraphicBuffer(NULL), mFence(NULL), mCrop(Rect::INVALID_RECT), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mIsAutoTimestamp(false), mDataSpace(HAL_DATASPACE_UNKNOWN), mFrameNumber(0), mSlot(INVALID_BUFFER_SLOT), mIsDroppable(false), mAcquireCalled(false), mTransformToDisplayInverse(false), mSurfaceDamage(), mAutoRefresh(false), mQueuedBuffer(true), mIsStale(false) { } BufferItem::~BufferItem() {} template static void addAligned(size_t& size, T /* value */) { size = FlattenableUtils::align(size); size += sizeof(T); } size_t BufferItem::getPodSize() const { size_t size = 0; addAligned(size, mCrop); addAligned(size, mTransform); addAligned(size, mScalingMode); addAligned(size, mTimestampLo); addAligned(size, mTimestampHi); addAligned(size, mIsAutoTimestamp); addAligned(size, mDataSpace); addAligned(size, mFrameNumberLo); addAligned(size, mFrameNumberHi); addAligned(size, mSlot); addAligned(size, mIsDroppable); addAligned(size, mAcquireCalled); addAligned(size, mTransformToDisplayInverse); return size; } size_t BufferItem::getFlattenedSize() const { size_t size = sizeof(uint32_t); // Flags if (mGraphicBuffer != 0) { size += mGraphicBuffer->getFlattenedSize(); FlattenableUtils::align<4>(size); } if (mFence != 0) { size += mFence->getFlattenedSize(); FlattenableUtils::align<4>(size); } size += mSurfaceDamage.getFlattenedSize(); size = FlattenableUtils::align<8>(size); return size + getPodSize(); } size_t BufferItem::getFdCount() const { size_t count = 0; if (mGraphicBuffer != 0) { count += mGraphicBuffer->getFdCount(); } if (mFence != 0) { count += mFence->getFdCount(); } return count; } template static void writeAligned(void*& buffer, size_t& size, T value) { size -= FlattenableUtils::align(buffer); FlattenableUtils::write(buffer, size, value); } status_t BufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space if (size < BufferItem::getFlattenedSize()) { return NO_MEMORY; } // content flags are stored first uint32_t& flags = *static_cast(buffer); // advance the pointer FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); flags = 0; if (mGraphicBuffer != 0) { status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); flags |= 1; } if (mFence != 0) { status_t err = mFence->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); flags |= 2; } status_t err = mSurfaceDamage.flatten(buffer, size); if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } writeAligned(buffer, size, mCrop); writeAligned(buffer, size, mTransform); writeAligned(buffer, size, mScalingMode); writeAligned(buffer, size, mTimestampLo); writeAligned(buffer, size, mTimestampHi); writeAligned(buffer, size, mIsAutoTimestamp); writeAligned(buffer, size, mDataSpace); writeAligned(buffer, size, mFrameNumberLo); writeAligned(buffer, size, mFrameNumberHi); writeAligned(buffer, size, mSlot); writeAligned(buffer, size, mIsDroppable); writeAligned(buffer, size, mAcquireCalled); writeAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } template static void readAligned(const void*& buffer, size_t& size, T& value) { size -= FlattenableUtils::align(buffer); FlattenableUtils::read(buffer, size, value); } status_t BufferItem::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (size < sizeof(uint32_t)) { return NO_MEMORY; } uint32_t flags = 0; FlattenableUtils::read(buffer, size, flags); if (flags & 1) { mGraphicBuffer = new GraphicBuffer(); status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); } if (flags & 2) { mFence = new Fence(); status_t err = mFence->unflatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); } status_t err = mSurfaceDamage.unflatten(buffer, size); if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } readAligned(buffer, size, mCrop); readAligned(buffer, size, mTransform); readAligned(buffer, size, mScalingMode); readAligned(buffer, size, mTimestampLo); readAligned(buffer, size, mTimestampHi); readAligned(buffer, size, mIsAutoTimestamp); readAligned(buffer, size, mDataSpace); readAligned(buffer, size, mFrameNumberLo); readAligned(buffer, size, mFrameNumberHi); readAligned(buffer, size, mSlot); readAligned(buffer, size, mIsDroppable); readAligned(buffer, size, mAcquireCalled); readAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } const char* BufferItem::scalingModeName(uint32_t scalingMode) { switch (scalingMode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; default: return "Unknown"; } } } // namespace android libs/gui/BufferItemConsumer.cpp0100644 0000000 0000000 00000006540 13077405420 015601 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "BufferItemConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include //#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) //#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) #define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { BufferItemConsumer::BufferItemConsumer( const sp& consumer, uint32_t consumerUsage, int bufferCount, bool controlledByApp) : ConsumerBase(consumer, controlledByApp) { status_t err = mConsumer->setConsumerUsageBits(consumerUsage); LOG_ALWAYS_FATAL_IF(err != OK, "Failed to set consumer usage bits to %#x", consumerUsage); if (bufferCount != DEFAULT_MAX_BUFFERS) { err = mConsumer->setMaxAcquiredBufferCount(bufferCount); LOG_ALWAYS_FATAL_IF(err != OK, "Failed to set max acquired buffer count to %d", bufferCount); } } BufferItemConsumer::~BufferItemConsumer() {} void BufferItemConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); if (mAbandoned) { BI_LOGE("setName: BufferItemConsumer is abandoned!"); return; } mName = name; mConsumer->setConsumerName(name); } status_t BufferItemConsumer::acquireBuffer(BufferItem *item, nsecs_t presentWhen, bool waitForFence) { status_t err; if (!item) return BAD_VALUE; Mutex::Autolock _l(mMutex); err = acquireBufferLocked(item, presentWhen); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); } return err; } if (waitForFence) { err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer"); if (err != OK) { BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); return err; } } item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer; return OK; } status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, const sp& releaseFence) { status_t err; Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } return err; } } // namespace android libs/gui/BufferQueue.cpp0100644 0000000 0000000 00000005646 13077405420 014261 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "BufferQueue" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include #include #include #include namespace android { BufferQueue::ProxyConsumerListener::ProxyConsumerListener( const wp& consumerListener): mConsumerListener(consumerListener) {} BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onFrameAvailable( const BufferItem& item) { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(item); } } void BufferQueue::ProxyConsumerListener::onFrameReplaced( const BufferItem& item) { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameReplaced(item); } } void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onBuffersReleased(); } } void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onSidebandStreamChanged(); } } void BufferQueue::createBufferQueue(sp* outProducer, sp* outConsumer, const sp& allocator) { LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); sp core(new BufferQueueCore(allocator)); LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp producer(new BufferQueueProducer(core)); LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp consumer(new BufferQueueConsumer(core)); LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; } }; // namespace android libs/gui/BufferQueueConsumer.cpp0100644 0000000 0000000 00000066577 13077405420 016007 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #define LOG_TAG "BufferQueueConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #if DEBUG_ONLY_CODE #define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0) #else #define VALIDATE_CONSISTENCY() #endif #include #include #include #include #include #include #include #include namespace android { BufferQueueConsumer::BufferQueueConsumer(const sp& core) : mCore(core), mSlots(core->mSlots), mConsumerName() {} BufferQueueConsumer::~BufferQueueConsumer() {} status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent, uint64_t maxFrameNumber) { ATRACE_CALL(); int numDroppedBuffers = 0; sp listener; { Mutex::Autolock lock(mCore->mMutex); // Check that the consumer doesn't currently have the maximum number of // buffers acquired. We allow the max buffer count to be exceeded by one // buffer so that the consumer can successfully set up the newly acquired // buffer before releasing the old one. int numAcquiredBuffers = 0; for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isAcquired()) { ++numAcquiredBuffers; } } if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } bool sharedBufferAvailable = mCore->mSharedBufferMode && mCore->mAutoRefresh && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT; // In asynchronous mode the list is guaranteed to be one buffer deep, // while in synchronous mode we use the oldest buffer. if (mCore->mQueue.empty() && !sharedBufferAvailable) { return NO_BUFFER_AVAILABLE; } BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); // If expectedPresent is specified, we may not want to return a buffer yet. // If it's specified and there's more than one buffer queued, we may want // to drop a buffer. // Skip this if we're in shared buffer mode and the queue is empty, // since in that case we'll just return the shared buffer. if (expectedPresent != 0 && !mCore->mQueue.empty()) { const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second // The 'expectedPresent' argument indicates when the buffer is expected // to be presented on-screen. If the buffer's desired present time is // earlier (less) than expectedPresent -- meaning it will be displayed // on time or possibly late if we show it as soon as possible -- we // acquire and return it. If we don't want to display it until after the // expectedPresent time, we return PRESENT_LATER without acquiring it. // // To be safe, we don't defer acquisition if expectedPresent is more // than one second in the future beyond the desired present time // (i.e., we'd be holding the buffer for a long time). // // NOTE: Code assumes monotonic time values from the system clock // are positive. // Start by checking to see if we can drop frames. We skip this check if // the timestamps are being auto-generated by Surface. If the app isn't // generating timestamps explicitly, it probably doesn't want frames to // be discarded based on them. while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { const BufferItem& bufferItem(mCore->mQueue[1]); // If dropping entry[0] would leave us with a buffer that the // consumer is not yet ready for, don't drop it. if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) { break; } // If entry[1] is timely, drop entry[0] (and repeat). We apply an // additional criterion here: we only drop the earlier buffer if our // desiredPresent falls within +/- 1 second of the expected present. // Otherwise, bogus desiredPresent times (e.g., 0 or a small // relative timestamp), which normally mean "ignore the timestamp // and acquire immediately", would cause us to drop frames. // // We may want to add an additional criterion: don't drop the // earlier buffer if entry[1]'s fence hasn't signaled yet. nsecs_t desiredPresent = bufferItem.mTimestamp; if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || desiredPresent > expectedPresent) { // This buffer is set to display in the near future, or // desiredPresent is garbage. Either way we don't want to drop // the previous buffer just to get this on the screen sooner. BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" PRId64 " (%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); break; } BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 " size=%zu", desiredPresent, expectedPresent, mCore->mQueue.size()); if (!front->mIsStale) { // Front buffer is still in mSlots, so mark the slot as free mSlots[front->mSlot].mBufferState.freeQueued(); // After leaving shared buffer mode, the shared buffer will // still be around. Mark it as no longer shared if this // operation causes it to be free. if (!mCore->mSharedBufferMode && mSlots[front->mSlot].mBufferState.isFree()) { mSlots[front->mSlot].mBufferState.mShared = false; } // Don't put the shared buffer on the free list if (!mSlots[front->mSlot].mBufferState.isShared()) { mCore->mActiveBuffers.erase(front->mSlot); mCore->mFreeBuffers.push_back(front->mSlot); } listener = mCore->mConnectedProducerListener; ++numDroppedBuffers; } mCore->mQueue.erase(front); front = mCore->mQueue.begin(); } // See if the front buffer is ready to be acquired nsecs_t desiredPresent = front->mTimestamp; bool bufferIsDue = desiredPresent <= expectedPresent || desiredPresent > expectedPresent + MAX_REASONABLE_NSEC; bool consumerIsReady = maxFrameNumber > 0 ? front->mFrameNumber <= maxFrameNumber : true; if (!bufferIsDue || !consumerIsReady) { BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64 " consumer=%" PRIu64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC), front->mFrameNumber, maxFrameNumber); return PRESENT_LATER; } BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); } int slot = BufferQueueCore::INVALID_BUFFER_SLOT; if (sharedBufferAvailable && mCore->mQueue.empty()) { // make sure the buffer has finished allocating before acquiring it mCore->waitWhileAllocatingLocked(); slot = mCore->mSharedBufferSlot; // Recreate the BufferItem for the shared buffer from the data that // was cached when it was last queued. outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer; outBuffer->mFence = Fence::NO_FENCE; outBuffer->mCrop = mCore->mSharedBufferCache.crop; outBuffer->mTransform = mCore->mSharedBufferCache.transform & ~static_cast( NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode; outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace; outBuffer->mFrameNumber = mCore->mFrameCounter; outBuffer->mSlot = slot; outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled; outBuffer->mTransformToDisplayInverse = (mCore->mSharedBufferCache.transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0; outBuffer->mSurfaceDamage = Region::INVALID_REGION; outBuffer->mQueuedBuffer = false; outBuffer->mIsStale = false; outBuffer->mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; } else { slot = front->mSlot; *outBuffer = *front; } ATRACE_BUFFER_INDEX(slot); BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle); if (!outBuffer->mIsStale) { mSlots[slot].mAcquireCalled = true; // Don't decrease the queue count if the BufferItem wasn't // previously in the queue. This happens in shared buffer mode when // the queue is empty and the BufferItem is created above. if (mCore->mQueue.empty()) { mSlots[slot].mBufferState.acquireNotInQueue(); } else { mSlots[slot].mBufferState.acquire(); } mSlots[slot].mFence = Fence::NO_FENCE; } // If the buffer has previously been acquired by the consumer, set // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer // on the consumer side if (outBuffer->mAcquireCalled) { outBuffer->mGraphicBuffer = NULL; } mCore->mQueue.erase(front); // We might have freed a slot while dropping old buffers, or the producer // may be blocked waiting for the number of buffers in the queue to // decrease. mCore->mDequeueCondition.broadcast(); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); VALIDATE_CONSISTENCY(); } if (listener != NULL) { for (int i = 0; i < numDroppedBuffers; ++i) { listener->onBufferReleased(); } } return NO_ERROR; } status_t BufferQueueConsumer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); BQ_LOGV("detachBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mSharedBufferMode || slot == mCore->mSharedBufferSlot) { BQ_LOGE("detachBuffer: detachBuffer not allowed in shared buffer mode"); return BAD_VALUE; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isAcquired()) { BQ_LOGE("detachBuffer: slot %d is not owned by the consumer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } mSlots[slot].mBufferState.detachConsumer(); mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); mCore->mDequeueCondition.broadcast(); VALIDATE_CONSISTENCY(); return NO_ERROR; } status_t BufferQueueConsumer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mSharedBufferMode) { BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode"); return BAD_VALUE; } // Make sure we don't have too many acquired buffers int numAcquiredBuffers = 0; for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isAcquired()) { ++numAcquiredBuffers; } } if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { BQ_LOGE("attachBuffer: max acquired buffer count reached: %d " "(max %d)", numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " "[queue %u]", buffer->getGenerationNumber(), mCore->mGenerationNumber); return BAD_VALUE; } // Find a free slot to put the buffer into int found = BufferQueueCore::INVALID_BUFFER_SLOT; if (!mCore->mFreeSlots.empty()) { auto slot = mCore->mFreeSlots.begin(); found = *slot; mCore->mFreeSlots.erase(slot); } else if (!mCore->mFreeBuffers.empty()) { found = mCore->mFreeBuffers.front(); mCore->mFreeBuffers.remove(found); } if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("attachBuffer: could not find free buffer slot"); return NO_MEMORY; } mCore->mActiveBuffers.insert(found); *outSlot = found; ATRACE_BUFFER_INDEX(*outSlot); BQ_LOGV("attachBuffer: returning slot %d", *outSlot); mSlots[*outSlot].mGraphicBuffer = buffer; mSlots[*outSlot].mBufferState.attachConsumer(); mSlots[*outSlot].mNeedsReallocation = true; mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mFrameNumber = 0; // mAcquireCalled tells BufferQueue that it doesn't need to send a valid // GraphicBuffer pointer on the next acquireBuffer call, which decreases // Binder traffic by not un/flattening the GraphicBuffer. However, it // requires that the consumer maintain a cached copy of the slot <--> buffer // mappings, which is why the consumer doesn't need the valid pointer on // acquire. // // The StreamSplitter is one of the primary users of the attach/detach // logic, and while it is running, all buffers it acquires are immediately // detached, and all buffers it eventually releases are ones that were // attached (as opposed to having been obtained from acquireBuffer), so it // doesn't make sense to maintain the slot/buffer mappings, which would // become invalid for every buffer during detach/attach. By setting this to // false, the valid GraphicBuffer pointer will always be sent with acquire // for attached buffers. mSlots[*outSlot].mAcquireCalled = false; VALIDATE_CONSISTENCY(); return NO_ERROR; } status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, const sp& releaseFence, EGLDisplay eglDisplay, EGLSyncKHR eglFence) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || releaseFence == NULL) { BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, releaseFence.get()); return BAD_VALUE; } sp listener; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); // If the frame number has changed because the buffer has been reallocated, // we can ignore this releaseBuffer for the old buffer. // Ignore this for the shared buffer where the frame number can easily // get out of sync due to the buffer being queued and acquired at the // same time. if (frameNumber != mSlots[slot].mFrameNumber && !mSlots[slot].mBufferState.isShared()) { return STALE_BUFFER_SLOT; } if (!mSlots[slot].mBufferState.isAcquired()) { BQ_LOGE("releaseBuffer: attempted to release buffer slot %d " "but its state was %s", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } mSlots[slot].mEglDisplay = eglDisplay; mSlots[slot].mEglFence = eglFence; mSlots[slot].mFence = releaseFence; mSlots[slot].mBufferState.release(); // After leaving shared buffer mode, the shared buffer will // still be around. Mark it as no longer shared if this // operation causes it to be free. if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) { mSlots[slot].mBufferState.mShared = false; } // Don't put the shared buffer on the free list. if (!mSlots[slot].mBufferState.isShared()) { mCore->mActiveBuffers.erase(slot); mCore->mFreeBuffers.push_back(slot); } listener = mCore->mConnectedProducerListener; BQ_LOGV("releaseBuffer: releasing slot %d", slot); mCore->mDequeueCondition.broadcast(); VALIDATE_CONSISTENCY(); } // Autolock scope // Call back without lock held if (listener != NULL) { listener->onBufferReleased(); } return NO_ERROR; } status_t BufferQueueConsumer::connect( const sp& consumerListener, bool controlledByApp) { ATRACE_CALL(); if (consumerListener == NULL) { BQ_LOGE("connect: consumerListener may not be NULL"); return BAD_VALUE; } BQ_LOGV("connect: controlledByApp=%s", controlledByApp ? "true" : "false"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("connect: BufferQueue has been abandoned"); return NO_INIT; } mCore->mConsumerListener = consumerListener; mCore->mConsumerControlledByApp = controlledByApp; return NO_ERROR; } status_t BufferQueueConsumer::disconnect() { ATRACE_CALL(); BQ_LOGV("disconnect"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mConsumerListener == NULL) { BQ_LOGE("disconnect: no consumer is connected"); return BAD_VALUE; } mCore->mIsAbandoned = true; mCore->mConsumerListener = NULL; mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; mCore->mDequeueCondition.broadcast(); return NO_ERROR; } status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ATRACE_CALL(); if (outSlotMask == NULL) { BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned"); return NO_INIT; } uint64_t mask = 0; for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { if (!mSlots[s].mAcquireCalled) { mask |= (1ULL << s); } } // Remove from the mask queued buffers for which acquire has been called, // since the consumer will not receive their buffer addresses and so must // retain their cached information BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); while (current != mCore->mQueue.end()) { if (current->mAcquireCalled) { mask &= ~(1ULL << current->mSlot); } ++current; } BQ_LOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); *outSlotMask = mask; return NO_ERROR; } status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) { ATRACE_CALL(); if (width == 0 || height == 0) { BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " "height=%u)", width, height); return BAD_VALUE; } BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height); Mutex::Autolock lock(mCore->mMutex); mCore->mDefaultWidth = width; mCore->mDefaultHeight = height; return NO_ERROR; } status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { ATRACE_CALL(); if (bufferCount < 1 || bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("setMaxBufferCount: invalid count %d", bufferCount); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("setMaxBufferCount: producer is already connected"); return INVALID_OPERATION; } if (bufferCount < mCore->mMaxAcquiredBufferCount) { BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than" "mMaxAcquiredBufferCount (%d)", bufferCount, mCore->mMaxAcquiredBufferCount); return BAD_VALUE; } int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, mCore->mDequeueBufferCannotBlock, bufferCount) - mCore->getMaxBufferCountLocked(); if (!mCore->adjustAvailableSlotsLocked(delta)) { BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number of " "available slots. Delta = %d", delta); return BAD_VALUE; } mCore->mMaxBufferCount = bufferCount; return NO_ERROR; } status_t BufferQueueConsumer::setMaxAcquiredBufferCount( int maxAcquiredBuffers) { ATRACE_CALL(); if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", maxAcquiredBuffers); return BAD_VALUE; } sp listener; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned"); return NO_INIT; } if (maxAcquiredBuffers == mCore->mMaxAcquiredBufferCount) { return NO_ERROR; } // The new maxAcquiredBuffers count should not be violated by the number // of currently acquired buffers int acquiredCount = 0; for (int slot : mCore->mActiveBuffers) { if (mSlots[slot].mBufferState.isAcquired()) { acquiredCount++; } } if (acquiredCount > maxAcquiredBuffers) { BQ_LOGE("setMaxAcquiredBufferCount: the requested maxAcquiredBuffer" "count (%d) exceeds the current acquired buffer count (%d)", maxAcquiredBuffers, acquiredCount); return BAD_VALUE; } if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount + (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) > mCore->mMaxBufferCount) { BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would " "exceed the maxBufferCount (%d) (maxDequeued %d async %d)", maxAcquiredBuffers, mCore->mMaxBufferCount, mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock); return BAD_VALUE; } int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount; if (!mCore->adjustAvailableSlotsLocked(delta)) { return BAD_VALUE; } BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); if (delta < 0) { listener = mCore->mConsumerListener; } } // Call back without lock held if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; } void BufferQueueConsumer::setConsumerName(const String8& name) { ATRACE_CALL(); BQ_LOGV("setConsumerName: '%s'", name.string()); Mutex::Autolock lock(mCore->mMutex); mCore->mConsumerName = name; mConsumerName = name; } status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); Mutex::Autolock lock(mCore->mMutex); mCore->mDefaultBufferFormat = defaultFormat; return NO_ERROR; } status_t BufferQueueConsumer::setDefaultBufferDataSpace( android_dataspace defaultDataSpace) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace); Mutex::Autolock lock(mCore->mMutex); mCore->mDefaultBufferDataSpace = defaultDataSpace; return NO_ERROR; } status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { ATRACE_CALL(); BQ_LOGV("setConsumerUsageBits: %#x", usage); Mutex::Autolock lock(mCore->mMutex); mCore->mConsumerUsageBits = usage; return NO_ERROR; } status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { ATRACE_CALL(); BQ_LOGV("setTransformHint: %#x", hint); Mutex::Autolock lock(mCore->mMutex); mCore->mTransformHint = hint; return NO_ERROR; } sp BufferQueueConsumer::getSidebandStream() const { Mutex::Autolock lock(mCore->mMutex); return mCore->mSidebandStream; } status_t BufferQueueConsumer::discardFreeBuffers() { Mutex::Autolock lock(mCore->mMutex); mCore->discardFreeBuffersLocked(); return NO_ERROR; } void BufferQueueConsumer::dump(String8& result, const char* prefix) const { const IPCThreadState* ipc = IPCThreadState::self(); const pid_t pid = ipc->getCallingPid(); const uid_t uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(String16( "android.permission.DUMP"), pid, uid)) { result.appendFormat("Permission Denial: can't dump BufferQueueConsumer " "from pid=%d, uid=%d\n", pid, uid); android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0); } else { mCore->dump(result, prefix); } } } // namespace android libs/gui/BufferQueueCore.cpp0100644 0000000 0000000 00000035601 13077405420 015064 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BufferQueueCore" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #define EGL_EGLEXT_PROTOTYPES #if DEBUG_ONLY_CODE #define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0) #else #define VALIDATE_CONSISTENCY() #endif #include #include #include #include #include #include #include #include namespace android { static String8 getUniqueName() { static volatile int32_t counter = 0; return String8::format("unnamed-%d-%d", getpid(), android_atomic_inc(&counter)); } static uint64_t getUniqueId() { static std::atomic counter{0}; static uint64_t id = static_cast(getpid()) << 32; return id | counter++; } BufferQueueCore::BufferQueueCore(const sp& allocator) : mAllocator(allocator), mMutex(), mIsAbandoned(false), mConsumerControlledByApp(false), mConsumerName(getUniqueName()), mConsumerListener(), mConsumerUsageBits(0), mConnectedApi(NO_CONNECTED_API), mConnectedProducerListener(), mSlots(), mQueue(), mFreeSlots(), mFreeBuffers(), mUnusedSlots(), mActiveBuffers(), mDequeueCondition(), mDequeueBufferCannotBlock(false), mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS), mMaxAcquiredBufferCount(1), mMaxDequeuedBufferCount(1), mBufferHasBeenQueued(false), mFrameCounter(0), mTransformHint(0), mIsAllocating(false), mIsAllocatingCondition(), mAllowAllocation(true), mBufferAge(0), mGenerationNumber(0), mAsyncMode(false), mSharedBufferMode(false), mAutoRefresh(false), mSharedBufferSlot(INVALID_BUFFER_SLOT), mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN), mLastQueuedSlot(INVALID_BUFFER_SLOT), mUniqueId(getUniqueId()) { if (allocator == NULL) { sp composer(ComposerService::getComposerService()); mAllocator = composer->createGraphicBufferAlloc(); if (mAllocator == NULL) { BQ_LOGE("createGraphicBufferAlloc failed"); } } int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { mFreeSlots.insert(s); } for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS; s++) { mUnusedSlots.push_front(s); } } BufferQueueCore::~BufferQueueCore() {} void BufferQueueCore::dump(String8& result, const char* prefix) const { Mutex::Autolock lock(mMutex); String8 fifo; Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", current->mSlot, current->mGraphicBuffer.get(), current->mCrop.left, current->mCrop.top, current->mCrop.right, current->mCrop.bottom, current->mTransform, current->mTimestamp, BufferItem::scalingModeName(current->mScalingMode)); ++current; } result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d " "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, " "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix, mMaxAcquiredBufferCount, mMaxDequeuedBufferCount, mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(), fifo.string()); for (int s : mActiveBuffers) { const sp& buffer(mSlots[s].mGraphicBuffer); // A dequeued buffer might be null if it's still being allocated if (buffer.get()) { result.appendFormat("%s%s[%02d:%p] state=%-8s, %p " "[%4ux%4u:%4u,%3X]\n", prefix, (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s, buffer.get(), mSlots[s].mBufferState.string(), buffer->handle, buffer->width, buffer->height, buffer->stride, buffer->format); } else { result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s, buffer.get(), mSlots[s].mBufferState.string()); } } for (int s : mFreeBuffers) { const sp& buffer(mSlots[s].mGraphicBuffer); result.appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n", prefix, s, buffer.get(), mSlots[s].mBufferState.string(), buffer->handle, buffer->width, buffer->height, buffer->stride, buffer->format); } for (int s : mFreeSlots) { const sp& buffer(mSlots[s].mGraphicBuffer); result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s, buffer.get(), mSlots[s].mBufferState.string()); } } int BufferQueueCore::getMinUndequeuedBufferCountLocked() const { // If dequeueBuffer is allowed to error out, we don't have to add an // extra buffer. if (mAsyncMode || mDequeueBufferCannotBlock) { return mMaxAcquiredBufferCount + 1; } return mMaxAcquiredBufferCount; } int BufferQueueCore::getMinMaxBufferCountLocked() const { return getMinUndequeuedBufferCountLocked() + 1; } int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode, bool dequeueBufferCannotBlock, int maxBufferCount) const { int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount + ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0); maxCount = std::min(maxBufferCount, maxCount); return maxCount; } int BufferQueueCore::getMaxBufferCountLocked() const { int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount + ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0); // limit maxBufferCount by mMaxBufferCount always maxBufferCount = std::min(mMaxBufferCount, maxBufferCount); return maxBufferCount; } void BufferQueueCore::clearBufferSlotLocked(int slot) { BQ_LOGV("clearBufferSlotLocked: slot %d", slot); mSlots[slot].mGraphicBuffer.clear(); mSlots[slot].mBufferState.reset(); mSlots[slot].mRequestBufferCalled = false; mSlots[slot].mFrameNumber = 0; mSlots[slot].mAcquireCalled = false; mSlots[slot].mNeedsReallocation = true; // Destroy fence as BufferQueue now takes ownership if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence); mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; } mSlots[slot].mFence = Fence::NO_FENCE; mSlots[slot].mEglDisplay = EGL_NO_DISPLAY; if (mLastQueuedSlot == slot) { mLastQueuedSlot = INVALID_BUFFER_SLOT; } } void BufferQueueCore::freeAllBuffersLocked() { for (int s : mFreeSlots) { clearBufferSlotLocked(s); } for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); } mFreeBuffers.clear(); for (int s : mActiveBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); } mActiveBuffers.clear(); for (auto& b : mQueue) { b.mIsStale = true; } VALIDATE_CONSISTENCY(); } void BufferQueueCore::discardFreeBuffersLocked() { for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); } mFreeBuffers.clear(); VALIDATE_CONSISTENCY(); } bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) { if (delta >= 0) { // If we're going to fail, do so before modifying anything if (delta > static_cast(mUnusedSlots.size())) { return false; } while (delta > 0) { if (mUnusedSlots.empty()) { return false; } int slot = mUnusedSlots.back(); mUnusedSlots.pop_back(); mFreeSlots.insert(slot); delta--; } } else { // If we're going to fail, do so before modifying anything if (-delta > static_cast(mFreeSlots.size() + mFreeBuffers.size())) { return false; } while (delta < 0) { if (!mFreeSlots.empty()) { auto slot = mFreeSlots.begin(); clearBufferSlotLocked(*slot); mUnusedSlots.push_back(*slot); mFreeSlots.erase(slot); } else if (!mFreeBuffers.empty()) { int slot = mFreeBuffers.back(); clearBufferSlotLocked(slot); mUnusedSlots.push_back(slot); mFreeBuffers.pop_back(); } else { return false; } delta++; } } return true; } void BufferQueueCore::waitWhileAllocatingLocked() const { ATRACE_CALL(); while (mIsAllocating) { mIsAllocatingCondition.wait(mMutex); } } #if DEBUG_ONLY_CODE void BufferQueueCore::validateConsistencyLocked() const { static const useconds_t PAUSE_TIME = 0; int allocatedSlots = 0; for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { bool isInFreeSlots = mFreeSlots.count(slot) != 0; bool isInFreeBuffers = std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) != mFreeBuffers.cend(); bool isInActiveBuffers = mActiveBuffers.count(slot) != 0; bool isInUnusedSlots = std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) != mUnusedSlots.cend(); if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) { allocatedSlots++; } if (isInUnusedSlots) { if (isInFreeSlots) { BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot); usleep(PAUSE_TIME); } if (isInFreeBuffers) { BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot); usleep(PAUSE_TIME); } if (isInActiveBuffers) { BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers", slot); usleep(PAUSE_TIME); } if (!mSlots[slot].mBufferState.isFree()) { BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot); usleep(PAUSE_TIME); } if (mSlots[slot].mGraphicBuffer != NULL) { BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer", slot); usleep(PAUSE_TIME); } } else if (isInFreeSlots) { if (isInUnusedSlots) { BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot); usleep(PAUSE_TIME); } if (isInFreeBuffers) { BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot); usleep(PAUSE_TIME); } if (isInActiveBuffers) { BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot); usleep(PAUSE_TIME); } if (!mSlots[slot].mBufferState.isFree()) { BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot); usleep(PAUSE_TIME); } if (mSlots[slot].mGraphicBuffer != NULL) { BQ_LOGE("Slot %d is in mFreeSlots but has a buffer", slot); usleep(PAUSE_TIME); } } else if (isInFreeBuffers) { if (isInUnusedSlots) { BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot); usleep(PAUSE_TIME); } if (isInFreeSlots) { BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot); usleep(PAUSE_TIME); } if (isInActiveBuffers) { BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers", slot); usleep(PAUSE_TIME); } if (!mSlots[slot].mBufferState.isFree()) { BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot); usleep(PAUSE_TIME); } if (mSlots[slot].mGraphicBuffer == NULL) { BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot); usleep(PAUSE_TIME); } } else if (isInActiveBuffers) { if (isInUnusedSlots) { BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots", slot); usleep(PAUSE_TIME); } if (isInFreeSlots) { BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot); usleep(PAUSE_TIME); } if (isInFreeBuffers) { BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers", slot); usleep(PAUSE_TIME); } if (mSlots[slot].mBufferState.isFree() && !mSlots[slot].mBufferState.isShared()) { BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot); usleep(PAUSE_TIME); } if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) { BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot); usleep(PAUSE_TIME); } } else { BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, " "mFreeBuffers, or mActiveBuffers", slot); usleep(PAUSE_TIME); } } if (allocatedSlots != getMaxBufferCountLocked()) { BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, " "Should be %d (%zu free slots, %zu free buffers, " "%zu activeBuffers, %zu unusedSlots)", allocatedSlots, getMaxBufferCountLocked(), mFreeSlots.size(), mFreeBuffers.size(), mActiveBuffers.size(), mUnusedSlots.size()); } } #endif } // namespace android libs/gui/BufferQueueProducer.cpp0100644 0000000 0000000 00000145706 13077405420 015767 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #define LOG_TAG "BufferQueueProducer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #if DEBUG_ONLY_CODE #define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0) #else #define VALIDATE_CONSISTENCY() #endif #define EGL_EGLEXT_PROTOTYPES #include #include #include #include #include #include #include #include #include namespace android { BufferQueueProducer::BufferQueueProducer(const sp& core) : mCore(core), mSlots(core->mSlots), mConsumerName(), mStickyTransform(0), mLastQueueBufferFence(Fence::NO_FENCE), mCallbackMutex(), mNextCallbackTicket(0), mCurrentCallbackTicket(0), mCallbackCondition(), mDequeueTimeout(-1) {} BufferQueueProducer::~BufferQueueProducer() {} status_t BufferQueueProducer::requestBuffer(int slot, sp* buf) { ATRACE_CALL(); BQ_LOGV("requestBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("requestBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("requestBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("requestBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } mSlots[slot].mRequestBufferCalled = true; *buf = mSlots[slot].mGraphicBuffer; return NO_ERROR; } status_t BufferQueueProducer::setMaxDequeuedBufferCount( int maxDequeuedBuffers) { ATRACE_CALL(); BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d", maxDequeuedBuffers); sp listener; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been " "abandoned"); return NO_INIT; } if (maxDequeuedBuffers == mCore->mMaxDequeuedBufferCount) { return NO_ERROR; } // The new maxDequeuedBuffer count should not be violated by the number // of currently dequeued buffers int dequeuedCount = 0; for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isDequeued()) { dequeuedCount++; } } if (dequeuedCount > maxDequeuedBuffers) { BQ_LOGE("setMaxDequeuedBufferCount: the requested maxDequeuedBuffer" "count (%d) exceeds the current dequeued buffer count (%d)", maxDequeuedBuffers, dequeuedCount); return BAD_VALUE; } int bufferCount = mCore->getMinUndequeuedBufferCountLocked(); bufferCount += maxDequeuedBuffers; if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large " "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } const int minBufferSlots = mCore->getMinMaxBufferCountLocked(); if (bufferCount < minBufferSlots) { BQ_LOGE("setMaxDequeuedBufferCount: requested buffer count %d is " "less than minimum %d", bufferCount, minBufferSlots); return BAD_VALUE; } if (bufferCount > mCore->mMaxBufferCount) { BQ_LOGE("setMaxDequeuedBufferCount: %d dequeued buffers would " "exceed the maxBufferCount (%d) (maxAcquired %d async %d " "mDequeuedBufferCannotBlock %d)", maxDequeuedBuffers, mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount, mCore->mAsyncMode, mCore->mDequeueBufferCannotBlock); return BAD_VALUE; } int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount; if (!mCore->adjustAvailableSlotsLocked(delta)) { return BAD_VALUE; } mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers; VALIDATE_CONSISTENCY(); if (delta < 0) { listener = mCore->mConsumerListener; } mCore->mDequeueCondition.broadcast(); } // Autolock scope // Call back without lock held if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; } status_t BufferQueueProducer::setAsyncMode(bool async) { ATRACE_CALL(); BQ_LOGV("setAsyncMode: async = %d", async); sp listener; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { BQ_LOGE("setAsyncMode: BufferQueue has been abandoned"); return NO_INIT; } if (async == mCore->mAsyncMode) { return NO_ERROR; } if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount + (async || mCore->mDequeueBufferCannotBlock ? 1 : 0)) > mCore->mMaxBufferCount) { BQ_LOGE("setAsyncMode(%d): this call would cause the " "maxBufferCount (%d) to be exceeded (maxAcquired %d " "maxDequeued %d mDequeueBufferCannotBlock %d)", async, mCore->mMaxBufferCount, mCore->mMaxAcquiredBufferCount, mCore->mMaxDequeuedBufferCount, mCore->mDequeueBufferCannotBlock); return BAD_VALUE; } int delta = mCore->getMaxBufferCountLocked(async, mCore->mDequeueBufferCannotBlock, mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked(); if (!mCore->adjustAvailableSlotsLocked(delta)) { BQ_LOGE("setAsyncMode: BufferQueue failed to adjust the number of " "available slots. Delta = %d", delta); return BAD_VALUE; } mCore->mAsyncMode = async; VALIDATE_CONSISTENCY(); mCore->mDequeueCondition.broadcast(); if (delta < 0) { listener = mCore->mConsumerListener; } } // Autolock scope // Call back without lock held if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; } int BufferQueueProducer::getFreeBufferLocked() const { if (mCore->mFreeBuffers.empty()) { return BufferQueueCore::INVALID_BUFFER_SLOT; } int slot = mCore->mFreeBuffers.front(); mCore->mFreeBuffers.pop_front(); return slot; } int BufferQueueProducer::getFreeSlotLocked() const { if (mCore->mFreeSlots.empty()) { return BufferQueueCore::INVALID_BUFFER_SLOT; } int slot = *(mCore->mFreeSlots.begin()); mCore->mFreeSlots.erase(slot); return slot; } status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const { auto callerString = (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer"; bool tryAgain = true; while (tryAgain) { if (mCore->mIsAbandoned) { BQ_LOGE("%s: BufferQueue has been abandoned", callerString); return NO_INIT; } int dequeuedCount = 0; int acquiredCount = 0; for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isDequeued()) { ++dequeuedCount; } if (mSlots[s].mBufferState.isAcquired()) { ++acquiredCount; } } // Producers are not allowed to dequeue more than // mMaxDequeuedBufferCount buffers. // This check is only done if a buffer has already been queued if (mCore->mBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) { BQ_LOGE("%s: attempting to exceed the max dequeued buffer count " "(%d)", callerString, mCore->mMaxDequeuedBufferCount); return INVALID_OPERATION; } *found = BufferQueueCore::INVALID_BUFFER_SLOT; // If we disconnect and reconnect quickly, we can be in a state where // our slots are empty but we have many buffers in the queue. This can // cause us to run out of memory if we outrun the consumer. Wait here if // it looks like we have too many buffers queued up. const int maxBufferCount = mCore->getMaxBufferCountLocked(); bool tooManyBuffers = mCore->mQueue.size() > static_cast(maxBufferCount); if (tooManyBuffers) { BQ_LOGV("%s: queue size is %zu, waiting", callerString, mCore->mQueue.size()); } else { // If in shared buffer mode and a shared buffer exists, always // return it. if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = mCore->mSharedBufferSlot; } else { if (caller == FreeSlotCaller::Dequeue) { // If we're calling this from dequeue, prefer free buffers int slot = getFreeBufferLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else if (mCore->mAllowAllocation) { *found = getFreeSlotLocked(); } } else { // If we're calling this from attach, prefer free slots int slot = getFreeSlotLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else { *found = getFreeBufferLocked(); } } } } // If no buffer is found, or if the queue has too many buffers // outstanding, wait for a buffer to be acquired or released, or for the // max buffer count to change. tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { // Return an error if we're in non-blocking mode (producer and // consumer are controlled by the application). // However, the consumer is allowed to briefly acquire an extra // buffer (which could cause us to have to wait here), which is // okay, since it is only used to implement an atomic acquire + // release (e.g., in GLConsumer::updateTexImage()) if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) && (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } if (mDequeueTimeout >= 0) { status_t result = mCore->mDequeueCondition.waitRelative( mCore->mMutex, mDequeueTimeout); if (result == TIMED_OUT) { return result; } } else { mCore->mDequeueCondition.wait(mCore->mMutex); } } } // while (tryAgain) return NO_ERROR; } status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp *outFence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; if (mCore->mIsAbandoned) { BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer"); return NO_INIT; } } // Autolock scope BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height, format, usage); if ((width && !height) || (!width && height)) { BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); return BAD_VALUE; } status_t returnFlags = NO_ERROR; EGLDisplay eglDisplay = EGL_NO_DISPLAY; EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; bool attachedByConsumer = false; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (format == 0) { format = mCore->mDefaultBufferFormat; } // Enable the usage bits the consumer requested usage |= mCore->mConsumerUsageBits; const bool useDefaultSize = !width && !height; if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; } int found = BufferItem::INVALID_BUFFER_SLOT; while (found == BufferItem::INVALID_BUFFER_SLOT) { status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, &found); if (status != NO_ERROR) { return status; } // This should not happen if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const sp& buffer(mSlots[found].mGraphicBuffer); // If we are not allowed to allocate new buffers, // waitForFreeSlotThenRelock must have returned a slot containing a // buffer. If this buffer would require reallocation to meet the // requested attributes, we free it and attempt to get another one. if (!mCore->mAllowAllocation) { if (buffer->needsReallocation(width, height, format, usage)) { if (mCore->mSharedBufferSlot == found) { BQ_LOGE("dequeueBuffer: cannot re-allocate a shared" "buffer"); return BAD_VALUE; } mCore->mFreeSlots.insert(found); mCore->clearBufferSlotLocked(found); found = BufferItem::INVALID_BUFFER_SLOT; continue; } } } const sp& buffer(mSlots[found].mGraphicBuffer); if (mCore->mSharedBufferSlot == found && buffer->needsReallocation(width, height, format, usage)) { BQ_LOGE("dequeueBuffer: cannot re-allocate a shared" "buffer"); return BAD_VALUE; } if (mCore->mSharedBufferSlot != found) { mCore->mActiveBuffers.insert(found); } *outSlot = found; ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlots[found].mNeedsReallocation; mSlots[found].mNeedsReallocation = false; mSlots[found].mBufferState.dequeue(); if ((buffer == NULL) || buffer->needsReallocation(width, height, format, usage)) { mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; mCore->mBufferAge = 0; mCore->mIsAllocating = true; returnFlags |= BUFFER_NEEDS_REALLOCATION; } else { // We add 1 because that will be the frame number when this buffer // is queued mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber; } BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge); if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); } eglDisplay = mSlots[found].mEglDisplay; eglFence = mSlots[found].mEglFence; // Don't return a fence in shared buffer mode, except for the first // frame. *outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; // If shared buffer mode has just been enabled, cache the slot of the // first buffer that is dequeued and mark it as the shared buffer. if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == BufferQueueCore::INVALID_BUFFER_SLOT) { mCore->mSharedBufferSlot = found; mSlots[found].mBufferState.mShared = true; } } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( width, height, format, usage, &error)); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); if (graphicBuffer != NULL && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); if (graphicBuffer == NULL) { BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; } if (mCore->mIsAbandoned) { BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); return NO_INIT; } VALIDATE_CONSISTENCY(); } // Autolock scope } if (attachedByConsumer) { returnFlags |= BUFFER_NEEDS_REALLOCATION; } if (eglFence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without // synchronizing access to it. It's too late at this point to abort the // dequeue operation. if (result == EGL_FALSE) { BQ_LOGE("dequeueBuffer: error %#x waiting for fence", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { BQ_LOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(eglDisplay, eglFence); } BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", *outSlot, mSlots[*outSlot].mFrameNumber, mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); return returnFlags; } status_t BufferQueueProducer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); BQ_LOGV("detachBuffer: slot %d", slot); sp listener; { Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("detachBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (mCore->mSharedBufferMode || mCore->mSharedBufferSlot == slot) { BQ_LOGE("detachBuffer: cannot detach a buffer in shared buffer mode"); return BAD_VALUE; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("detachBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } else if (!mSlots[slot].mRequestBufferCalled) { BQ_LOGE("detachBuffer: buffer in slot %d has not been requested", slot); return BAD_VALUE; } mSlots[slot].mBufferState.detachProducer(); mCore->mActiveBuffers.erase(slot); mCore->mFreeSlots.insert(slot); mCore->clearBufferSlotLocked(slot); mCore->mDequeueCondition.broadcast(); VALIDATE_CONSISTENCY(); listener = mCore->mConsumerListener; } if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; } status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, sp* outFence) { ATRACE_CALL(); if (outBuffer == NULL) { BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; } else if (outFence == NULL) { BQ_LOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (mCore->mSharedBufferMode) { BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer " "mode"); return BAD_VALUE; } mCore->waitWhileAllocatingLocked(); if (mCore->mFreeBuffers.empty()) { return NO_MEMORY; } int found = mCore->mFreeBuffers.front(); mCore->mFreeBuffers.remove(found); mCore->mFreeSlots.insert(found); BQ_LOGV("detachNextBuffer detached slot %d", found); *outBuffer = mSlots[found].mGraphicBuffer; *outFence = mSlots[found].mFence; mCore->clearBufferSlotLocked(found); VALIDATE_CONSISTENCY(); return NO_ERROR; } status_t BufferQueueProducer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("attachBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("attachBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (mCore->mSharedBufferMode) { BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode"); return BAD_VALUE; } if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " "[queue %u]", buffer->getGenerationNumber(), mCore->mGenerationNumber); return BAD_VALUE; } mCore->waitWhileAllocatingLocked(); status_t returnFlags = NO_ERROR; int found; status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found); if (status != NO_ERROR) { return status; } // This should not happen if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("attachBuffer: no available buffer slots"); return -EBUSY; } *outSlot = found; ATRACE_BUFFER_INDEX(*outSlot); BQ_LOGV("attachBuffer: returning slot %d flags=%#x", *outSlot, returnFlags); mSlots[*outSlot].mGraphicBuffer = buffer; mSlots[*outSlot].mBufferState.attachProducer(); mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR; mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mRequestBufferCalled = true; mSlots[*outSlot].mAcquireCalled = false; mCore->mActiveBuffers.insert(found); VALIDATE_CONSISTENCY(); return returnFlags; } status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; Rect crop(Rect::EMPTY_RECT); int scalingMode; uint32_t transform; uint32_t stickyTransform; sp fence; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &fence, &stickyTransform); Region surfaceDamage = input.getSurfaceDamage(); if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); return BAD_VALUE; } switch (scalingMode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: break; default: BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode); return BAD_VALUE; } sp frameAvailableListener; sp frameReplacedListener; int callbackTicket = 0; BufferItem item; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("queueBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("queueBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("queueBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } else if (!mSlots[slot].mRequestBufferCalled) { BQ_LOGE("queueBuffer: slot %d was queued without requesting " "a buffer", slot); return BAD_VALUE; } // If shared buffer mode has just been enabled, cache the slot of the // first buffer that is queued and mark it as the shared buffer. if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == BufferQueueCore::INVALID_BUFFER_SLOT) { mCore->mSharedBufferSlot = slot; mSlots[slot].mBufferState.mShared = true; } BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" " crop=[%d,%d,%d,%d] transform=%#x scale=%s", slot, mCore->mFrameCounter + 1, timestamp, dataSpace, crop.left, crop.top, crop.right, crop.bottom, transform, BufferItem::scalingModeName(static_cast(scalingMode))); const sp& graphicBuffer(mSlots[slot].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); Rect croppedRect(Rect::EMPTY_RECT); crop.intersect(bufferRect, &croppedRect); if (croppedRect != crop) { BQ_LOGE("queueBuffer: crop rect is not contained within the " "buffer in slot %d", slot); return BAD_VALUE; } // Override UNKNOWN dataspace with consumer default if (dataSpace == HAL_DATASPACE_UNKNOWN) { dataSpace = mCore->mDefaultBufferDataSpace; } mSlots[slot].mFence = fence; mSlots[slot].mBufferState.queue(); ++mCore->mFrameCounter; mSlots[slot].mFrameNumber = mCore->mFrameCounter; item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; item.mTransform = transform & ~static_cast(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); item.mTransformToDisplayInverse = (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0; item.mScalingMode = static_cast(scalingMode); item.mTimestamp = timestamp; item.mIsAutoTimestamp = isAutoTimestamp; item.mDataSpace = dataSpace; item.mFrameNumber = mCore->mFrameCounter; item.mSlot = slot; item.mFence = fence; item.mIsDroppable = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock || (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot); item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true; item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; mStickyTransform = stickyTransform; // Cache the shared buffer data so that the BufferItem can be recreated. if (mCore->mSharedBufferMode) { mCore->mSharedBufferCache.crop = crop; mCore->mSharedBufferCache.transform = transform; mCore->mSharedBufferCache.scalingMode = static_cast( scalingMode); mCore->mSharedBufferCache.dataspace = dataSpace; } if (mCore->mQueue.empty()) { // When the queue is empty, we can ignore mDequeueBufferCannotBlock // and simply queue this buffer mCore->mQueue.push_back(item); frameAvailableListener = mCore->mConsumerListener; } else { // When the queue is not empty, we need to look at the last buffer // in the queue to see if we need to replace it const BufferItem& last = mCore->mQueue.itemAt( mCore->mQueue.size() - 1); if (last.mIsDroppable) { if (!last.mIsStale) { mSlots[last.mSlot].mBufferState.freeQueued(); // After leaving shared buffer mode, the shared buffer will // still be around. Mark it as no longer shared if this // operation causes it to be free. if (!mCore->mSharedBufferMode && mSlots[last.mSlot].mBufferState.isFree()) { mSlots[last.mSlot].mBufferState.mShared = false; } // Don't put the shared buffer on the free list. if (!mSlots[last.mSlot].mBufferState.isShared()) { mCore->mActiveBuffers.erase(last.mSlot); mCore->mFreeBuffers.push_back(last.mSlot); } } // Overwrite the droppable buffer with the incoming one mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item; frameReplacedListener = mCore->mConsumerListener; } else { mCore->mQueue.push_back(item); frameAvailableListener = mCore->mConsumerListener; } } mCore->mBufferHasBeenQueued = true; mCore->mDequeueCondition.broadcast(); mCore->mLastQueuedSlot = slot; output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, mCore->mTransformHint, static_cast(mCore->mQueue.size())); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); // Take a ticket for the callback functions callbackTicket = mNextCallbackTicket++; VALIDATE_CONSISTENCY(); } // Autolock scope // Don't send the GraphicBuffer through the callback, and don't send // the slot number, since the consumer shouldn't need it item.mGraphicBuffer.clear(); item.mSlot = BufferItem::INVALID_BUFFER_SLOT; // Call back without the main BufferQueue lock held, but with the callback // lock held so we can ensure that callbacks occur in order { Mutex::Autolock lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { mCallbackCondition.wait(mCallbackMutex); } if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } ++mCurrentCallbackTicket; mCallbackCondition.broadcast(); } // Wait without lock held if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) { // Waiting here allows for two full buffers to be queued but not a // third. In the event that frames take varying time, this makes a // small trade-off in favor of latency rather than throughput. mLastQueueBufferFence->waitForever("Throttling EGL Production"); } mLastQueueBufferFence = fence; mLastQueuedCrop = item.mCrop; mLastQueuedTransform = item.mTransform; return NO_ERROR; } status_t BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { ATRACE_CALL(); BQ_LOGV("cancelBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("cancelBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (mCore->mSharedBufferMode) { BQ_LOGE("cancelBuffer: cannot cancel a buffer in shared buffer mode"); return BAD_VALUE; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } else if (fence == NULL) { BQ_LOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } mSlots[slot].mBufferState.cancel(); // After leaving shared buffer mode, the shared buffer will still be around. // Mark it as no longer shared if this operation causes it to be free. if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) { mSlots[slot].mBufferState.mShared = false; } // Don't put the shared buffer on the free list. if (!mSlots[slot].mBufferState.isShared()) { mCore->mActiveBuffers.erase(slot); mCore->mFreeBuffers.push_back(slot); } mSlots[slot].mFence = fence; mCore->mDequeueCondition.broadcast(); VALIDATE_CONSISTENCY(); return NO_ERROR; } int BufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); if (outValue == NULL) { BQ_LOGE("query: outValue was NULL"); return BAD_VALUE; } if (mCore->mIsAbandoned) { BQ_LOGE("query: BufferQueue has been abandoned"); return NO_INIT; } int value; switch (what) { case NATIVE_WINDOW_WIDTH: value = static_cast(mCore->mDefaultWidth); break; case NATIVE_WINDOW_HEIGHT: value = static_cast(mCore->mDefaultHeight); break; case NATIVE_WINDOW_FORMAT: value = static_cast(mCore->mDefaultBufferFormat); break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: value = mCore->getMinUndequeuedBufferCountLocked(); break; case NATIVE_WINDOW_STICKY_TRANSFORM: value = static_cast(mStickyTransform); break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mCore->mQueue.size() > 1); break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: value = static_cast(mCore->mConsumerUsageBits); break; case NATIVE_WINDOW_DEFAULT_DATASPACE: value = static_cast(mCore->mDefaultBufferDataSpace); break; case NATIVE_WINDOW_BUFFER_AGE: if (mCore->mBufferAge > INT32_MAX) { value = 0; } else { value = static_cast(mCore->mBufferAge); } break; default: return BAD_VALUE; } BQ_LOGV("query: %d? %d", what, value); *outValue = value; return NO_ERROR; } status_t BufferQueueProducer::connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput *output) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; BQ_LOGV("connect: api=%d producerControlledByApp=%s", api, producerControlledByApp ? "true" : "false"); if (mCore->mIsAbandoned) { BQ_LOGE("connect: BufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConsumerListener == NULL) { BQ_LOGE("connect: BufferQueue has no consumer"); return NO_INIT; } if (output == NULL) { BQ_LOGE("connect: output was NULL"); return BAD_VALUE; } if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("connect: already connected (cur=%d req=%d)", mCore->mConnectedApi, api); return BAD_VALUE; } int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, mDequeueTimeout < 0 ? mCore->mConsumerControlledByApp && producerControlledByApp : false, mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked(); if (!mCore->adjustAvailableSlotsLocked(delta)) { BQ_LOGE("connect: BufferQueue failed to adjust the number of available " "slots. Delta = %d", delta); return BAD_VALUE; } int status = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: mCore->mConnectedApi = api; output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, mCore->mTransformHint, static_cast(mCore->mQueue.size())); // Set up a death notification so that we can disconnect // automatically if the remote producer dies if (listener != NULL && IInterface::asBinder(listener)->remoteBinder() != NULL) { status = IInterface::asBinder(listener)->linkToDeath( static_cast(this)); if (status != NO_ERROR) { BQ_LOGE("connect: linkToDeath failed: %s (%d)", strerror(-status), status); } } mCore->mConnectedProducerListener = listener; break; default: BQ_LOGE("connect: unknown API %d", api); status = BAD_VALUE; break; } mCore->mBufferHasBeenQueued = false; mCore->mDequeueBufferCannotBlock = false; if (mDequeueTimeout < 0) { mCore->mDequeueBufferCannotBlock = mCore->mConsumerControlledByApp && producerControlledByApp; } mCore->mAllowAllocation = true; VALIDATE_CONSISTENCY(); return status; } status_t BufferQueueProducer::disconnect(int api) { ATRACE_CALL(); BQ_LOGV("disconnect: api %d", api); int status = NO_ERROR; sp listener; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { // It's not really an error to disconnect after the surface has // been abandoned; it should just be a no-op. return NO_ERROR; } if (api == BufferQueueCore::CURRENTLY_CONNECTED_API) { api = mCore->mConnectedApi; // If we're asked to disconnect the currently connected api but // nobody is connected, it's not really an error. if (api == BufferQueueCore::NO_CONNECTED_API) { return NO_ERROR; } } switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: if (mCore->mConnectedApi == api) { mCore->freeAllBuffersLocked(); // Remove our death notification callback if we have one if (mCore->mConnectedProducerListener != NULL) { sp token = IInterface::asBinder(mCore->mConnectedProducerListener); // This can fail if we're here because of the death // notification, but we just ignore it token->unlinkToDeath( static_cast(this)); } mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; mCore->mConnectedProducerListener = NULL; mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: still connected to another API " "(cur=%d req=%d)", mCore->mConnectedApi, api); status = BAD_VALUE; } break; default: BQ_LOGE("disconnect: unknown API %d", api); status = BAD_VALUE; break; } } // Autolock scope // Call back without lock held if (listener != NULL) { listener->onBuffersReleased(); } return status; } status_t BufferQueueProducer::setSidebandStream(const sp& stream) { sp listener; { // Autolock scope Mutex::Autolock _l(mCore->mMutex); mCore->mSidebandStream = stream; listener = mCore->mConsumerListener; } // Autolock scope if (listener != NULL) { listener->onSidebandStreamChanged(); } return NO_ERROR; } void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; uint32_t allocHeight = 0; PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint32_t allocUsage = 0; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); if (!mCore->mAllowAllocation) { BQ_LOGE("allocateBuffers: allocation is not allowed for this " "BufferQueue"); return; } newBufferCount = mCore->mFreeSlots.size(); if (newBufferCount == 0) { return; } allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; mCore->mIsAllocating = true; } // Autolock scope Vector> buffers; for (size_t i = 0; i < newBufferCount; ++i) { status_t result = NO_ERROR; sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( allocWidth, allocHeight, allocFormat, allocUsage, &result)); if (result != NO_ERROR) { BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" " %u, usage %u)", width, height, format, usage); Mutex::Autolock lock(mCore->mMutex); mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); return; } buffers.push_back(graphicBuffer); } { // Autolock scope Mutex::Autolock lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint32_t checkUsage = usage | mCore->mConsumerUsageBits; if (checkWidth != allocWidth || checkHeight != allocHeight || checkFormat != allocFormat || checkUsage != allocUsage) { // Something changed while we released the lock. Retry. BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying."); mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); continue; } for (size_t i = 0; i < newBufferCount; ++i) { if (mCore->mFreeSlots.empty()) { BQ_LOGV("allocateBuffers: a slot was occupied while " "allocating. Dropping allocated buffer."); continue; } auto slot = mCore->mFreeSlots.begin(); mCore->clearBufferSlotLocked(*slot); // Clean up the slot first mSlots[*slot].mGraphicBuffer = buffers[i]; mSlots[*slot].mFence = Fence::NO_FENCE; // freeBufferLocked puts this slot on the free slots list. Since // we then attached a buffer, move the slot to free buffer list. mCore->mFreeBuffers.push_front(*slot); BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", *slot); // Make sure the erase is done after all uses of the slot // iterator since it will be invalid after this point. mCore->mFreeSlots.erase(slot); } mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); VALIDATE_CONSISTENCY(); } // Autolock scope } } status_t BufferQueueProducer::allowAllocation(bool allow) { ATRACE_CALL(); BQ_LOGV("allowAllocation: %s", allow ? "true" : "false"); Mutex::Autolock lock(mCore->mMutex); mCore->mAllowAllocation = allow; return NO_ERROR; } status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { ATRACE_CALL(); BQ_LOGV("setGenerationNumber: %u", generationNumber); Mutex::Autolock lock(mCore->mMutex); mCore->mGenerationNumber = generationNumber; return NO_ERROR; } String8 BufferQueueProducer::getConsumerName() const { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); BQ_LOGV("getConsumerName: %s", mConsumerName.string()); return mConsumerName; } uint64_t BufferQueueProducer::getNextFrameNumber() const { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); uint64_t nextFrameNumber = mCore->mFrameCounter + 1; return nextFrameNumber; } status_t BufferQueueProducer::setSharedBufferMode(bool sharedBufferMode) { ATRACE_CALL(); BQ_LOGV("setSharedBufferMode: %d", sharedBufferMode); Mutex::Autolock lock(mCore->mMutex); if (!sharedBufferMode) { mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; } mCore->mSharedBufferMode = sharedBufferMode; return NO_ERROR; } status_t BufferQueueProducer::setAutoRefresh(bool autoRefresh) { ATRACE_CALL(); BQ_LOGV("setAutoRefresh: %d", autoRefresh); Mutex::Autolock lock(mCore->mMutex); mCore->mAutoRefresh = autoRefresh; return NO_ERROR; } status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) { ATRACE_CALL(); BQ_LOGV("setDequeueTimeout: %" PRId64, timeout); Mutex::Autolock lock(mCore->mMutex); int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false, mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked(); if (!mCore->adjustAvailableSlotsLocked(delta)) { BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of " "available slots. Delta = %d", delta); return BAD_VALUE; } mDequeueTimeout = timeout; mCore->mDequeueBufferCannotBlock = false; VALIDATE_CONSISTENCY(); return NO_ERROR; } status_t BufferQueueProducer::getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) { ATRACE_CALL(); BQ_LOGV("getLastQueuedBuffer"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) { *outBuffer = nullptr; *outFence = Fence::NO_FENCE; return NO_ERROR; } *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer; *outFence = mLastQueueBufferFence; // Currently only SurfaceFlinger internally ever changes // GLConsumer's filtering mode, so we just use 'true' here as // this is slightly specialized for the current client of this API, // which does want filtering. GLConsumer::computeTransformMatrix(outTransformMatrix, mSlots[mCore->mLastQueuedSlot].mGraphicBuffer, mLastQueuedCrop, mLastQueuedTransform, true /* filter */); return NO_ERROR; } void BufferQueueProducer::binderDied(const wp& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove // this callback upon disconnect. It's therefore safe to read mConnectedApi // without synchronization here. int api = mCore->mConnectedApi; disconnect(api); } status_t BufferQueueProducer::getUniqueId(uint64_t* outId) const { BQ_LOGV("getUniqueId"); *outId = mCore->mUniqueId; return NO_ERROR; } } // namespace android libs/gui/BufferSlot.cpp0100644 0000000 0000000 00000002010 13077405420 014074 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace android { const char* BufferState::string() const { if (isShared()) { return "SHARED"; } if (isFree()) { return "FREE"; } if (isAcquired()) { return "ACQUIRED"; } if (isDequeued()) { return "DEQUEUED"; } if (isQueued()) { return "QUEUED"; } return "UNKNOWN"; } } // namespace android libs/gui/CleanSpec.mk0100644 0000000 0000000 00000004700 13077405420 013513 0ustar000000000 0000000 # Copyright (C) 2012 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. # # If you don't need to do a full clean build but would like to touch # a file or delete some intermediate files, add a clean step to the end # of the list. These steps will only be run once, if they haven't been # run before. # # E.g.: # $(call add-clean-step, touch -c external/sqlite/sqlite3.h) # $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) # # Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with # files that are missing or have been moved. # # Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. # Use $(OUT_DIR) to refer to the "out" directory. # # If you need to re-do something that's already mentioned, just copy # the command and add it to the bottom of the list. E.g., if a change # that you made last week required touching a file and a change you # made today requires touching the same file, just copy the old # touch step and add it to the end of the list. # # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ # For example: #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ $(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates) libs/gui/ConsumerBase.cpp0100644 0000000 0000000 00000025255 13077405420 014427 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #define LOG_TAG "ConsumerBase" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #define EGL_EGLEXT_PROTOTYPES #include #include #include #include #include #include #include #include #include #include #include #include // Macros for including the ConsumerBase name in log messages #define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) #define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { // Get an ID that's unique within this process. static int32_t createProcessUniqueId() { static volatile int32_t globalCounter = 0; return android_atomic_inc(&globalCounter); } ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : mAbandoned(false), mConsumer(bufferQueue) { // Choose a name using the PID and a process-unique ID. mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); // Note that we can't create an sp<...>(this) in a ctor that will not keep a // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. wp listener = static_cast(this); sp proxy = new BufferQueue::ProxyConsumerListener(listener); status_t err = mConsumer->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); } else { mConsumer->setConsumerName(mName); } } ConsumerBase::~ConsumerBase() { CB_LOGV("~ConsumerBase"); Mutex::Autolock lock(mMutex); // Verify that abandon() has been called before we get here. This should // be done by ConsumerBase::onLastStrongRef(), but it's possible for a // derived class to override that method and not call // ConsumerBase::onLastStrongRef(). LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " "consumer is not abandoned!", mName.string()); } void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { abandon(); } void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; mSlots[slotIndex].mFrameNumber = 0; } void ConsumerBase::onFrameAvailable(const BufferItem& item) { CB_LOGV("onFrameAvailable"); sp listener; { // scope for the lock Mutex::Autolock lock(mMutex); listener = mFrameAvailableListener.promote(); } if (listener != NULL) { CB_LOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(item); } } void ConsumerBase::onFrameReplaced(const BufferItem &item) { CB_LOGV("onFrameReplaced"); sp listener; { Mutex::Autolock lock(mMutex); listener = mFrameAvailableListener.promote(); } if (listener != NULL) { CB_LOGV("actually calling onFrameReplaced"); listener->onFrameReplaced(item); } } void ConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); CB_LOGV("onBuffersReleased"); if (mAbandoned) { // Nothing to do if we're already abandoned. return; } uint64_t mask = 0; mConsumer->getReleasedBuffers(&mask); for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { if (mask & (1ULL << i)) { freeBufferLocked(i); } } } void ConsumerBase::onSidebandStreamChanged() { } void ConsumerBase::abandon() { CB_LOGV("abandon"); Mutex::Autolock lock(mMutex); if (!mAbandoned) { abandonLocked(); mAbandoned = true; } } void ConsumerBase::abandonLocked() { CB_LOGV("abandonLocked"); if (mAbandoned) { CB_LOGE("abandonLocked: ConsumerBase is abandoned!"); return; } for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); } // disconnect from the BufferQueue mConsumer->consumerDisconnect(); mConsumer.clear(); } bool ConsumerBase::isAbandoned() { Mutex::Autolock _l(mMutex); return mAbandoned; } void ConsumerBase::setFrameAvailableListener( const wp& listener) { CB_LOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); mFrameAvailableListener = listener; } status_t ConsumerBase::detachBuffer(int slot) { CB_LOGV("detachBuffer"); Mutex::Autolock lock(mMutex); if (mAbandoned) { CB_LOGE("detachBuffer: ConsumerBase is abandoned!"); return NO_INIT; } status_t result = mConsumer->detachBuffer(slot); if (result != NO_ERROR) { CB_LOGE("Failed to detach buffer: %d", result); return result; } freeBufferLocked(slot); return result; } status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mMutex); if (mAbandoned) { CB_LOGE("setDefaultBufferSize: ConsumerBase is abandoned!"); return NO_INIT; } return mConsumer->setDefaultBufferSize(width, height); } status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) { Mutex::Autolock _l(mMutex); if (mAbandoned) { CB_LOGE("setDefaultBufferFormat: ConsumerBase is abandoned!"); return NO_INIT; } return mConsumer->setDefaultBufferFormat(defaultFormat); } status_t ConsumerBase::setDefaultBufferDataSpace( android_dataspace defaultDataSpace) { Mutex::Autolock _l(mMutex); if (mAbandoned) { CB_LOGE("setDefaultBufferDataSpace: ConsumerBase is abandoned!"); return NO_INIT; } return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } status_t ConsumerBase::discardFreeBuffers() { Mutex::Autolock _l(mMutex); if (mAbandoned) { CB_LOGE("discardFreeBuffers: ConsumerBase is abandoned!"); return NO_INIT; } return mConsumer->discardFreeBuffers(); } void ConsumerBase::dump(String8& result) const { dump(result, ""); } void ConsumerBase::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); dumpLocked(result, prefix); } void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); if (!mAbandoned) { mConsumer->dump(result, prefix); } } status_t ConsumerBase::acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber) { if (mAbandoned) { CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!"); return NO_INIT; } status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } if (item->mGraphicBuffer != NULL) { mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; } mSlots[item->mSlot].mFrameNumber = item->mFrameNumber; mSlots[item->mSlot].mFence = item->mFence; CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, item->mSlot, item->mFrameNumber); return OK; } status_t ConsumerBase::addReleaseFence(int slot, const sp graphicBuffer, const sp& fence) { Mutex::Autolock lock(mMutex); return addReleaseFenceLocked(slot, graphicBuffer, fence); } status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp graphicBuffer, const sp& fence) { CB_LOGV("addReleaseFenceLocked: slot=%d", slot); // If consumer no longer tracks this graphicBuffer, we can safely // drop this fence, as it will never be received by the producer. if (!stillTracking(slot, graphicBuffer)) { return OK; } if (!mSlots[slot].mFence.get()) { mSlots[slot].mFence = fence; } else { sp mergedFence = Fence::merge( String8::format("%.28s:%d", mName.string(), slot), mSlots[slot].mFence, fence); if (!mergedFence.get()) { CB_LOGE("failed to merge release fences"); // synchronization is broken, the best we can do is hope fences // signal in order so the new fence will act like a union mSlots[slot].mFence = fence; return BAD_VALUE; } mSlots[slot].mFence = mergedFence; } return OK; } status_t ConsumerBase::releaseBufferLocked( int slot, const sp graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence) { if (mAbandoned) { CB_LOGE("releaseBufferLocked: ConsumerBase is abandoned!"); return NO_INIT; } // If consumer no longer tracks this graphicBuffer (we received a new // buffer on the same slot), the buffer producer is definitely no longer // tracking it. if (!stillTracking(slot, graphicBuffer)) { return OK; } CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64, slot, mSlots[slot].mFrameNumber); status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, display, eglFence, mSlots[slot].mFence); if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) { freeBufferLocked(slot); } mSlots[slot].mFence = Fence::NO_FENCE; return err; } bool ConsumerBase::stillTracking(int slot, const sp graphicBuffer) { if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { return false; } return (mSlots[slot].mGraphicBuffer != NULL && mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); } } // namespace android libs/gui/CpuConsumer.cpp0100644 0000000 0000000 00000021146 13077405420 014277 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) #define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) #define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { CpuConsumer::CpuConsumer(const sp& bq, size_t maxLockedBuffers, bool controlledByApp) : ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0) { // Create tracking entries for locked buffers mAcquiredBuffers.insertAt(0, maxLockedBuffers); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); mConsumer->setMaxAcquiredBufferCount(static_cast(maxLockedBuffers)); } CpuConsumer::~CpuConsumer() { // ConsumerBase destructor does all the work. } void CpuConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); if (mAbandoned) { CC_LOGE("setName: CpuConsumer is abandoned!"); return; } mName = name; mConsumer->setConsumerName(name); } static bool isPossiblyYUV(PixelFormat format) { switch (static_cast(format)) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_Y8: case HAL_PIXEL_FORMAT_Y16: case HAL_PIXEL_FORMAT_RAW16: case HAL_PIXEL_FORMAT_RAW10: case HAL_PIXEL_FORMAT_RAW_OPAQUE: case HAL_PIXEL_FORMAT_BLOB: case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return false; case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCbCr_420_888: case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: default: return true; } } status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; if (!nativeBuffer) return BAD_VALUE; if (mCurrentLockedBuffers == mMaxLockedBuffers) { CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); return NOT_ENOUGH_DATA; } BufferItem b; Mutex::Autolock _l(mMutex); err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { return BAD_VALUE; } else { CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); return err; } } int slot = b.mSlot; void *bufferPointer = NULL; android_ycbcr ycbcr = android_ycbcr(); PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); PixelFormat flexFormat = format; if (isPossiblyYUV(format)) { if (b.mFence.get()) { err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &ycbcr, b.mFence->dup()); } else { err = mSlots[slot].mGraphicBuffer->lockYCbCr( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &ycbcr); } if (err == OK) { bufferPointer = ycbcr.y; flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { CC_LOGV("locking buffer of format %#x as flex YUV", format); } } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); return err; } } if (bufferPointer == NULL) { // not flexible YUV if (b.mFence.get()) { err = mSlots[slot].mGraphicBuffer->lockAsync( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &bufferPointer, b.mFence->dup()); } else { err = mSlots[slot].mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_READ_OFTEN, b.mCrop, &bufferPointer); } if (err != OK) { CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); return err; } } size_t lockedIdx = 0; for (; lockedIdx < static_cast(mMaxLockedBuffers); lockedIdx++) { if (mAcquiredBuffers[lockedIdx].mSlot == BufferQueue::INVALID_BUFFER_SLOT) { break; } } assert(lockedIdx < mMaxLockedBuffers); AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); ab.mSlot = slot; ab.mBufferPointer = bufferPointer; ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; nativeBuffer->data = reinterpret_cast(bufferPointer); nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); nativeBuffer->format = format; nativeBuffer->flexFormat = flexFormat; nativeBuffer->stride = (ycbcr.y != NULL) ? static_cast(ycbcr.ystride) : mSlots[slot].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; nativeBuffer->scalingMode = b.mScalingMode; nativeBuffer->timestamp = b.mTimestamp; nativeBuffer->dataSpace = b.mDataSpace; nativeBuffer->frameNumber = b.mFrameNumber; nativeBuffer->dataCb = reinterpret_cast(ycbcr.cb); nativeBuffer->dataCr = reinterpret_cast(ycbcr.cr); nativeBuffer->chromaStride = static_cast(ycbcr.cstride); nativeBuffer->chromaStep = static_cast(ycbcr.chroma_step); mCurrentLockedBuffers++; return OK; } status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); size_t lockedIdx = 0; void *bufPtr = reinterpret_cast(nativeBuffer.data); for (; lockedIdx < static_cast(mMaxLockedBuffers); lockedIdx++) { if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; } if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } return releaseAcquiredBufferLocked(lockedIdx); } status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { status_t err; int fd = -1; err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } int buf = mAcquiredBuffers[lockedIdx].mSlot; if (CC_LIKELY(fd != -1)) { sp fence(new Fence(fd)); addReleaseFenceLocked( mAcquiredBuffers[lockedIdx].mSlot, mSlots[buf].mGraphicBuffer, fence); } // release the buffer if it hasn't already been freed by the BufferQueue. // This can happen, for example, when the producer of this buffer // disconnected after this buffer was acquired. if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == mSlots[buf].mGraphicBuffer)) { releaseBufferLocked( buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; ab.mBufferPointer = NULL; ab.mGraphicBuffer.clear(); mCurrentLockedBuffers--; return OK; } void CpuConsumer::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); } } // namespace android libs/gui/DisplayEventReceiver.cpp0100644 0000000 0000000 00000005274 13077405420 016134 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- DisplayEventReceiver::DisplayEventReceiver() { sp sf(ComposerService::getComposerService()); if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(); if (mEventConnection != NULL) { mDataChannel = mEventConnection->getDataChannel(); } } } DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); } status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { if (int32_t(count) < 0) return BAD_VALUE; if (mEventConnection != NULL) { mEventConnection->setVsyncRate(count); return NO_ERROR; } return NO_INIT; } status_t DisplayEventReceiver::requestNextVsync() { if (mEventConnection != NULL) { mEventConnection->requestNextVsync(); return NO_ERROR; } return NO_INIT; } ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, size_t count) { return DisplayEventReceiver::getEvents(mDataChannel, events, count); } ssize_t DisplayEventReceiver::getEvents(const sp& dataChannel, Event* events, size_t count) { return BitTube::recvObjects(dataChannel, events, count); } ssize_t DisplayEventReceiver::sendEvents(const sp& dataChannel, Event const* events, size_t count) { return BitTube::sendObjects(dataChannel, events, count); } // --------------------------------------------------------------------------- }; // namespace android libs/gui/GLConsumer.cpp0100644 0000000 0000000 00000124323 13077405420 014053 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "GLConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 namespace android { // Macros for including the GLConsumer name in log messages #define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) #define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) #define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) #define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) static const struct { uint32_t width, height; char const* bits; } kDebugData = { 15, 12, "_______________" "_______________" "_____XX_XX_____" "__X_X_____X_X__" "__X_XXXXXXX_X__" "__XXXXXXXXXXX__" "___XX_XXX_XX___" "____XXXXXXX____" "_____X___X_____" "____X_____X____" "_______________" "_______________" }; // Transform matrices static float mtxIdentity[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }; static float mtxFlipH[16] = { -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, }; static float mtxFlipV[16] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, }; static float mtxRot90[16] = { 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, }; static void mtxMul(float out[16], const float a[16], const float b[16]); Mutex GLConsumer::sStaticInitLock; sp GLConsumer::sReleasedTexImageBuffer; static bool hasEglAndroidImageCropImpl() { EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); size_t cropExtLen = strlen(CROP_EXT_STR); size_t extsLen = strlen(exts); bool equal = !strcmp(CROP_EXT_STR, exts); bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1); bool atEnd = (cropExtLen+1) < extsLen && !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1)); bool inMiddle = strstr(exts, " " CROP_EXT_STR " "); return equal || atStart || atEnd || inMiddle; } static bool hasEglAndroidImageCrop() { // Only compute whether the extension is present once the first time this // function is called. static bool hasIt = hasEglAndroidImageCropImpl(); return hasIt; } static bool hasEglProtectedContentImpl() { EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR); size_t extsLen = strlen(exts); bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts); bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1); bool atEnd = (cropExtLen+1) < extsLen && !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen+1)); bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " "); return equal || atStart || atEnd || inMiddle; } static bool hasEglProtectedContent() { // Only compute whether the extension is present once the first time this // function is called. static bool hasIt = hasEglProtectedContentImpl(); return hasIt; } static bool isEglImageCroppable(const Rect& crop) { return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0); } GLConsumer::GLConsumer(const sp& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), mCurrentCrop(Rect::EMPTY_RECT), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), mCurrentFrameNumber(0), mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), mTexName(tex), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } GLConsumer::GLConsumer(const sp& bq, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), mCurrentCrop(Rect::EMPTY_RECT), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), mCurrentFrameNumber(0), mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), mTexName(0), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(false) { GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setDefaultBufferSize: GLConsumer is abandoned!"); return NO_INIT; } mDefaultWidth = w; mDefaultHeight = h; return mConsumer->setDefaultBufferSize(w, h); } status_t GLConsumer::updateTexImage() { ATRACE_CALL(); GLC_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("updateTexImage: GLConsumer is abandoned!"); return NO_INIT; } // Make sure the EGL state is the same as in previous calls. status_t err = checkAndUpdateEglStateLocked(); if (err != NO_ERROR) { return err; } BufferItem item; // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. err = acquireBufferLocked(&item, 0); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // We always bind the texture even if we don't update its contents. GLC_LOGV("updateTexImage: no buffers were available"); glBindTexture(mTexTarget, mTexName); err = NO_ERROR; } else { GLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); } return err; } // Release the previous buffer. err = updateAndReleaseLocked(item); if (err != NO_ERROR) { // We always bind the texture. glBindTexture(mTexTarget, mTexName); return err; } // Bind the new buffer to the GL texture, and wait until it's ready. return bindTextureImageLocked(); } status_t GLConsumer::releaseTexImage() { ATRACE_CALL(); GLC_LOGV("releaseTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("releaseTexImage: GLConsumer is abandoned!"); return NO_INIT; } // Make sure the EGL state is the same as in previous calls. status_t err = NO_ERROR; if (mAttached) { err = checkAndUpdateEglStateLocked(true); if (err != NO_ERROR) { return err; } } else { // if we're detached, no need to validate EGL's state -- we won't use it. } // Update the GLConsumer state. int buf = mCurrentTexture; if (buf != BufferQueue::INVALID_BUFFER_SLOT) { GLC_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); if (mAttached) { // Do whatever sync ops we need to do before releasing the slot. err = syncForReleaseLocked(mEglDisplay); if (err != NO_ERROR) { GLC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); return err; } } else { // if we're detached, we just use the fence that was created in detachFromContext() // so... basically, nothing more to do here. } err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); if (err < NO_ERROR) { GLC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err); return err; } if (mReleasedTexImage == NULL) { mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); } mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; mCurrentTextureImage = mReleasedTexImage; mCurrentCrop.makeInvalid(); mCurrentTransform = 0; mCurrentTimestamp = 0; mCurrentFence = Fence::NO_FENCE; if (mAttached) { // This binds a dummy buffer (mReleasedTexImage). status_t result = bindTextureImageLocked(); if (result != NO_ERROR) { return result; } } else { // detached, don't touch the texture (and we may not even have an // EGLDisplay here. } } return NO_ERROR; } sp GLConsumer::getDebugTexImageBuffer() { Mutex::Autolock _l(sStaticInitLock); if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) { // The first time, create the debug texture in case the application // continues to use it. sp buffer = new GraphicBuffer( kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_WRITE_RARELY); uint32_t* bits; buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast(&bits)); uint32_t stride = buffer->getStride(); uint32_t height = buffer->getHeight(); memset(bits, 0, stride * height * 4); for (uint32_t y = 0; y < kDebugData.height; y++) { for (uint32_t x = 0; x < kDebugData.width; x++) { bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000 : 0xFFFFFFFF; } bits += stride; } buffer->unlock(); sReleasedTexImageBuffer = buffer; } return sReleasedTexImageBuffer; } status_t GLConsumer::acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber) { status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } // If item->mGraphicBuffer is not null, this buffer has not been acquired // before, so any prior EglImage created is using a stale buffer. This // replaces any old EglImage with a new one (using the new buffer). if (item->mGraphicBuffer != NULL) { int slot = item->mSlot; mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); } return NO_ERROR; } status_t GLConsumer::releaseBufferLocked(int buf, sp graphicBuffer, EGLDisplay display, EGLSyncKHR eglFence) { // release the buffer if it hasn't already been discarded by the // BufferQueue. This can happen, for example, when the producer of this // buffer has reallocated the original buffer slot after this buffer // was acquired. status_t err = ConsumerBase::releaseBufferLocked( buf, graphicBuffer, display, eglFence); mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; return err; } status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease) { status_t err = NO_ERROR; int slot = item.mSlot; if (!mAttached) { GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return INVALID_OPERATION; } // Confirm state. err = checkAndUpdateEglStateLocked(); if (err != NO_ERROR) { releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return err; } // Ensure we have a valid EglImageKHR for the slot, creating an EglImage // if nessessary, for the gralloc buffer currently in the slot in // ConsumerBase. // We may have to do this even when item.mGraphicBuffer == NULL (which // means the buffer was previously acquired). err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); if (err != NO_ERROR) { GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, slot); releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return UNKNOWN_ERROR; } // Do whatever sync ops we need to do before releasing the old slot. if (slot != mCurrentTexture) { err = syncForReleaseLocked(mEglDisplay); if (err != NO_ERROR) { // Release the buffer we just acquired. It's not safe to // release the old buffer, so instead we just drop the new frame. // As we are still under lock since acquireBuffer, it is safe to // release by slot. releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); return err; } } GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot, mSlots[slot].mGraphicBuffer->handle); // Hang onto the pointer so that it isn't freed in the call to // releaseBufferLocked() if we're in shared buffer mode and both buffers are // the same. sp nextTextureImage = mEglSlots[slot].mEglImage; // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { status_t status = releaseBufferLocked( mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); if (status < NO_ERROR) { GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); err = status; // keep going, with error raised [?] } } else { pendingRelease->currentTexture = mCurrentTexture; pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer(); pendingRelease->display = mEglDisplay; pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence; pendingRelease->isPending = true; } } // Update the GLConsumer state. mCurrentTexture = slot; mCurrentTextureImage = nextTextureImage; mCurrentCrop = item.mCrop; mCurrentTransform = item.mTransform; mCurrentScalingMode = item.mScalingMode; mCurrentTimestamp = item.mTimestamp; mCurrentFence = item.mFence; mCurrentFrameNumber = item.mFrameNumber; computeCurrentTransformMatrixLocked(); return err; } status_t GLConsumer::bindTextureImageLocked() { if (mEglDisplay == EGL_NO_DISPLAY) { ALOGE("bindTextureImage: invalid display"); return INVALID_OPERATION; } GLenum error; while ((error = glGetError()) != GL_NO_ERROR) { GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error); } glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) { GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop); if (err != NO_ERROR) { GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } mCurrentTextureImage->bindToTextureTarget(mTexTarget); // In the rare case that the display is terminated and then initialized // again, we can't detect that the display changed (it didn't), but the // image is invalid. In this case, repeat the exact same steps while // forcing the creation of a new image. if ((error = glGetError()) != GL_NO_ERROR) { glBindTexture(mTexTarget, mTexName); status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop, true); if (result != NO_ERROR) { GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } mCurrentTextureImage->bindToTextureTarget(mTexTarget); if ((error = glGetError()) != GL_NO_ERROR) { GLC_LOGE("bindTextureImage: error binding external image: %#04x", error); return UNKNOWN_ERROR; } } // Wait for the new buffer to be ready. return doGLFenceWaitLocked(); } status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { EGLDisplay dpy = eglGetCurrentDisplay(); EGLContext ctx = eglGetCurrentContext(); if (!contextCheck) { // if this is the first time we're called, mEglDisplay/mEglContext have // never been set, so don't error out (below). if (mEglDisplay == EGL_NO_DISPLAY) { mEglDisplay = dpy; } if (mEglContext == EGL_NO_CONTEXT) { mEglContext = ctx; } } if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { GLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { GLC_LOGE("checkAndUpdateEglState: invalid current EGLContext"); return INVALID_OPERATION; } mEglDisplay = dpy; mEglContext = ctx; return NO_ERROR; } void GLConsumer::setReleaseFence(const sp& fence) { if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { status_t err = addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { GLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); } } } status_t GLConsumer::detachFromContext() { ATRACE_CALL(); GLC_LOGV("detachFromContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("detachFromContext: abandoned GLConsumer"); return NO_INIT; } if (!mAttached) { GLC_LOGE("detachFromContext: GLConsumer is not attached to a " "context"); return INVALID_OPERATION; } EGLDisplay dpy = eglGetCurrentDisplay(); EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { GLC_LOGE("detachFromContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { GLC_LOGE("detachFromContext: invalid current EGLContext"); return INVALID_OPERATION; } if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) { status_t err = syncForReleaseLocked(dpy); if (err != OK) { return err; } glDeleteTextures(1, &mTexName); } mEglDisplay = EGL_NO_DISPLAY; mEglContext = EGL_NO_CONTEXT; mAttached = false; return OK; } status_t GLConsumer::attachToContext(uint32_t tex) { ATRACE_CALL(); GLC_LOGV("attachToContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("attachToContext: abandoned GLConsumer"); return NO_INIT; } if (mAttached) { GLC_LOGE("attachToContext: GLConsumer is already attached to a " "context"); return INVALID_OPERATION; } EGLDisplay dpy = eglGetCurrentDisplay(); EGLContext ctx = eglGetCurrentContext(); if (dpy == EGL_NO_DISPLAY) { GLC_LOGE("attachToContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (ctx == EGL_NO_CONTEXT) { GLC_LOGE("attachToContext: invalid current EGLContext"); return INVALID_OPERATION; } // We need to bind the texture regardless of whether there's a current // buffer. glBindTexture(mTexTarget, GLuint(tex)); mEglDisplay = dpy; mEglContext = ctx; mTexName = tex; mAttached = true; if (mCurrentTextureImage != NULL) { // This may wait for a buffer a second time. This is likely required if // this is a different context, since otherwise the wait could be skipped // by bouncing through another context. For the same context the extra // wait is redundant. status_t err = bindTextureImageLocked(); if (err != NO_ERROR) { return err; } } return OK; } status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { GLC_LOGV("syncForReleaseLocked"); if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); eglDestroySyncKHR(dpy, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { GLC_LOGE("syncForReleaseLocked: error dup'ing native fence " "fd: %#x", eglGetError()); return UNKNOWN_ERROR; } sp fence(new Fence(fenceFd)); status_t err = addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { GLC_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); return err; } } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to // wait on that before replacing it with another fence to // ensure that all outstanding buffer accesses have completed // before the producer accesses it. EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); if (result == EGL_FALSE) { GLC_LOGE("syncForReleaseLocked: error waiting for previous " "fence: %#x", eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { GLC_LOGE("syncForReleaseLocked: timeout waiting for previous " "fence"); return TIMED_OUT; } eglDestroySyncKHR(dpy, fence); } // Create a fence for the outstanding accesses in the current // OpenGL ES context. fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); mEglSlots[mCurrentTexture].mEglFence = fence; } } return OK; } bool GLConsumer::isExternalFormat(PixelFormat format) { switch (format) { // supported YUV formats case HAL_PIXEL_FORMAT_YV12: // Legacy/deprecated YUV formats case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: return true; } // Any OEM format needs to be considered if (format>=0x100 && format<=0x1FF) return true; return false; } uint32_t GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } void GLConsumer::getTransformMatrix(float mtx[16]) { Mutex::Autolock lock(mMutex); memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); } void GLConsumer::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); return; } bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; if (needsRecompute && mCurrentTextureImage==NULL) { GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } if (needsRecompute && mCurrentTextureImage != NULL) { computeCurrentTransformMatrixLocked(); } } void GLConsumer::computeCurrentTransformMatrixLocked() { GLC_LOGV("computeCurrentTransformMatrixLocked"); sp buf = (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer(); if (buf == nullptr) { GLC_LOGD("computeCurrentTransformMatrixLocked: " "mCurrentTextureImage is NULL"); } computeTransformMatrix(mCurrentTransformMatrix, buf, isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop, mCurrentTransform, mFilteringEnabled); } void GLConsumer::computeTransformMatrix(float outTransform[16], const sp& buf, const Rect& cropRect, uint32_t transform, bool filtering) { float xform[16]; for (int i = 0; i < 16; i++) { xform[i] = mtxIdentity[i]; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { float result[16]; mtxMul(result, xform, mtxFlipH); for (int i = 0; i < 16; i++) { xform[i] = result[i]; } } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { float result[16]; mtxMul(result, xform, mtxFlipV); for (int i = 0; i < 16; i++) { xform[i] = result[i]; } } if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { float result[16]; mtxMul(result, xform, mtxRot90); for (int i = 0; i < 16; i++) { xform[i] = result[i]; } } float mtxBeforeFlipV[16]; if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; float bufferWidth = buf->getWidth(); float bufferHeight = buf->getHeight(); float shrinkAmount = 0.0f; if (filtering) { // In order to prevent bilinear sampling beyond the edge of the // crop rectangle we may need to shrink it by 2 texels in each // dimension. Normally this would just need to take 1/2 a texel // off each end, but because the chroma channels of YUV420 images // are subsampled we may need to shrink the crop region by a whole // texel on each side. switch (buf->getPixelFormat()) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_RGB_888: case PIXEL_FORMAT_RGB_565: case PIXEL_FORMAT_BGRA_8888: // We know there's no subsampling of any channels, so we // only need to shrink by a half a pixel. shrinkAmount = 0.5; break; default: // If we don't recognize the format, we must assume the // worst case (that we care about), which is YUV420. shrinkAmount = 1.0; break; } } // Only shrink the dimensions that are not the size of the buffer. if (cropRect.width() < bufferWidth) { tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; } if (cropRect.height() < bufferHeight) { ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; } float crop[16] = { sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1, }; mtxMul(mtxBeforeFlipV, crop, xform); } else { for (int i = 0; i < 16; i++) { mtxBeforeFlipV[i] = xform[i]; } } // SurfaceFlinger expects the top of its window textures to be at a Y // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV); } nsecs_t GLConsumer::getTimestamp() { GLC_LOGV("getTimestamp"); Mutex::Autolock lock(mMutex); return mCurrentTimestamp; } uint64_t GLConsumer::getFrameNumber() { GLC_LOGV("getFrameNumber"); Mutex::Autolock lock(mMutex); return mCurrentFrameNumber; } sp GLConsumer::getCurrentBuffer() const { Mutex::Autolock lock(mMutex); return (mCurrentTextureImage == NULL) ? NULL : mCurrentTextureImage->graphicBuffer(); } Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); Rect outCrop = mCurrentCrop; if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { uint32_t newWidth = static_cast(mCurrentCrop.width()); uint32_t newHeight = static_cast(mCurrentCrop.height()); if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { newWidth = newHeight * mDefaultWidth / mDefaultHeight; GLC_LOGV("too wide: newWidth = %d", newWidth); } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { newHeight = newWidth * mDefaultHeight / mDefaultWidth; GLC_LOGV("too tall: newHeight = %d", newHeight); } uint32_t currentWidth = static_cast(mCurrentCrop.width()); uint32_t currentHeight = static_cast(mCurrentCrop.height()); // The crop is too wide if (newWidth < currentWidth) { uint32_t dw = currentWidth - newWidth; auto halfdw = dw / 2; outCrop.left += halfdw; // Not halfdw because it would subtract 1 too few when dw is odd outCrop.right -= (dw - halfdw); // The crop is too tall } else if (newHeight < currentHeight) { uint32_t dh = currentHeight - newHeight; auto halfdh = dh / 2; outCrop.top += halfdh; // Not halfdh because it would subtract 1 too few when dh is odd outCrop.bottom -= (dh - halfdh); } GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,outCrop.bottom); } return outCrop; } uint32_t GLConsumer::getCurrentTransform() const { Mutex::Autolock lock(mMutex); return mCurrentTransform; } uint32_t GLConsumer::getCurrentScalingMode() const { Mutex::Autolock lock(mMutex); return mCurrentScalingMode; } sp GLConsumer::getCurrentFence() const { Mutex::Autolock lock(mMutex); return mCurrentFence; } status_t GLConsumer::doGLFenceWait() const { Mutex::Autolock lock(mMutex); return doGLFenceWaitLocked(); } status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { GLC_LOGE("doGLFenceWait: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { GLC_LOGE("doGLFenceWait: invalid current EGLContext"); return INVALID_OPERATION; } if (mCurrentFence->isValid()) { if (SyncFeatures::getInstance().useWaitSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { GLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); return -errno; } EGLint attribs[] = { EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE }; EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { close(fenceFd); GLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } // XXX: The spec draft is inconsistent as to whether this should // return an EGLint or void. Ignore the return value for now, as // it's not strictly needed. eglWaitSyncKHR(dpy, sync, 0); EGLint eglErr = eglGetError(); eglDestroySyncKHR(dpy, sync); if (eglErr != EGL_SUCCESS) { GLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr); return UNKNOWN_ERROR; } } else { status_t err = mCurrentFence->waitForever( "GLConsumer::doGLFenceWaitLocked"); if (err != NO_ERROR) { GLC_LOGE("doGLFenceWait: error waiting for fence: %d", err); return err; } } } return NO_ERROR; } void GLConsumer::freeBufferLocked(int slotIndex) { GLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); if (slotIndex == mCurrentTexture) { mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; } mEglSlots[slotIndex].mEglImage.clear(); ConsumerBase::freeBufferLocked(slotIndex); } void GLConsumer::abandonLocked() { GLC_LOGV("abandonLocked"); mCurrentTextureImage.clear(); ConsumerBase::abandonLocked(); } void GLConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); if (mAbandoned) { GLC_LOGE("setName: GLConsumer is abandoned!"); return; } mName = name; mConsumer->setConsumerName(name); } status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!"); return NO_INIT; } return mConsumer->setDefaultBufferFormat(defaultFormat); } status_t GLConsumer::setDefaultBufferDataSpace( android_dataspace defaultDataSpace) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!"); return NO_INIT; } return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); return NO_INIT; } usage |= DEFAULT_USAGE_FLAGS; return mConsumer->setConsumerUsageBits(usage); } status_t GLConsumer::setTransformHint(uint32_t hint) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setTransformHint: GLConsumer is abandoned!"); return NO_INIT; } return mConsumer->setTransformHint(hint); } status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { Mutex::Autolock lock(mMutex); if (mAbandoned) { GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!"); return NO_INIT; } return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const { result.appendFormat( "%smTexName=%d mCurrentTexture=%d\n" "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); ConsumerBase::dumpLocked(result, prefix); } static void mtxMul(float out[16], const float a[16], const float b[16]) { out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; } GLConsumer::EglImage::EglImage(sp graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY), mCropRect(Rect::EMPTY_RECT) { } GLConsumer::EglImage::~EglImage() { if (mEglImage != EGL_NO_IMAGE_KHR) { if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("~EglImage: eglDestroyImageKHR failed"); } eglTerminate(mEglDisplay); } } status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, const Rect& cropRect, bool forceCreation) { // If there's an image and it's no longer valid, destroy it. bool haveImage = mEglImage != EGL_NO_IMAGE_KHR; bool displayInvalid = mEglDisplay != eglDisplay; bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect; if (haveImage && (displayInvalid || cropInvalid || forceCreation)) { if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("createIfNeeded: eglDestroyImageKHR failed"); } eglTerminate(mEglDisplay); mEglImage = EGL_NO_IMAGE_KHR; mEglDisplay = EGL_NO_DISPLAY; } // If there's no image, create one. if (mEglImage == EGL_NO_IMAGE_KHR) { mEglDisplay = eglDisplay; mCropRect = cropRect; mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect); } // Fail if we can't create a valid image. if (mEglImage == EGL_NO_IMAGE_KHR) { mEglDisplay = EGL_NO_DISPLAY; mCropRect.makeInvalid(); const sp& buffer = mGraphicBuffer; ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d", buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), buffer->getPixelFormat()); return UNKNOWN_ERROR; } return OK; } void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { glEGLImageTargetTexture2DOES(texTarget, static_cast(mEglImage)); } EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, const sp& graphicBuffer, const Rect& crop) { EGLClientBuffer cbuf = static_cast(graphicBuffer->getNativeBuffer()); const bool createProtectedImage = (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent(); EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_IMAGE_CROP_LEFT_ANDROID, crop.left, EGL_IMAGE_CROP_TOP_ANDROID, crop.top, EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right, EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom, createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, createProtectedImage ? EGL_TRUE : EGL_NONE, EGL_NONE, }; if (!crop.isValid()) { // No crop rect to set, so terminate the attrib array before the crop. attrs[2] = EGL_NONE; } else if (!isEglImageCroppable(crop)) { // The crop rect is not at the origin, so we can't set the crop on the // EGLImage because that's not allowed by the EGL_ANDROID_image_crop // extension. In the future we can add a layered extension that // removes this restriction if there is hardware that can support it. attrs[2] = EGL_NONE; } eglInitialize(dpy, 0, 0); EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); if (image == EGL_NO_IMAGE_KHR) { EGLint error = eglGetError(); ALOGE("error creating EGLImage: %#x", error); eglTerminate(dpy); } return image; } }; // namespace android libs/gui/GraphicBufferAlloc.cpp0100644 0000000 0000000 00000003526 13077405420 015520 0ustar000000000 0000000 /* ** ** Copyright 2012 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 #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- GraphicBufferAlloc::GraphicBufferAlloc() { } GraphicBufferAlloc::~GraphicBufferAlloc() { } sp GraphicBufferAlloc::createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, status_t* error) { sp graphicBuffer( new GraphicBuffer(width, height, format, usage)); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) { if (err == NO_MEMORY) { GraphicBuffer::dumpAllocationsToSystemLog(); } ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", width, height, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- libs/gui/GuiConfig.cpp0100644 0000000 0000000 00000001625 13077405420 013706 0ustar000000000 0000000 /* * Copyright (C) 2012 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 namespace android { void appendGuiConfigString(String8& configStr) { static const char* config = " [libgui" #ifdef DONT_USE_FENCE_SYNC " DONT_USE_FENCE_SYNC" #endif "]"; configStr.append(config); } }; // namespace android libs/gui/IConsumerListener.cpp0100644 0000000 0000000 00000006425 13077405420 015451 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- enum { ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION, ON_BUFFER_RELEASED, ON_SIDEBAND_STREAM_CHANGED, }; class BpConsumerListener : public BpInterface { public: BpConsumerListener(const sp& impl) : BpInterface(impl) { } virtual ~BpConsumerListener(); virtual void onFrameAvailable(const BufferItem& item) { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); data.write(item); remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY); } virtual void onBuffersReleased() { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY); } virtual void onSidebandStreamChanged() { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpConsumerListener::~BpConsumerListener() {} IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); // ---------------------------------------------------------------------- status_t BnConsumerListener::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case ON_FRAME_AVAILABLE: { CHECK_INTERFACE(IConsumerListener, data, reply); BufferItem item; data.read(item); onFrameAvailable(item); return NO_ERROR; } case ON_BUFFER_RELEASED: { CHECK_INTERFACE(IConsumerListener, data, reply); onBuffersReleased(); return NO_ERROR; } case ON_SIDEBAND_STREAM_CHANGED: { CHECK_INTERFACE(IConsumerListener, data, reply); onSidebandStreamChanged(); return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- libs/gui/IDisplayEventConnection.cpp0100644 0000000 0000000 00000006437 13077405420 016602 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- enum { GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, SET_VSYNC_RATE, REQUEST_NEXT_VSYNC }; class BpDisplayEventConnection : public BpInterface { public: BpDisplayEventConnection(const sp& impl) : BpInterface(impl) { } virtual ~BpDisplayEventConnection(); virtual sp getDataChannel() const { Parcel data, reply; data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); remote()->transact(GET_DATA_CHANNEL, data, &reply); return new BitTube(reply); } virtual void setVsyncRate(uint32_t count) { Parcel data, reply; data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); data.writeUint32(count); remote()->transact(SET_VSYNC_RATE, data, &reply); } virtual void requestNextVsync() { Parcel data, reply; data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpDisplayEventConnection::~BpDisplayEventConnection() {} IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection"); // ---------------------------------------------------------------------------- status_t BnDisplayEventConnection::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case GET_DATA_CHANNEL: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); sp channel(getDataChannel()); channel->writeToParcel(reply); return NO_ERROR; } case SET_VSYNC_RATE: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); setVsyncRate(data.readUint32()); return NO_ERROR; } case REQUEST_NEXT_VSYNC: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); requestNextVsync(); return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/IGraphicBufferAlloc.cpp0100644 0000000 0000000 00000010440 13077405420 015622 0ustar000000000 0000000 /* * 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. */ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { enum { CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, }; class BpGraphicBufferAlloc : public BpInterface { public: BpGraphicBufferAlloc(const sp& impl) : BpInterface(impl) { } virtual ~BpGraphicBufferAlloc(); virtual sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast(format)); data.writeUint32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp graphicBuffer; status_t result = reply.readInt32(); if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); result = reply.read(*graphicBuffer); if (result != NO_ERROR) { graphicBuffer.clear(); } // reply.readStrongBinder(); // here we don't even have to read the BufferReference from // the parcel, it'll die with the parcel. } *error = result; return graphicBuffer; } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {} IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); // ---------------------------------------------------------------------- status_t BnGraphicBufferAlloc::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // codes that don't require permission check // BufferReference just keeps a strong reference to a GraphicBuffer until it // is destroyed (that is, until no local or remote process have a reference // to it). class BufferReference : public BBinder { sp mBuffer; public: BufferReference(const sp& buffer) : mBuffer(buffer) {} }; switch (code) { case CREATE_GRAPHIC_BUFFER: { CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast(data.readInt32()); uint32_t usage = data.readUint32(); status_t error; sp result = createGraphicBuffer(width, height, format, usage, &error); reply->writeInt32(error); if (result != 0) { reply->write(*result); // We add a BufferReference to this parcel to make sure the // buffer stays alive until the GraphicBuffer object on // the other side has been created. // This is needed so that the buffer handle can be // registered before the buffer is destroyed on implementations // that do not use file-descriptors to track their buffers. reply->writeStrongBinder( new BufferReference(result) ); } return NO_ERROR; } default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/gui/IGraphicBufferConsumer.cpp0100644 0000000 0000000 00000040241 13077405420 016365 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include #include #include #include #include #include #include #include namespace android { enum { ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, DETACH_BUFFER, ATTACH_BUFFER, RELEASE_BUFFER, CONSUMER_CONNECT, CONSUMER_DISCONNECT, GET_RELEASED_BUFFERS, SET_DEFAULT_BUFFER_SIZE, SET_MAX_BUFFER_COUNT, SET_MAX_ACQUIRED_BUFFER_COUNT, SET_CONSUMER_NAME, SET_DEFAULT_BUFFER_FORMAT, SET_DEFAULT_BUFFER_DATA_SPACE, SET_CONSUMER_USAGE_BITS, SET_TRANSFORM_HINT, GET_SIDEBAND_STREAM, DISCARD_FREE_BUFFERS, DUMP, }; class BpGraphicBufferConsumer : public BpInterface { public: BpGraphicBufferConsumer(const sp& impl) : BpInterface(impl) { } virtual ~BpGraphicBufferConsumer(); virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen, uint64_t maxFrameNumber) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt64(presentWhen); data.writeUint64(maxFrameNumber); status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } result = reply.read(*buffer); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t detachBuffer(int slot) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(slot); status_t result = remote()->transact(DETACH_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t attachBuffer(int* slot, const sp& buffer) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.write(*buffer.get()); status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } *slot = reply.readInt32(); result = reply.readInt32(); return result; } virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)), const sp& releaseFence) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(buf); data.writeInt64(static_cast(frameNumber)); data.write(*releaseFence); status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(consumer)); data.writeInt32(controlledByApp); status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t consumerDisconnect() { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t getReleasedBuffers(uint64_t* slotMask) { Parcel data, reply; if (slotMask == NULL) { ALOGE("getReleasedBuffers: slotMask must not be NULL"); return BAD_VALUE; } data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); if (result != NO_ERROR) { return result; } *slotMask = static_cast(reply.readInt64()); return reply.readInt32(); } virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeUint32(width); data.writeUint32(height); status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t setMaxBufferCount(int bufferCount) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(bufferCount); status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(maxAcquiredBuffers); status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual void setConsumerName(const String8& name) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeString8(name); remote()->transact(SET_CONSUMER_NAME, data, &reply); } virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(static_cast(defaultFormat)); status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t setDefaultBufferDataSpace( android_dataspace defaultDataSpace) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(static_cast(defaultDataSpace)); status_t result = remote()->transact(SET_DEFAULT_BUFFER_DATA_SPACE, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t setConsumerUsageBits(uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeUint32(usage); status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual status_t setTransformHint(uint32_t hint) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeUint32(hint); status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); if (result != NO_ERROR) { return result; } return reply.readInt32(); } virtual sp getSidebandStream() const { Parcel data, reply; status_t err; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { return NULL; } sp stream; if (reply.readInt32()) { stream = NativeHandle::create(reply.readNativeHandle(), true); } return stream; } virtual status_t discardFreeBuffers() { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); status_t error = remote()->transact(DISCARD_FREE_BUFFERS, data, &reply); if (error != NO_ERROR) { return error; } int32_t result = NO_ERROR; error = reply.readInt32(&result); if (error != NO_ERROR) { return error; } return result; } virtual void dump(String8& result, const char* prefix) const { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeString8(result); data.writeString8(String8(prefix ? prefix : "")); remote()->transact(DUMP, data, &reply); reply.readString8(); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpGraphicBufferConsumer::~BpGraphicBufferConsumer() {} IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); // ---------------------------------------------------------------------- status_t BnGraphicBufferConsumer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case ACQUIRE_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); BufferItem item; int64_t presentWhen = data.readInt64(); uint64_t maxFrameNumber = data.readUint64(); status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber); status_t err = reply->write(item); if (err) return err; reply->writeInt32(result); return NO_ERROR; } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp buffer = new GraphicBuffer(); data.read(*buffer.get()); int slot = -1; int result = attachBuffer(&slot, buffer); reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; } case RELEASE_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int buf = data.readInt32(); uint64_t frameNumber = static_cast(data.readInt64()); sp releaseFence = new Fence(); status_t err = data.read(*releaseFence); if (err) return err; status_t result = releaseBuffer(buf, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); reply->writeInt32(result); return NO_ERROR; } case CONSUMER_CONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); bool controlledByApp = data.readInt32(); status_t result = consumerConnect(consumer, controlledByApp); reply->writeInt32(result); return NO_ERROR; } case CONSUMER_DISCONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = consumerDisconnect(); reply->writeInt32(result); return NO_ERROR; } case GET_RELEASED_BUFFERS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint64_t slotMask = 0; status_t result = getReleasedBuffers(&slotMask); reply->writeInt64(static_cast(slotMask)); reply->writeInt32(result); return NO_ERROR; } case SET_DEFAULT_BUFFER_SIZE: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); status_t result = setDefaultBufferSize(width, height); reply->writeInt32(result); return NO_ERROR; } case SET_MAX_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int bufferCount = data.readInt32(); status_t result = setMaxBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; } case SET_MAX_ACQUIRED_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int maxAcquiredBuffers = data.readInt32(); status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); reply->writeInt32(result); return NO_ERROR; } case SET_CONSUMER_NAME: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); setConsumerName( data.readString8() ); return NO_ERROR; } case SET_DEFAULT_BUFFER_FORMAT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); PixelFormat defaultFormat = static_cast(data.readInt32()); status_t result = setDefaultBufferFormat(defaultFormat); reply->writeInt32(result); return NO_ERROR; } case SET_DEFAULT_BUFFER_DATA_SPACE: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); android_dataspace defaultDataSpace = static_cast(data.readInt32()); status_t result = setDefaultBufferDataSpace(defaultDataSpace); reply->writeInt32(result); return NO_ERROR; } case SET_CONSUMER_USAGE_BITS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint32_t usage = data.readUint32(); status_t result = setConsumerUsageBits(usage); reply->writeInt32(result); return NO_ERROR; } case SET_TRANSFORM_HINT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint32_t hint = data.readUint32(); status_t result = setTransformHint(hint); reply->writeInt32(result); return NO_ERROR; } case GET_SIDEBAND_STREAM: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp stream = getSidebandStream(); reply->writeInt32(static_cast(stream != NULL)); if (stream != NULL) { reply->writeNativeHandle(stream->handle()); } return NO_ERROR; } case DISCARD_FREE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = discardFreeBuffers(); status_t error = reply->writeInt32(result); return error; } case DUMP: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); String8 result = data.readString8(); String8 prefix = data.readString8(); static_cast(this)->dump(result, prefix); reply->writeString8(result); return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } }; // namespace android libs/gui/IGraphicBufferProducer.cpp0100644 0000000 0000000 00000066446 13077405420 016374 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- enum { REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION, DEQUEUE_BUFFER, DETACH_BUFFER, DETACH_NEXT_BUFFER, ATTACH_BUFFER, QUEUE_BUFFER, CANCEL_BUFFER, QUERY, CONNECT, DISCONNECT, SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, ALLOW_ALLOCATION, SET_GENERATION_NUMBER, GET_CONSUMER_NAME, SET_MAX_DEQUEUED_BUFFER_COUNT, SET_ASYNC_MODE, GET_NEXT_FRAME_NUMBER, SET_SHARED_BUFFER_MODE, SET_AUTO_REFRESH, SET_DEQUEUE_TIMEOUT, GET_LAST_QUEUED_BUFFER, GET_UNIQUE_ID, }; class BpGraphicBufferProducer : public BpInterface { public: BpGraphicBufferProducer(const sp& impl) : BpInterface(impl) { } virtual ~BpGraphicBufferProducer(); virtual status_t requestBuffer(int bufferIdx, sp* buf) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(bufferIdx); status_t result =remote()->transact(REQUEST_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } bool nonNull = reply.readInt32(); if (nonNull) { *buf = new GraphicBuffer(); result = reply.read(**buf); if(result != NO_ERROR) { (*buf).clear(); return result; } } result = reply.readInt32(); return result; } virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) { Parcel data, reply; data.writeInterfaceToken( IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(maxDequeuedBuffers); status_t result = remote()->transact(SET_MAX_DEQUEUED_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t setAsyncMode(bool async) { Parcel data, reply; data.writeInterfaceToken( IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(async); status_t result = remote()->transact(SET_ASYNC_MODE, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t dequeueBuffer(int *buf, sp* fence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast(format)); data.writeUint32(usage); status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } *buf = reply.readInt32(); bool nonNull = reply.readInt32(); if (nonNull) { *fence = new Fence(); reply.read(**fence); } result = reply.readInt32(); return result; } virtual status_t detachBuffer(int slot) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(slot); status_t result = remote()->transact(DETACH_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence) { if (outBuffer == NULL) { ALOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; } else if (outFence == NULL) { ALOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); status_t result = remote()->transact(DETACH_NEXT_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); if (result == NO_ERROR) { bool nonNull = reply.readInt32(); if (nonNull) { *outBuffer = new GraphicBuffer; reply.read(**outBuffer); } nonNull = reply.readInt32(); if (nonNull) { *outFence = new Fence; reply.read(**outFence); } } return result; } virtual status_t attachBuffer(int* slot, const sp& buffer) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.write(*buffer.get()); status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } *slot = reply.readInt32(); result = reply.readInt32(); return result; } virtual status_t queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); data.write(input); status_t result = remote()->transact(QUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } memcpy(output, reply.readInplace(sizeof(*output)), sizeof(*output)); result = reply.readInt32(); return result; } virtual status_t cancelBuffer(int buf, const sp& fence) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); data.write(*fence.get()); status_t result = remote()->transact(CANCEL_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual int query(int what, int* value) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(what); status_t result = remote()->transact(QUERY, data, &reply); if (result != NO_ERROR) { return result; } value[0] = reply.readInt32(); result = reply.readInt32(); return result; } virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); if (listener != NULL) { data.writeInt32(1); data.writeStrongBinder(IInterface::asBinder(listener)); } else { data.writeInt32(0); } data.writeInt32(api); data.writeInt32(producerControlledByApp); status_t result = remote()->transact(CONNECT, data, &reply); if (result != NO_ERROR) { return result; } memcpy(output, reply.readInplace(sizeof(*output)), sizeof(*output)); result = reply.readInt32(); return result; } virtual status_t disconnect(int api) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(api); status_t result =remote()->transact(DISCONNECT, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t setSidebandStream(const sp& stream) { Parcel data, reply; status_t result; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); if (stream.get()) { data.writeInt32(true); data.writeNativeHandle(stream->handle()); } else { data.writeInt32(false); } if ((result = remote()->transact(SET_SIDEBAND_STREAM, data, &reply)) == NO_ERROR) { result = reply.readInt32(); } return result; } virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast(format)); data.writeUint32(usage); status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply); if (result != NO_ERROR) { ALOGE("allocateBuffers failed to transact: %d", result); } } virtual status_t allowAllocation(bool allow) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(static_cast(allow)); status_t result = remote()->transact(ALLOW_ALLOCATION, data, &reply); if (result != NO_ERROR) { return result; } result = reply.readInt32(); return result; } virtual status_t setGenerationNumber(uint32_t generationNumber) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeUint32(generationNumber); status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply); if (result == NO_ERROR) { result = reply.readInt32(); } return result; } virtual String8 getConsumerName() const { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply); if (result != NO_ERROR) { ALOGE("getConsumerName failed to transact: %d", result); return String8("TransactFailed"); } return reply.readString8(); } virtual uint64_t getNextFrameNumber() const { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_NEXT_FRAME_NUMBER, data, &reply); if (result != NO_ERROR) { ALOGE("getNextFrameNumber failed to transact: %d", result); return 0; } uint64_t frameNumber = reply.readUint64(); return frameNumber; } virtual status_t setSharedBufferMode(bool sharedBufferMode) { Parcel data, reply; data.writeInterfaceToken( IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(sharedBufferMode); status_t result = remote()->transact(SET_SHARED_BUFFER_MODE, data, &reply); if (result == NO_ERROR) { result = reply.readInt32(); } return result; } virtual status_t setAutoRefresh(bool autoRefresh) { Parcel data, reply; data.writeInterfaceToken( IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(autoRefresh); status_t result = remote()->transact(SET_AUTO_REFRESH, data, &reply); if (result == NO_ERROR) { result = reply.readInt32(); } return result; } virtual status_t setDequeueTimeout(nsecs_t timeout) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt64(timeout); status_t result = remote()->transact(SET_DEQUEUE_TIMEOUT, data, &reply); if (result != NO_ERROR) { ALOGE("setDequeueTimeout failed to transact: %d", result); return result; } return reply.readInt32(); } virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER, data, &reply); if (result != NO_ERROR) { ALOGE("getLastQueuedBuffer failed to transact: %d", result); return result; } result = reply.readInt32(); if (result != NO_ERROR) { return result; } bool hasBuffer = reply.readBool(); sp buffer; if (hasBuffer) { buffer = new GraphicBuffer(); result = reply.read(*buffer); if (result == NO_ERROR) { result = reply.read(outTransformMatrix, sizeof(float) * 16); } } if (result != NO_ERROR) { ALOGE("getLastQueuedBuffer failed to read buffer: %d", result); return result; } sp fence(new Fence); result = reply.read(*fence); if (result != NO_ERROR) { ALOGE("getLastQueuedBuffer failed to read fence: %d", result); return result; } *outBuffer = buffer; *outFence = fence; return result; } virtual status_t getUniqueId(uint64_t* outId) const { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_UNIQUE_ID, data, &reply); if (result != NO_ERROR) { ALOGE("getUniqueId failed to transact: %d", result); } status_t actualResult = NO_ERROR; result = reply.readInt32(&actualResult); if (result != NO_ERROR) { return result; } result = reply.readUint64(outId); if (result != NO_ERROR) { return result; } return actualResult; } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpGraphicBufferProducer::~BpGraphicBufferProducer() {} IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer"); // ---------------------------------------------------------------------- status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case REQUEST_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int bufferIdx = data.readInt32(); sp buffer; int result = requestBuffer(bufferIdx, &buffer); reply->writeInt32(buffer != 0); if (buffer != 0) { reply->write(*buffer); } reply->writeInt32(result); return NO_ERROR; } case SET_MAX_DEQUEUED_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int maxDequeuedBuffers = data.readInt32(); int result = setMaxDequeuedBufferCount(maxDequeuedBuffers); reply->writeInt32(result); return NO_ERROR; } case SET_ASYNC_MODE: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool async = data.readInt32(); int result = setAsyncMode(async); reply->writeInt32(result); return NO_ERROR; } case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast(data.readInt32()); uint32_t usage = data.readUint32(); int buf = 0; sp fence; int result = dequeueBuffer(&buf, &fence, width, height, format, usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { reply->write(*fence); } reply->writeInt32(result); return NO_ERROR; } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; } case DETACH_NEXT_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp buffer; sp fence; int32_t result = detachNextBuffer(&buffer, &fence); reply->writeInt32(result); if (result == NO_ERROR) { reply->writeInt32(buffer != NULL); if (buffer != NULL) { reply->write(*buffer); } reply->writeInt32(fence != NULL); if (fence != NULL) { reply->write(*fence); } } return NO_ERROR; } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp buffer = new GraphicBuffer(); data.read(*buffer.get()); int slot = 0; int result = attachBuffer(&slot, buffer); reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; } case QUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); QueueBufferInput input(data); QueueBufferOutput* const output = reinterpret_cast( reply->writeInplace(sizeof(QueueBufferOutput))); memset(output, 0, sizeof(QueueBufferOutput)); status_t result = queueBuffer(buf, input, output); reply->writeInt32(result); return NO_ERROR; } case CANCEL_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); sp fence = new Fence(); data.read(*fence.get()); status_t result = cancelBuffer(buf, fence); reply->writeInt32(result); return NO_ERROR; } case QUERY: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int value = 0; int what = data.readInt32(); int res = query(what, &value); reply->writeInt32(value); reply->writeInt32(res); return NO_ERROR; } case CONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp listener; if (data.readInt32() == 1) { listener = IProducerListener::asInterface(data.readStrongBinder()); } int api = data.readInt32(); bool producerControlledByApp = data.readInt32(); QueueBufferOutput* const output = reinterpret_cast( reply->writeInplace(sizeof(QueueBufferOutput))); memset(output, 0, sizeof(QueueBufferOutput)); status_t res = connect(listener, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; } case DISCONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int api = data.readInt32(); status_t res = disconnect(api); reply->writeInt32(res); return NO_ERROR; } case SET_SIDEBAND_STREAM: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp stream; if (data.readInt32()) { stream = NativeHandle::create(data.readNativeHandle(), true); } status_t result = setSidebandStream(stream); reply->writeInt32(result); return NO_ERROR; } case ALLOCATE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast(data.readInt32()); uint32_t usage = data.readUint32(); allocateBuffers(width, height, format, usage); return NO_ERROR; } case ALLOW_ALLOCATION: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool allow = static_cast(data.readInt32()); status_t result = allowAllocation(allow); reply->writeInt32(result); return NO_ERROR; } case SET_GENERATION_NUMBER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint32_t generationNumber = data.readUint32(); status_t result = setGenerationNumber(generationNumber); reply->writeInt32(result); return NO_ERROR; } case GET_CONSUMER_NAME: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); reply->writeString8(getConsumerName()); return NO_ERROR; } case GET_NEXT_FRAME_NUMBER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint64_t frameNumber = getNextFrameNumber(); reply->writeUint64(frameNumber); return NO_ERROR; } case SET_SHARED_BUFFER_MODE: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool sharedBufferMode = data.readInt32(); status_t result = setSharedBufferMode(sharedBufferMode); reply->writeInt32(result); return NO_ERROR; } case SET_AUTO_REFRESH: { CHECK_INTERFACE(IGraphicBuffer, data, reply); bool autoRefresh = data.readInt32(); status_t result = setAutoRefresh(autoRefresh); reply->writeInt32(result); return NO_ERROR; } case SET_DEQUEUE_TIMEOUT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); nsecs_t timeout = data.readInt64(); status_t result = setDequeueTimeout(timeout); reply->writeInt32(result); return NO_ERROR; } case GET_LAST_QUEUED_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp buffer(nullptr); sp fence(Fence::NO_FENCE); float transform[16] = {}; status_t result = getLastQueuedBuffer(&buffer, &fence, transform); reply->writeInt32(result); if (result != NO_ERROR) { return result; } if (!buffer.get()) { reply->writeBool(false); } else { reply->writeBool(true); result = reply->write(*buffer); if (result == NO_ERROR) { reply->write(transform, sizeof(float) * 16); } } if (result != NO_ERROR) { ALOGE("getLastQueuedBuffer failed to write buffer: %d", result); return result; } result = reply->write(*fence); if (result != NO_ERROR) { ALOGE("getLastQueuedBuffer failed to write fence: %d", result); return result; } return NO_ERROR; } case GET_UNIQUE_ID: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint64_t outId = 0; status_t actualResult = getUniqueId(&outId); status_t result = reply->writeInt32(actualResult); if (result != NO_ERROR) { return result; } result = reply->writeUint64(outId); if (result != NO_ERROR) { return result; } return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { parcel.read(*this); } size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return sizeof(timestamp) + sizeof(isAutoTimestamp) + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + sizeof(stickyTransform) + fence->getFlattenedSize() + surfaceDamage.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { return fence->getFdCount(); } status_t IGraphicBufferProducer::QueueBufferInput::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { if (size < getFlattenedSize()) { return NO_MEMORY; } FlattenableUtils::write(buffer, size, timestamp); FlattenableUtils::write(buffer, size, isAutoTimestamp); FlattenableUtils::write(buffer, size, dataSpace); FlattenableUtils::write(buffer, size, crop); FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); status_t result = fence->flatten(buffer, size, fds, count); if (result != NO_ERROR) { return result; } return surfaceDamage.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { size_t minNeeded = sizeof(timestamp) + sizeof(isAutoTimestamp) + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + sizeof(stickyTransform); if (size < minNeeded) { return NO_MEMORY; } FlattenableUtils::read(buffer, size, timestamp); FlattenableUtils::read(buffer, size, isAutoTimestamp); FlattenableUtils::read(buffer, size, dataSpace); FlattenableUtils::read(buffer, size, crop); FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); FlattenableUtils::read(buffer, size, stickyTransform); fence = new Fence(); status_t result = fence->unflatten(buffer, size, fds, count); if (result != NO_ERROR) { return result; } return surfaceDamage.unflatten(buffer, size); } }; // namespace android libs/gui/IProducerListener.cpp0100644 0000000 0000000 00000003477 13077405420 015445 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include namespace android { enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, }; class BpProducerListener : public BpInterface { public: BpProducerListener(const sp& impl) : BpInterface(impl) {} virtual ~BpProducerListener(); virtual void onBufferReleased() { Parcel data, reply; data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpProducerListener::~BpProducerListener() {} IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener") status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case ON_BUFFER_RELEASED: CHECK_INTERFACE(IProducerListener, data, reply); onBufferReleased(); return NO_ERROR; } return BBinder::onTransact(code, data, reply, flags); } } // namespace android libs/gui/ISensorEventConnection.cpp0100644 0000000 0000000 00000011310 13077405420 016430 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- enum { GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, ENABLE_DISABLE, SET_EVENT_RATE, FLUSH_SENSOR }; class BpSensorEventConnection : public BpInterface { public: BpSensorEventConnection(const sp& impl) : BpInterface(impl) { } virtual ~BpSensorEventConnection(); virtual sp getSensorChannel() const { Parcel data, reply; data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); remote()->transact(GET_SENSOR_CHANNEL, data, &reply); return new BitTube(reply); } virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) { Parcel data, reply; data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); data.writeInt32(handle); data.writeInt32(enabled); data.writeInt64(samplingPeriodNs); data.writeInt64(maxBatchReportLatencyNs); data.writeInt32(reservedFlags); remote()->transact(ENABLE_DISABLE, data, &reply); return reply.readInt32(); } virtual status_t setEventRate(int handle, nsecs_t ns) { Parcel data, reply; data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); data.writeInt32(handle); data.writeInt64(ns); remote()->transact(SET_EVENT_RATE, data, &reply); return reply.readInt32(); } virtual status_t flush() { Parcel data, reply; data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); remote()->transact(FLUSH_SENSOR, data, &reply); return reply.readInt32(); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpSensorEventConnection::~BpSensorEventConnection() {} IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection"); // ---------------------------------------------------------------------------- status_t BnSensorEventConnection::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case GET_SENSOR_CHANNEL: { CHECK_INTERFACE(ISensorEventConnection, data, reply); sp channel(getSensorChannel()); channel->writeToParcel(reply); return NO_ERROR; } case ENABLE_DISABLE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); int enabled = data.readInt32(); nsecs_t samplingPeriodNs = data.readInt64(); nsecs_t maxBatchReportLatencyNs = data.readInt64(); int reservedFlags = data.readInt32(); status_t result = enableDisable(handle, enabled, samplingPeriodNs, maxBatchReportLatencyNs, reservedFlags); reply->writeInt32(result); return NO_ERROR; } case SET_EVENT_RATE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); nsecs_t ns = data.readInt64(); status_t result = setEventRate(handle, ns); reply->writeInt32(result); return NO_ERROR; } case FLUSH_SENSOR: { CHECK_INTERFACE(ISensorEventConnection, data, reply); status_t result = flush(); reply->writeInt32(result); return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/ISensorServer.cpp0100644 0000000 0000000 00000012512 13077405420 014602 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include namespace android { // ---------------------------------------------------------------------------- enum { GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION, CREATE_SENSOR_EVENT_CONNECTION, ENABLE_DATA_INJECTION, GET_DYNAMIC_SENSOR_LIST, }; class BpSensorServer : public BpInterface { public: BpSensorServer(const sp& impl) : BpInterface(impl) { } virtual ~BpSensorServer(); virtual Vector getSensorList(const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); data.writeString16(opPackageName); remote()->transact(GET_SENSOR_LIST, data, &reply); Sensor s; Vector v; uint32_t n = reply.readUint32(); v.setCapacity(n); while (n--) { reply.read(s); v.add(s); } return v; } virtual Vector getDynamicSensorList(const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); data.writeString16(opPackageName); remote()->transact(GET_DYNAMIC_SENSOR_LIST, data, &reply); Sensor s; Vector v; uint32_t n = reply.readUint32(); v.setCapacity(n); while (n--) { reply.read(s); v.add(s); } return v; } virtual sp createSensorEventConnection(const String8& packageName, int mode, const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); data.writeString8(packageName); data.writeInt32(mode); data.writeString16(opPackageName); remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply); return interface_cast(reply.readStrongBinder()); } virtual int isDataInjectionEnabled() { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); remote()->transact(ENABLE_DATA_INJECTION, data, &reply); return reply.readInt32(); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpSensorServer::~BpSensorServer() {} IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer"); // ---------------------------------------------------------------------- status_t BnSensorServer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case GET_SENSOR_LIST: { CHECK_INTERFACE(ISensorServer, data, reply); const String16& opPackageName = data.readString16(); Vector v(getSensorList(opPackageName)); size_t n = v.size(); reply->writeUint32(static_cast(n)); for (size_t i = 0; i < n; i++) { reply->write(v[i]); } return NO_ERROR; } case CREATE_SENSOR_EVENT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); String8 packageName = data.readString8(); int32_t mode = data.readInt32(); const String16& opPackageName = data.readString16(); sp connection(createSensorEventConnection(packageName, mode, opPackageName)); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } case ENABLE_DATA_INJECTION: { CHECK_INTERFACE(ISensorServer, data, reply); int32_t ret = isDataInjectionEnabled(); reply->writeInt32(static_cast(ret)); return NO_ERROR; } case GET_DYNAMIC_SENSOR_LIST: { CHECK_INTERFACE(ISensorServer, data, reply); const String16& opPackageName = data.readString16(); Vector v(getDynamicSensorList(opPackageName)); size_t n = v.size(); reply->writeUint32(static_cast(n)); for (size_t i = 0; i < n; i++) { reply->write(v[i]); } return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/ISurfaceComposer.cpp0100644 0000000 0000000 00000046177 13077405420 015260 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { class IDisplayEventConnection; class BpSurfaceComposer : public BpInterface { public: BpSurfaceComposer(const sp& impl) : BpInterface(impl) { } virtual ~BpSurfaceComposer(); virtual sp createConnection() { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); return interface_cast(reply.readStrongBinder()); } virtual sp createGraphicBufferAlloc() { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply); return interface_cast(reply.readStrongBinder()); } virtual void setTransactionState( const Vector& state, const Vector& displays, uint32_t flags) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeUint32(static_cast(state.size())); for (const auto& s : state) { s.write(data); } data.writeUint32(static_cast(displays.size())); for (const auto& d : displays) { d.write(data); } data.writeUint32(flags); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } virtual void bootFinished() { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } virtual status_t captureScreen(const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); data.writeUint32(minLayerZ); data.writeUint32(maxLayerZ); data.writeInt32(static_cast(useIdentityTransform)); data.writeInt32(static_cast(rotation)); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); return reply.readInt32(); } virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const { Parcel data, reply; int err = NO_ERROR; err = data.writeInterfaceToken( ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " "interface descriptor: %s (%d)", strerror(-err), -err); return false; } err = data.writeStrongBinder(IInterface::asBinder(bufferProducer)); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " "strong binder to parcel: %s (%d)", strerror(-err), -err); return false; } err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data, &reply); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " "performing transaction: %s (%d)", strerror(-err), -err); return false; } int32_t result = 0; err = reply.readInt32(&result); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " "retrieving result: %s (%d)", strerror(-err), -err); return false; } return result != 0; } virtual sp createDisplayEventConnection() { Parcel data, reply; sp result; int err = data.writeInterfaceToken( ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { return result; } err = remote()->transact( BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing " "transaction: %s (%d)", strerror(-err), -err); return result; } result = interface_cast(reply.readStrongBinder()); return result; } virtual sp createDisplay(const String8& displayName, bool secure) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeString8(displayName); data.writeInt32(secure ? 1 : 0); remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply); return reply.readStrongBinder(); } virtual void destroyDisplay(const sp& display) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply); } virtual sp getBuiltInDisplay(int32_t id) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeInt32(id); remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply); return reply.readStrongBinder(); } virtual void setPowerMode(const sp& display, int mode) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); data.writeInt32(mode); remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply); } virtual status_t getDisplayConfigs(const sp& display, Vector* configs) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply); status_t result = reply.readInt32(); if (result == NO_ERROR) { size_t numConfigs = reply.readUint32(); configs->clear(); configs->resize(numConfigs); for (size_t c = 0; c < numConfigs; ++c) { memcpy(&(configs->editItemAt(c)), reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo)); } } return result; } virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply); status_t result = reply.readInt32(); if (result == NO_ERROR) { memcpy(stats, reply.readInplace(sizeof(DisplayStatInfo)), sizeof(DisplayStatInfo)); } return result; } virtual int getActiveConfig(const sp& display) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::GET_ACTIVE_CONFIG, data, &reply); return reply.readInt32(); } virtual status_t setActiveConfig(const sp& display, int id) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); data.writeInt32(id); remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply); return reply.readInt32(); } virtual status_t clearAnimationFrameStats() { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply); return reply.readInt32(); } virtual status_t getAnimationFrameStats(FrameStats* outStats) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); reply.read(*outStats); return reply.readInt32(); } virtual status_t getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); if (result != NO_ERROR) { ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result); return result; } result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES, data, &reply); if (result != NO_ERROR) { ALOGE("getHdrCapabilities failed to transact: %d", result); return result; } result = reply.readInt32(); if (result == NO_ERROR) { result = reply.readParcelable(outCapabilities); } return result; } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpSurfaceComposer::~BpSurfaceComposer() {} IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); // ---------------------------------------------------------------------- status_t BnSurfaceComposer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case CREATE_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp b = IInterface::asBinder(createConnection()); reply->writeStrongBinder(b); return NO_ERROR; } case CREATE_GRAPHIC_BUFFER_ALLOC: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp b = IInterface::asBinder(createGraphicBufferAlloc()); reply->writeStrongBinder(b); return NO_ERROR; } case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); size_t count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } ComposerState s; Vector state; state.setCapacity(count); for (size_t i = 0; i < count; i++) { if (s.read(data) == BAD_VALUE) { return BAD_VALUE; } state.add(s); } count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } DisplayState d; Vector displays; displays.setCapacity(count); for (size_t i = 0; i < count; i++) { if (d.read(data) == BAD_VALUE) { return BAD_VALUE; } displays.add(d); } uint32_t stateFlags = data.readUint32(); setTransactionState(state, displays, stateFlags); return NO_ERROR; } case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); bootFinished(); return NO_ERROR; } case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); sp producer = interface_cast(data.readStrongBinder()); Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); uint32_t reqHeight = data.readUint32(); uint32_t minLayerZ = data.readUint32(); uint32_t maxLayerZ = data.readUint32(); bool useIdentityTransform = static_cast(data.readInt32()); int32_t rotation = data.readInt32(); status_t res = captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, static_cast(rotation)); reply->writeInt32(res); return NO_ERROR; } case AUTHENTICATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp bufferProducer = interface_cast(data.readStrongBinder()); int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0; reply->writeInt32(result); return NO_ERROR; } case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp connection(createDisplayEventConnection()); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } case CREATE_DISPLAY: { CHECK_INTERFACE(ISurfaceComposer, data, reply); String8 displayName = data.readString8(); bool secure = bool(data.readInt32()); sp display(createDisplay(displayName, secure)); reply->writeStrongBinder(display); return NO_ERROR; } case DESTROY_DISPLAY: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); destroyDisplay(display); return NO_ERROR; } case GET_BUILT_IN_DISPLAY: { CHECK_INTERFACE(ISurfaceComposer, data, reply); int32_t id = data.readInt32(); sp display(getBuiltInDisplay(id)); reply->writeStrongBinder(display); return NO_ERROR; } case GET_DISPLAY_CONFIGS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); Vector configs; sp display = data.readStrongBinder(); status_t result = getDisplayConfigs(display, &configs); reply->writeInt32(result); if (result == NO_ERROR) { reply->writeUint32(static_cast(configs.size())); for (size_t c = 0; c < configs.size(); ++c) { memcpy(reply->writeInplace(sizeof(DisplayInfo)), &configs[c], sizeof(DisplayInfo)); } } return NO_ERROR; } case GET_DISPLAY_STATS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); DisplayStatInfo stats; sp display = data.readStrongBinder(); status_t result = getDisplayStats(display, &stats); reply->writeInt32(result); if (result == NO_ERROR) { memcpy(reply->writeInplace(sizeof(DisplayStatInfo)), &stats, sizeof(DisplayStatInfo)); } return NO_ERROR; } case GET_ACTIVE_CONFIG: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); int id = getActiveConfig(display); reply->writeInt32(id); return NO_ERROR; } case SET_ACTIVE_CONFIG: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); int id = data.readInt32(); status_t result = setActiveConfig(display, id); reply->writeInt32(result); return NO_ERROR; } case CLEAR_ANIMATION_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); status_t result = clearAnimationFrameStats(); reply->writeInt32(result); return NO_ERROR; } case GET_ANIMATION_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); FrameStats stats; status_t result = getAnimationFrameStats(&stats); reply->write(stats); reply->writeInt32(result); return NO_ERROR; } case SET_POWER_MODE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); int32_t mode = data.readInt32(); setPowerMode(display, mode); return NO_ERROR; } case GET_HDR_CAPABILITIES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = nullptr; status_t result = data.readStrongBinder(&display); if (result != NO_ERROR) { ALOGE("getHdrCapabilities failed to readStrongBinder: %d", result); return result; } HdrCapabilities capabilities; result = getHdrCapabilities(display, &capabilities); reply->writeInt32(result); if (result == NO_ERROR) { reply->writeParcelable(capabilities); } return NO_ERROR; } default: { return BBinder::onTransact(code, data, reply, flags); } } } // ---------------------------------------------------------------------------- }; libs/gui/ISurfaceComposerClient.cpp0100644 0000000 0000000 00000012645 13077405420 016410 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ // tag as surfaceflinger #define LOG_TAG "SurfaceFlinger" #include #include #include #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { enum { CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, DESTROY_SURFACE, CLEAR_LAYER_FRAME_STATS, GET_LAYER_FRAME_STATS }; class BpSurfaceComposerClient : public BpInterface { public: BpSurfaceComposerClient(const sp& impl) : BpInterface(impl) { } virtual ~BpSurfaceComposerClient(); virtual status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeString8(name); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast(format)); data.writeUint32(flags); remote()->transact(CREATE_SURFACE, data, &reply); *handle = reply.readStrongBinder(); *gbp = interface_cast(reply.readStrongBinder()); return reply.readInt32(); } virtual status_t destroySurface(const sp& handle) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeStrongBinder(handle); remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); } virtual status_t clearLayerFrameStats(const sp& handle) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeStrongBinder(handle); remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply); return reply.readInt32(); } virtual status_t getLayerFrameStats(const sp& handle, FrameStats* outStats) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeStrongBinder(handle); remote()->transact(GET_LAYER_FRAME_STATS, data, &reply); reply.read(*outStats); return reply.readInt32(); } }; // Out-of-line virtual method definition to trigger vtable emission in this // translation unit (see clang warning -Wweak-vtables) BpSurfaceComposerClient::~BpSurfaceComposerClient() {} IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); // ---------------------------------------------------------------------- status_t BnSurfaceComposerClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); String8 name = data.readString8(); uint32_t width = data.readUint32(); uint32_t height = data.readUint32(); PixelFormat format = static_cast(data.readInt32()); uint32_t createFlags = data.readUint32(); sp handle; sp gbp; status_t result = createSurface(name, width, height, format, createFlags, &handle, &gbp); reply->writeStrongBinder(handle); reply->writeStrongBinder(IInterface::asBinder(gbp)); reply->writeInt32(result); return NO_ERROR; } case DESTROY_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); reply->writeInt32(destroySurface( data.readStrongBinder() ) ); return NO_ERROR; } case CLEAR_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp handle = data.readStrongBinder(); status_t result = clearLayerFrameStats(handle); reply->writeInt32(result); return NO_ERROR; } case GET_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp handle = data.readStrongBinder(); FrameStats stats; status_t result = getLayerFrameStats(handle, &stats); reply->write(stats); reply->writeInt32(result); return NO_ERROR; } default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android libs/gui/LayerState.cpp0100644 0000000 0000000 00000007331 13077405420 014111 0ustar000000000 0000000 /* * Copyright (C) 2008 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 #include #include #include #include namespace android { status_t layer_state_t::write(Parcel& output) const { output.writeStrongBinder(surface); output.writeUint32(what); output.writeFloat(x); output.writeFloat(y); output.writeUint32(z); output.writeUint32(w); output.writeUint32(h); output.writeUint32(layerStack); output.writeFloat(alpha); output.writeUint32(flags); output.writeUint32(mask); *reinterpret_cast( output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix; output.write(crop); output.write(finalCrop); output.writeStrongBinder(handle); output.writeUint64(frameNumber); output.writeInt32(overrideScalingMode); output.write(transparentRegion); return NO_ERROR; } status_t layer_state_t::read(const Parcel& input) { surface = input.readStrongBinder(); what = input.readUint32(); x = input.readFloat(); y = input.readFloat(); z = input.readUint32(); w = input.readUint32(); h = input.readUint32(); layerStack = input.readUint32(); alpha = input.readFloat(); flags = static_cast(input.readUint32()); mask = static_cast(input.readUint32()); const void* matrix_data = input.readInplace(sizeof(layer_state_t::matrix22_t)); if (matrix_data) { matrix = *reinterpret_cast(matrix_data); } else { return BAD_VALUE; } input.read(crop); input.read(finalCrop); handle = input.readStrongBinder(); frameNumber = input.readUint64(); overrideScalingMode = input.readInt32(); input.read(transparentRegion); return NO_ERROR; } status_t ComposerState::write(Parcel& output) const { output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } status_t ComposerState::read(const Parcel& input) { client = interface_cast(input.readStrongBinder()); return state.read(input); } DisplayState::DisplayState() : what(0), layerStack(0), orientation(eOrientationDefault), viewport(Rect::EMPTY_RECT), frame(Rect::EMPTY_RECT), width(0), height(0) { } status_t DisplayState::write(Parcel& output) const { output.writeStrongBinder(token); output.writeStrongBinder(IInterface::asBinder(surface)); output.writeUint32(what); output.writeUint32(layerStack); output.writeUint32(orientation); output.write(viewport); output.write(frame); output.writeUint32(width); output.writeUint32(height); return NO_ERROR; } status_t DisplayState::read(const Parcel& input) { token = input.readStrongBinder(); surface = interface_cast(input.readStrongBinder()); what = input.readUint32(); layerStack = input.readUint32(); orientation = input.readUint32(); input.read(viewport); input.read(frame); width = input.readUint32(); height = input.readUint32(); return NO_ERROR; } }; // namespace android libs/gui/Sensor.cpp0100644 0000000 0000000 00000046641 13077405420 013314 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- Sensor::Sensor(const char * name) : mName(name), mHandle(0), mType(0), mMinValue(0), mMaxValue(0), mResolution(0), mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0), mFifoMaxEventCount(0), mRequiredAppOp(0), mMaxDelay(0), mFlags(0) { } Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) : Sensor(*hwSensor, uuid_t(), halVersion) { } Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) { mName = hwSensor.name; mVendor = hwSensor.vendor; mVersion = hwSensor.version; mHandle = hwSensor.handle; mType = hwSensor.type; mMinValue = 0; // FIXME: minValue mMaxValue = hwSensor.maxRange; // FIXME: maxValue mResolution = hwSensor.resolution; mPower = hwSensor.power; mMinDelay = hwSensor.minDelay; mFlags = 0; mUuid = uuid; // Set fifo event count zero for older devices which do not support batching. Fused // sensors also have their fifo counts set to zero. if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) { mFifoReservedEventCount = hwSensor.fifoReservedEventCount; mFifoMaxEventCount = hwSensor.fifoMaxEventCount; } else { mFifoReservedEventCount = 0; mFifoMaxEventCount = 0; } if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { if (hwSensor.maxDelay > INT_MAX) { // Max delay is declared as a 64 bit integer for 64 bit architectures. But it should // always fit in a 32 bit integer, log error and cap it to INT_MAX. ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.string(), static_cast(hwSensor.maxDelay)); mMaxDelay = INT_MAX; } else { mMaxDelay = static_cast(hwSensor.maxDelay); } } else { // For older hals set maxDelay to 0. mMaxDelay = 0; } // Ensure existing sensors have correct string type, required permissions and reporting mode. // Set reportingMode for all android defined sensor types, set wake-up flag only for proximity // sensor, significant motion, tilt, pick_up gesture, wake gesture and glance gesture on older // HALs. Newer HALs can define both wake-up and non wake-up proximity sensors. // All the OEM defined defined sensors have flags set to whatever is provided by the HAL. switch (mType) { case SENSOR_TYPE_ACCELEROMETER: mStringType = SENSOR_STRING_TYPE_ACCELEROMETER; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_AMBIENT_TEMPERATURE: mStringType = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; case SENSOR_TYPE_GAME_ROTATION_VECTOR: mStringType = SENSOR_STRING_TYPE_GAME_ROTATION_VECTOR; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: mStringType = SENSOR_STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_GRAVITY: mStringType = SENSOR_STRING_TYPE_GRAVITY; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_GYROSCOPE: mStringType = SENSOR_STRING_TYPE_GYROSCOPE; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_HEART_RATE: { mStringType = SENSOR_STRING_TYPE_HEART_RATE; mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS; AppOpsManager appOps; mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; } break; case SENSOR_TYPE_LIGHT: mStringType = SENSOR_STRING_TYPE_LIGHT; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; case SENSOR_TYPE_LINEAR_ACCELERATION: mStringType = SENSOR_STRING_TYPE_LINEAR_ACCELERATION; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_MAGNETIC_FIELD: mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_ORIENTATION: mStringType = SENSOR_STRING_TYPE_ORIENTATION; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_PRESSURE: mStringType = SENSOR_STRING_TYPE_PRESSURE; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_PROXIMITY: mStringType = SENSOR_STRING_TYPE_PROXIMITY; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_RELATIVE_HUMIDITY: mStringType = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; case SENSOR_TYPE_ROTATION_VECTOR: mStringType = SENSOR_STRING_TYPE_ROTATION_VECTOR; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_SIGNIFICANT_MOTION: mStringType = SENSOR_STRING_TYPE_SIGNIFICANT_MOTION; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_STEP_COUNTER: mStringType = SENSOR_STRING_TYPE_STEP_COUNTER; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; case SENSOR_TYPE_STEP_DETECTOR: mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR; mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; break; case SENSOR_TYPE_TEMPERATURE: mStringType = SENSOR_STRING_TYPE_TEMPERATURE; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; case SENSOR_TYPE_TILT_DETECTOR: mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR; mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_WAKE_GESTURE: mStringType = SENSOR_STRING_TYPE_WAKE_GESTURE; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_GLANCE_GESTURE: mStringType = SENSOR_STRING_TYPE_GLANCE_GESTURE; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_PICK_UP_GESTURE: mStringType = SENSOR_STRING_TYPE_PICK_UP_GESTURE; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_WRIST_TILT_GESTURE: mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE; mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_DYNAMIC_SENSOR_META: mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META; mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up break; case SENSOR_TYPE_POSE_6DOF: mStringType = SENSOR_STRING_TYPE_POSE_6DOF; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; case SENSOR_TYPE_STATIONARY_DETECT: mStringType = SENSOR_STRING_TYPE_STATIONARY_DETECT; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_MOTION_DETECT: mStringType = SENSOR_STRING_TYPE_MOTION_DETECT; mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= SENSOR_FLAG_WAKE_UP; } break; case SENSOR_TYPE_HEART_BEAT: mStringType = SENSOR_STRING_TYPE_HEART_BEAT; mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; break; default: // Only pipe the stringType, requiredPermission and flags for custom sensors. if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) { mStringType = hwSensor.stringType; } if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.requiredPermission) { mRequiredPermission = hwSensor.requiredPermission; if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) { AppOpsManager appOps; mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); } } if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { mFlags = static_cast(hwSensor.flags); } else { // This is an OEM defined sensor on an older HAL. Use minDelay to determine the // reporting mode of the sensor. if (mMinDelay > 0) { mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; } else if (mMinDelay == 0) { mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; } else if (mMinDelay < 0) { mFlags |= SENSOR_FLAG_ONE_SHOT_MODE; } } break; } if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { // Wake-up flag of HAL 1.3 and above is set here mFlags |= (hwSensor.flags & SENSOR_FLAG_WAKE_UP); // Log error if the reporting mode is not as expected, but respect HAL setting. int actualReportingMode = (hwSensor.flags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT; int expectedReportingMode = (mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT; if (actualReportingMode != expectedReportingMode) { ALOGE("Reporting Mode incorrect: sensor %s handle=%#010" PRIx32 " type=%" PRId32 " " "actual=%d expected=%d", mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode); } } // Feature flags // Set DYNAMIC_SENSOR_MASK and ADDITIONAL_INFO_MASK flag here. Compatible with HAL 1_3. if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { mFlags |= (hwSensor.flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK)); } // Set DATA_INJECTION flag here. Defined in HAL 1_4. if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) { mFlags |= (hwSensor.flags & DATA_INJECTION_MASK); } if (mRequiredPermission.length() > 0) { // If the sensor is protected by a permission we need to know if it is // a runtime one to determine whether we can use the permission cache. sp binder = defaultServiceManager()->getService(String16("permission")); if (binder != 0) { sp permCtrl = interface_cast(binder); mRequiredPermissionRuntime = permCtrl->isRuntimePermission( String16(mRequiredPermission)); } } } Sensor::~Sensor() { } const String8& Sensor::getName() const { return mName; } const String8& Sensor::getVendor() const { return mVendor; } int32_t Sensor::getHandle() const { return mHandle; } int32_t Sensor::getType() const { return mType; } float Sensor::getMinValue() const { return mMinValue; } float Sensor::getMaxValue() const { return mMaxValue; } float Sensor::getResolution() const { return mResolution; } float Sensor::getPowerUsage() const { return mPower; } int32_t Sensor::getMinDelay() const { return mMinDelay; } nsecs_t Sensor::getMinDelayNs() const { return getMinDelay() * 1000; } int32_t Sensor::getVersion() const { return mVersion; } uint32_t Sensor::getFifoReservedEventCount() const { return mFifoReservedEventCount; } uint32_t Sensor::getFifoMaxEventCount() const { return mFifoMaxEventCount; } const String8& Sensor::getStringType() const { return mStringType; } const String8& Sensor::getRequiredPermission() const { return mRequiredPermission; } bool Sensor::isRequiredPermissionRuntime() const { return mRequiredPermissionRuntime; } int32_t Sensor::getRequiredAppOp() const { return mRequiredAppOp; } int32_t Sensor::getMaxDelay() const { return mMaxDelay; } uint32_t Sensor::getFlags() const { return mFlags; } bool Sensor::isWakeUpSensor() const { return (mFlags & SENSOR_FLAG_WAKE_UP) != 0; } bool Sensor::isDynamicSensor() const { return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0; } bool Sensor::hasAdditionalInfo() const { return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0; } int32_t Sensor::getReportingMode() const { return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT); } const Sensor::uuid_t& Sensor::getUuid() const { return mUuid; } void Sensor::setId(int32_t id) { mUuid.i64[0] = id; mUuid.i64[1] = 0; } int32_t Sensor::getId() const { return int32_t(mUuid.i64[0]); } size_t Sensor::getFlattenedSize() const { size_t fixedSize = sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) + sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) + sizeof(mPower) + sizeof(mMinDelay) + sizeof(mFifoMaxEventCount) + sizeof(mFifoMaxEventCount) + sizeof(mRequiredPermissionRuntime) + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + sizeof(mUuid); size_t variableSize = sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) + sizeof(uint32_t) + FlattenableUtils::align<4>(mVendor.length()) + sizeof(uint32_t) + FlattenableUtils::align<4>(mStringType.length()) + sizeof(uint32_t) + FlattenableUtils::align<4>(mRequiredPermission.length()); return fixedSize + variableSize; } status_t Sensor::flatten(void* buffer, size_t size) const { if (size < getFlattenedSize()) { return NO_MEMORY; } flattenString8(buffer, size, mName); flattenString8(buffer, size, mVendor); FlattenableUtils::write(buffer, size, mVersion); FlattenableUtils::write(buffer, size, mHandle); FlattenableUtils::write(buffer, size, mType); FlattenableUtils::write(buffer, size, mMinValue); FlattenableUtils::write(buffer, size, mMaxValue); FlattenableUtils::write(buffer, size, mResolution); FlattenableUtils::write(buffer, size, mPower); FlattenableUtils::write(buffer, size, mMinDelay); FlattenableUtils::write(buffer, size, mFifoReservedEventCount); FlattenableUtils::write(buffer, size, mFifoMaxEventCount); flattenString8(buffer, size, mStringType); flattenString8(buffer, size, mRequiredPermission); FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime); FlattenableUtils::write(buffer, size, mRequiredAppOp); FlattenableUtils::write(buffer, size, mMaxDelay); FlattenableUtils::write(buffer, size, mFlags); if (mUuid.i64[1] != 0) { // We should never hit this case with our current API, but we // could via a careless API change. If that happens, // this code will keep us from leaking our UUID (while probably // breaking dynamic sensors). See b/29547335. ALOGW("Sensor with UUID being flattened; sending 0. Expect " "bad dynamic sensor behavior"); uuid_t tmpUuid; // default constructor makes this 0. FlattenableUtils::write(buffer, size, tmpUuid); } else { FlattenableUtils::write(buffer, size, mUuid); } return NO_ERROR; } status_t Sensor::unflatten(void const* buffer, size_t size) { if (!unflattenString8(buffer, size, mName)) { return NO_MEMORY; } if (!unflattenString8(buffer, size, mVendor)) { return NO_MEMORY; } size_t fixedSize1 = sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) + sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) + sizeof(mPower) + sizeof(mMinDelay) + sizeof(mFifoMaxEventCount) + sizeof(mFifoMaxEventCount); if (size < fixedSize1) { return NO_MEMORY; } FlattenableUtils::read(buffer, size, mVersion); FlattenableUtils::read(buffer, size, mHandle); FlattenableUtils::read(buffer, size, mType); FlattenableUtils::read(buffer, size, mMinValue); FlattenableUtils::read(buffer, size, mMaxValue); FlattenableUtils::read(buffer, size, mResolution); FlattenableUtils::read(buffer, size, mPower); FlattenableUtils::read(buffer, size, mMinDelay); FlattenableUtils::read(buffer, size, mFifoReservedEventCount); FlattenableUtils::read(buffer, size, mFifoMaxEventCount); if (!unflattenString8(buffer, size, mStringType)) { return NO_MEMORY; } if (!unflattenString8(buffer, size, mRequiredPermission)) { return NO_MEMORY; } size_t fixedSize2 = sizeof(mRequiredPermissionRuntime) + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + sizeof(mUuid); if (size < fixedSize2) { return NO_MEMORY; } FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime); FlattenableUtils::read(buffer, size, mRequiredAppOp); FlattenableUtils::read(buffer, size, mMaxDelay); FlattenableUtils::read(buffer, size, mFlags); FlattenableUtils::read(buffer, size, mUuid); return NO_ERROR; } void Sensor::flattenString8(void*& buffer, size_t& size, const String8& string8) { uint32_t len = static_cast(string8.length()); FlattenableUtils::write(buffer, size, len); memcpy(static_cast(buffer), string8.string(), len); FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); } bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) { uint32_t len; if (size < sizeof(len)) { return false; } FlattenableUtils::read(buffer, size, len); if (size < len) { return false; } outputString8.setTo(static_cast(buffer), len); FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); return true; } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/SensorEventQueue.cpp0100644 0000000 0000000 00000014220 13077405420 015307 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "Sensors" #include #include #include #include #include #include #include #include #include #include #include #include #include using std::min; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- SensorEventQueue::SensorEventQueue(const sp& connection) : mSensorEventConnection(connection), mRecBuffer(NULL), mAvailable(0), mConsumed(0), mNumAcksToSend(0) { mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT]; } SensorEventQueue::~SensorEventQueue() { delete [] mRecBuffer; } void SensorEventQueue::onFirstRef() { mSensorChannel = mSensorEventConnection->getSensorChannel(); } int SensorEventQueue::getFd() const { return mSensorChannel->getFd(); } ssize_t SensorEventQueue::write(const sp& tube, ASensorEvent const* events, size_t numEvents) { return BitTube::sendObjects(tube, events, numEvents); } ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) { if (mAvailable == 0) { ssize_t err = BitTube::recvObjects(mSensorChannel, mRecBuffer, MAX_RECEIVE_BUFFER_EVENT_COUNT); if (err < 0) { return err; } mAvailable = static_cast(err); mConsumed = 0; } size_t count = min(numEvents, mAvailable); memcpy(events, mRecBuffer + mConsumed, count * sizeof(ASensorEvent)); mAvailable -= count; mConsumed += count; return static_cast(count); } sp SensorEventQueue::getLooper() const { Mutex::Autolock _l(mLock); if (mLooper == 0) { mLooper = new Looper(true); mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL); } return mLooper; } status_t SensorEventQueue::waitForEvent() const { const int fd = getFd(); sp looper(getLooper()); int events; int32_t result; do { result = looper->pollOnce(-1, NULL, &events, NULL); if (result == ALOOPER_POLL_ERROR) { ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno); result = -EPIPE; // unknown error, so we make up one break; } if (events & ALOOPER_EVENT_HANGUP) { // the other-side has died ALOGE("SensorEventQueue::waitForEvent error HANGUP"); result = -EPIPE; // unknown error, so we make up one break; } } while (result != fd); return (result == fd) ? status_t(NO_ERROR) : result; } status_t SensorEventQueue::wake() const { sp looper(getLooper()); looper->wake(); return NO_ERROR; } status_t SensorEventQueue::enableSensor(Sensor const* sensor) const { return enableSensor(sensor, SENSOR_DELAY_NORMAL); } status_t SensorEventQueue::enableSensor(Sensor const* sensor, int32_t samplingPeriodUs) const { return mSensorEventConnection->enableDisable(sensor->getHandle(), true, us2ns(samplingPeriodUs), 0, 0); } status_t SensorEventQueue::disableSensor(Sensor const* sensor) const { return mSensorEventConnection->enableDisable(sensor->getHandle(), false, 0, 0, 0); } status_t SensorEventQueue::enableSensor(int32_t handle, int32_t samplingPeriodUs, int maxBatchReportLatencyUs, int reservedFlags) const { return mSensorEventConnection->enableDisable(handle, true, us2ns(samplingPeriodUs), us2ns(maxBatchReportLatencyUs), reservedFlags); } status_t SensorEventQueue::flush() const { return mSensorEventConnection->flush(); } status_t SensorEventQueue::disableSensor(int32_t handle) const { return mSensorEventConnection->enableDisable(handle, false, 0, 0, false); } status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const { return mSensorEventConnection->setEventRate(sensor->getHandle(), ns); } status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) { do { // Blocking call. ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL); if (size >= 0) { return NO_ERROR; } else if (size < 0 && errno == EAGAIN) { // If send is returning a "Try again" error, sleep for 100ms and try again. In all // other cases log a failure and exit. usleep(100000); } else { ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size); return INVALID_OPERATION; } } while (true); } void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { for (int i = 0; i < count; ++i) { if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) { ++mNumAcksToSend; } } // Send mNumAcksToSend to acknowledge for the wake up sensor events received. if (mNumAcksToSend > 0) { ssize_t size = ::send(mSensorChannel->getFd(), &mNumAcksToSend, sizeof(mNumAcksToSend), MSG_DONTWAIT | MSG_NOSIGNAL); if (size < 0) { ALOGE("sendAck failure %zd %d", size, mNumAcksToSend); } else { mNumAcksToSend = 0; } } return; } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/SensorManager.cpp0100644 0000000 0000000 00000020633 13077405420 014600 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "Sensors" #include #include #include #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- android::Mutex android::SensorManager::sLock; std::map android::SensorManager::sPackageInstances; SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) { Mutex::Autolock _l(sLock); SensorManager* sensorManager; std::map::iterator iterator = sPackageInstances.find(packageName); if (iterator != sPackageInstances.end()) { sensorManager = iterator->second; } else { String16 opPackageName = packageName; // It is possible that the calling code has no access to the package name. // In this case we will get the packages for the calling UID and pick the // first one for attributing the app op. This will work correctly for // runtime permissions as for legacy apps we will toggle the app op for // all packages in the UID. The caveat is that the operation may be attributed // to the wrong package and stats based on app ops may be slightly off. if (opPackageName.size() <= 0) { sp binder = defaultServiceManager()->getService(String16("permission")); if (binder != 0) { const uid_t uid = IPCThreadState::self()->getCallingUid(); Vector packages; interface_cast(binder)->getPackagesForUid(uid, packages); if (!packages.isEmpty()) { opPackageName = packages[0]; } else { ALOGE("No packages for calling UID"); } } else { ALOGE("Cannot get permission service"); } } sensorManager = new SensorManager(opPackageName); // If we had no package name, we looked it up from the UID and the sensor // manager instance we created should also be mapped to the empty package // name, to avoid looking up the packages for a UID and get the same result. if (packageName.size() <= 0) { sPackageInstances.insert(std::make_pair(String16(), sensorManager)); } // Stash the per package sensor manager. sPackageInstances.insert(std::make_pair(opPackageName, sensorManager)); } return *sensorManager; } SensorManager::SensorManager(const String16& opPackageName) : mSensorList(0), mOpPackageName(opPackageName) { // okay we're not locked here, but it's not needed during construction assertStateLocked(); } SensorManager::~SensorManager() { free(mSensorList); } void SensorManager::sensorManagerDied() { Mutex::Autolock _l(mLock); mSensorServer.clear(); free(mSensorList); mSensorList = NULL; mSensors.clear(); } status_t SensorManager::assertStateLocked() { bool initSensorManager = false; if (mSensorServer == NULL) { initSensorManager = true; } else { // Ping binder to check if sensorservice is alive. status_t err = IInterface::asBinder(mSensorServer)->pingBinder(); if (err != NO_ERROR) { initSensorManager = true; } } if (initSensorManager) { // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ... const String16 name("sensorservice"); for (int i = 0; i < 60; i++) { status_t err = getService(name, &mSensorServer); if (err == NAME_NOT_FOUND) { sleep(1); continue; } if (err != NO_ERROR) { return err; } break; } class DeathObserver : public IBinder::DeathRecipient { SensorManager& mSensorManager; virtual void binderDied(const wp& who) { ALOGW("sensorservice died [%p]", who.unsafe_get()); mSensorManager.sensorManagerDied(); } public: DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { } }; LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL"); mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver); mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); mSensorList = static_cast(malloc(count * sizeof(Sensor*))); LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL"); for (size_t i=0 ; i(err); } *list = mSensorList; return static_cast(mSensors.size()); } ssize_t SensorManager::getDynamicSensorList(Vector & dynamicSensors) { Mutex::Autolock _l(mLock); status_t err = assertStateLocked(); if (err < 0) { return static_cast(err); } dynamicSensors = mSensorServer->getDynamicSensorList(mOpPackageName); size_t count = dynamicSensors.size(); return static_cast(count); } Sensor const* SensorManager::getDefaultSensor(int type) { Mutex::Autolock _l(mLock); if (assertStateLocked() == NO_ERROR) { bool wakeUpSensor = false; // For the following sensor types, return a wake-up sensor. These types are by default // defined as wake-up sensors. For the rest of the sensor types defined in sensors.h return // a non_wake-up version. if (type == SENSOR_TYPE_PROXIMITY || type == SENSOR_TYPE_SIGNIFICANT_MOTION || type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE || type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE) { wakeUpSensor = true; } // For now we just return the first sensor of that type we find. // in the future it will make sense to let the SensorService make // that decision. for (size_t i=0 ; igetType() == type && mSensorList[i]->isWakeUpSensor() == wakeUpSensor) { return mSensorList[i]; } } } return NULL; } sp SensorManager::createEventQueue(String8 packageName, int mode) { sp queue; Mutex::Autolock _l(mLock); while (assertStateLocked() == NO_ERROR) { sp connection = mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName); if (connection == NULL) { // SensorService just died or the app doesn't have required permissions. ALOGE("createEventQueue: connection is NULL."); return NULL; } queue = new SensorEventQueue(connection); break; } return queue; } bool SensorManager::isDataInjectionEnabled() { Mutex::Autolock _l(mLock); if (assertStateLocked() == NO_ERROR) { return mSensorServer->isDataInjectionEnabled(); } return false; } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/StreamSplitter.cpp0100644 0000000 0000000 00000024121 13077405420 015012 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #define LOG_TAG "StreamSplitter" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include namespace android { status_t StreamSplitter::createSplitter( const sp& inputQueue, sp* outSplitter) { if (inputQueue == NULL) { ALOGE("createSplitter: inputQueue must not be NULL"); return BAD_VALUE; } if (outSplitter == NULL) { ALOGE("createSplitter: outSplitter must not be NULL"); return BAD_VALUE; } sp splitter(new StreamSplitter(inputQueue)); status_t status = splitter->mInput->consumerConnect(splitter, false); if (status == NO_ERROR) { splitter->mInput->setConsumerName(String8("StreamSplitter")); *outSplitter = splitter; } return status; } StreamSplitter::StreamSplitter(const sp& inputQueue) : mIsAbandoned(false), mMutex(), mReleaseCondition(), mOutstandingBuffers(0), mInput(inputQueue), mOutputs(), mBuffers() {} StreamSplitter::~StreamSplitter() { mInput->consumerDisconnect(); Vector >::iterator output = mOutputs.begin(); for (; output != mOutputs.end(); ++output) { (*output)->disconnect(NATIVE_WINDOW_API_CPU); } if (mBuffers.size() > 0) { ALOGE("%zu buffers still being tracked", mBuffers.size()); } } status_t StreamSplitter::addOutput( const sp& outputQueue) { if (outputQueue == NULL) { ALOGE("addOutput: outputQueue must not be NULL"); return BAD_VALUE; } Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; sp listener(new OutputListener(this, outputQueue)); IInterface::asBinder(outputQueue)->linkToDeath(listener); status_t status = outputQueue->connect(listener, NATIVE_WINDOW_API_CPU, /* producerControlledByApp */ false, &queueBufferOutput); if (status != NO_ERROR) { ALOGE("addOutput: failed to connect (%d)", status); return status; } mOutputs.push_back(outputQueue); return NO_ERROR; } void StreamSplitter::setName(const String8 &name) { Mutex::Autolock lock(mMutex); mInput->setConsumerName(name); } void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); // The current policy is that if any one consumer is consuming buffers too // slowly, the splitter will stall the rest of the outputs by not acquiring // any more buffers from the input. This will cause back pressure on the // input queue, slowing down its producer. // If there are too many outstanding buffers, we block until a buffer is // released back to the input in onBufferReleased while (mOutstandingBuffers >= MAX_OUTSTANDING_BUFFERS) { mReleaseCondition.wait(mMutex); // If the splitter is abandoned while we are waiting, the release // condition variable will be broadcast, and we should just return // without attempting to do anything more (since the input queue will // also be abandoned). if (mIsAbandoned) { return; } } ++mOutstandingBuffers; // Acquire and detach the buffer from the input BufferItem bufferItem; status_t status = mInput->acquireBuffer(&bufferItem, /* presentWhen */ 0); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "acquiring buffer from input failed (%d)", status); ALOGV("acquired buffer %#" PRIx64 " from input", bufferItem.mGraphicBuffer->getId()); status = mInput->detachBuffer(bufferItem.mSlot); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "detaching buffer from input failed (%d)", status); // Initialize our reference count for this buffer mBuffers.add(bufferItem.mGraphicBuffer->getId(), new BufferTracker(bufferItem.mGraphicBuffer)); IGraphicBufferProducer::QueueBufferInput queueInput( bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, bufferItem.mDataSpace, bufferItem.mCrop, static_cast(bufferItem.mScalingMode), bufferItem.mTransform, bufferItem.mFence); // Attach and queue the buffer to each of the outputs Vector >::iterator output = mOutputs.begin(); for (; output != mOutputs.end(); ++output) { int slot; status = (*output)->attachBuffer(&slot, bufferItem.mGraphicBuffer); if (status == NO_INIT) { // If we just discovered that this output has been abandoned, note // that, increment the release count so that we still release this // buffer eventually, and move on to the next output onAbandonedLocked(); mBuffers.editValueFor(bufferItem.mGraphicBuffer->getId())-> incrementReleaseCountLocked(); continue; } else { LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "attaching buffer to output failed (%d)", status); } IGraphicBufferProducer::QueueBufferOutput queueOutput; status = (*output)->queueBuffer(slot, queueInput, &queueOutput); if (status == NO_INIT) { // If we just discovered that this output has been abandoned, note // that, increment the release count so that we still release this // buffer eventually, and move on to the next output onAbandonedLocked(); mBuffers.editValueFor(bufferItem.mGraphicBuffer->getId())-> incrementReleaseCountLocked(); continue; } else { LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "queueing buffer to output failed (%d)", status); } ALOGV("queued buffer %#" PRIx64 " to output %p", bufferItem.mGraphicBuffer->getId(), output->get()); } } void StreamSplitter::onBufferReleasedByOutput( const sp& from) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); sp buffer; sp fence; status_t status = from->detachNextBuffer(&buffer, &fence); if (status == NO_INIT) { // If we just discovered that this output has been abandoned, note that, // but we can't do anything else, since buffer is invalid onAbandonedLocked(); return; } else { LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "detaching buffer from output failed (%d)", status); } ALOGV("detached buffer %#" PRIx64 " from output %p", buffer->getId(), from.get()); const sp& tracker = mBuffers.editValueFor(buffer->getId()); // Merge the release fence of the incoming buffer so that the fence we send // back to the input includes all of the outputs' fences tracker->mergeFence(fence); // Check to see if this is the last outstanding reference to this buffer size_t releaseCount = tracker->incrementReleaseCountLocked(); ALOGV("buffer %#" PRIx64 " reference count %zu (of %zu)", buffer->getId(), releaseCount, mOutputs.size()); if (releaseCount < mOutputs.size()) { return; } // If we've been abandoned, we can't return the buffer to the input, so just // stop tracking it and move on if (mIsAbandoned) { mBuffers.removeItem(buffer->getId()); return; } // Attach and release the buffer back to the input int consumerSlot; status = mInput->attachBuffer(&consumerSlot, tracker->getBuffer()); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "attaching buffer to input failed (%d)", status); status = mInput->releaseBuffer(consumerSlot, /* frameNumber */ 0, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker->getMergedFence()); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "releasing buffer to input failed (%d)", status); ALOGV("released buffer %#" PRIx64 " to input", buffer->getId()); // We no longer need to track the buffer once it has been returned to the // input mBuffers.removeItem(buffer->getId()); // Notify any waiting onFrameAvailable calls --mOutstandingBuffers; mReleaseCondition.signal(); } void StreamSplitter::onAbandonedLocked() { ALOGE("one of my outputs has abandoned me"); if (!mIsAbandoned) { mInput->consumerDisconnect(); } mIsAbandoned = true; mReleaseCondition.broadcast(); } StreamSplitter::OutputListener::OutputListener( const sp& splitter, const sp& output) : mSplitter(splitter), mOutput(output) {} StreamSplitter::OutputListener::~OutputListener() {} void StreamSplitter::OutputListener::onBufferReleased() { mSplitter->onBufferReleasedByOutput(mOutput); } void StreamSplitter::OutputListener::binderDied(const wp& /* who */) { Mutex::Autolock lock(mSplitter->mMutex); mSplitter->onAbandonedLocked(); } StreamSplitter::BufferTracker::BufferTracker(const sp& buffer) : mBuffer(buffer), mMergedFence(Fence::NO_FENCE), mReleaseCount(0) {} StreamSplitter::BufferTracker::~BufferTracker() {} void StreamSplitter::BufferTracker::mergeFence(const sp& with) { mMergedFence = Fence::merge(String8("StreamSplitter"), mMergedFence, with); } } // namespace android libs/gui/Surface.cpp0100644 0000000 0000000 00000121353 13077405420 013425 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "Surface" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { Surface::Surface( const sp& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), mGenerationNumber(0), mSharedBufferMode(false), mAutoRefresh(false), mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), mSharedBufferHasBeenQueued(false) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; ANativeWindow::dequeueBuffer = hook_dequeueBuffer; ANativeWindow::cancelBuffer = hook_cancelBuffer; ANativeWindow::queueBuffer = hook_queueBuffer; ANativeWindow::query = hook_query; ANativeWindow::perform = hook_perform; ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; const_cast(ANativeWindow::minSwapInterval) = 0; const_cast(ANativeWindow::maxSwapInterval) = 1; mReqWidth = 0; mReqHeight = 0; mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; mDataSpace = HAL_DATASPACE_UNKNOWN; mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; mDefaultWidth = 0; mDefaultHeight = 0; mUserWidth = 0; mUserHeight = 0; mTransformHint = 0; mConsumerRunningBehind = false; mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; } Surface::~Surface() { if (mConnectedToCpu) { Surface::disconnect(NATIVE_WINDOW_API_CPU); } } sp Surface::getIGraphicBufferProducer() const { return mGraphicBufferProducer; } void Surface::setSidebandStream(const sp& stream) { mGraphicBufferProducer->setSidebandStream(stream); } void Surface::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; mGraphicBufferProducer->allocateBuffers(reqWidth, reqHeight, mReqFormat, mReqUsage); } status_t Surface::setGenerationNumber(uint32_t generation) { status_t result = mGraphicBufferProducer->setGenerationNumber(generation); if (result == NO_ERROR) { mGenerationNumber = generation; } return result; } uint64_t Surface::getNextFrameNumber() const { return mGraphicBufferProducer->getNextFrameNumber(); } String8 Surface::getConsumerName() const { return mGraphicBufferProducer->getConsumerName(); } status_t Surface::setDequeueTimeout(nsecs_t timeout) { return mGraphicBufferProducer->setDequeueTimeout(timeout); } status_t Surface::getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) { return mGraphicBufferProducer->getLastQueuedBuffer(outBuffer, outFence, outTransformMatrix); } int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { Surface* c = getSelf(window); return c->setSwapInterval(interval); } int Surface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { Surface* c = getSelf(window); return c->dequeueBuffer(buffer, fenceFd); } int Surface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { Surface* c = getSelf(window); return c->cancelBuffer(buffer, fenceFd); } int Surface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { Surface* c = getSelf(window); return c->queueBuffer(buffer, fenceFd); } int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { Surface* c = getSelf(window); ANativeWindowBuffer* buf; int fenceFd = -1; int result = c->dequeueBuffer(&buf, &fenceFd); if (result != OK) { return result; } sp fence(new Fence(fenceFd)); int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); if (waitResult != OK) { ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult); c->cancelBuffer(buf, -1); return waitResult; } *buffer = buf; return result; } int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { Surface* c = getSelf(window); return c->cancelBuffer(buffer, -1); } int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { Surface* c = getSelf(window); return c->lockBuffer_DEPRECATED(buffer); } int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { Surface* c = getSelf(window); return c->queueBuffer(buffer, -1); } int Surface::hook_query(const ANativeWindow* window, int what, int* value) { const Surface* c = getSelf(window); return c->query(what, value); } int Surface::hook_perform(ANativeWindow* window, int operation, ...) { va_list args; va_start(args, operation); Surface* c = getSelf(window); int result = c->perform(operation, args); va_end(args); return result; } int Surface::setSwapInterval(int interval) { ATRACE_CALL(); // EGL specification states: // interval is silently clamped to minimum and maximum implementation // dependent values before being stored. if (interval < minSwapInterval) interval = minSwapInterval; if (interval > maxSwapInterval) interval = maxSwapInterval; mSwapIntervalZero = (interval == 0); mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero); return NO_ERROR; } int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); uint32_t reqWidth; uint32_t reqHeight; PixelFormat reqFormat; uint32_t reqUsage; { Mutex::Autolock lock(mMutex); reqWidth = mReqWidth ? mReqWidth : mUserWidth; reqHeight = mReqHeight ? mReqHeight : mUserHeight; reqFormat = mReqFormat; reqUsage = mReqUsage; if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { sp& gbuf(mSlots[mSharedBufferSlot].buffer); if (gbuf != NULL) { *buffer = gbuf.get(); *fenceFd = -1; return OK; } } } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer int buf = -1; sp fence; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, reqFormat, reqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer" "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat, reqUsage, result); return result; } Mutex::Autolock lock(mMutex); sp& gbuf(mSlots[buf].buffer); // this should never happen ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); } if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); mGraphicBufferProducer->cancelBuffer(buf, fence); return result; } } if (fence->isValid()) { *fenceFd = fence->dup(); if (*fenceFd == -1) { ALOGE("dequeueBuffer: error duping fence: %d", errno); // dup() should never fail; something is badly wrong. Soldier on // and hope for the best; the worst that should happen is some // visible corruption that lasts until the next frame. } } else { *fenceFd = -1; } *buffer = gbuf.get(); if (mSharedBufferMode && mAutoRefresh) { mSharedBufferSlot = buf; mSharedBufferHasBeenQueued = false; } else if (mSharedBufferSlot == buf) { mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; mSharedBufferHasBeenQueued = false; } return OK; } int Surface::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); ALOGV("Surface::cancelBuffer"); Mutex::Autolock lock(mMutex); int i = getSlotFromBufferLocked(buffer); if (i < 0) { if (fenceFd >= 0) { close(fenceFd); } return i; } if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { if (fenceFd >= 0) { close(fenceFd); } return OK; } sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); mGraphicBufferProducer->cancelBuffer(i, fence); if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == i) { mSharedBufferHasBeenQueued = true; } return OK; } int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { return i; } } ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); return BAD_VALUE; } int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__((unused))) { ALOGV("Surface::lockBuffer"); Mutex::Autolock lock(mMutex); return OK; } int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); ALOGV("Surface::queueBuffer"); Mutex::Autolock lock(mMutex); int64_t timestamp; bool isAutoTimestamp = false; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); isAutoTimestamp = true; ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", timestamp / 1000000.f); } else { timestamp = mTimestamp; } int i = getSlotFromBufferLocked(buffer); if (i < 0) { if (fenceFd >= 0) { close(fenceFd); } return i; } if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { if (fenceFd >= 0) { close(fenceFd); } return OK; } // Make sure the crop rectangle is entirely inside the buffer. Rect crop(Rect::EMPTY_RECT); mCrop.intersect(Rect(buffer->width, buffer->height), &crop); sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, fence, mStickyTransform); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); } else { // Here we do two things: // 1) The surface damage was specified using the OpenGL ES convention of // the origin being in the bottom-left corner. Here we flip to the // convention that the rest of the system uses (top-left corner) by // subtracting all top/bottom coordinates from the buffer height. // 2) If the buffer is coming in rotated (for example, because the EGL // implementation is reacting to the transform hint coming back from // SurfaceFlinger), the surface damage needs to be rotated the // opposite direction, since it was generated assuming an unrotated // buffer (the app doesn't know that the EGL implementation is // reacting to the transform hint behind its back). The // transformations in the switch statement below apply those // complementary rotations (e.g., if 90 degrees, rotate 270 degrees). int width = buffer->width; int height = buffer->height; bool rotated90 = (mTransform ^ mStickyTransform) & NATIVE_WINDOW_TRANSFORM_ROT_90; if (rotated90) { std::swap(width, height); } Region flippedRegion; for (auto rect : mDirtyRegion) { int left = rect.left; int right = rect.right; int top = height - rect.bottom; // Flip from OpenGL convention int bottom = height - rect.top; // Flip from OpenGL convention switch (mTransform ^ mStickyTransform) { case NATIVE_WINDOW_TRANSFORM_ROT_90: { // Rotate 270 degrees Rect flippedRect{top, width - right, bottom, width - left}; flippedRegion.orSelf(flippedRect); break; } case NATIVE_WINDOW_TRANSFORM_ROT_180: { // Rotate 180 degrees Rect flippedRect{width - right, height - bottom, width - left, height - top}; flippedRegion.orSelf(flippedRect); break; } case NATIVE_WINDOW_TRANSFORM_ROT_270: { // Rotate 90 degrees Rect flippedRect{height - bottom, left, height - top, right}; flippedRegion.orSelf(flippedRect); break; } default: { Rect flippedRect{left, top, right, bottom}; flippedRegion.orSelf(flippedRect); break; } } } input.setSurfaceDamage(flippedRegion); } status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); } uint32_t numPendingBuffers = 0; uint32_t hint = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, &numPendingBuffers); // Disable transform hint if sticky transform is set. if (mStickyTransform == 0) { mTransformHint = hint; } mConsumerRunningBehind = (numPendingBuffers >= 2); if (!mConnectedToCpu) { // Clear surface damage back to full-buffer mDirtyRegion = Region::INVALID_REGION; } if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == i) { mSharedBufferHasBeenQueued = true; } mQueueBufferCondition.broadcast(); return err; } int Surface::query(int what, int* value) const { ATRACE_CALL(); ALOGV("Surface::query"); { // scope for the lock Mutex::Autolock lock(mMutex); switch (what) { case NATIVE_WINDOW_FORMAT: if (mReqFormat) { *value = static_cast(mReqFormat); return NO_ERROR; } break; case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { sp composer( ComposerService::getComposerService()); if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) { *value = 1; } else { *value = 0; } return NO_ERROR; } case NATIVE_WINDOW_CONCRETE_TYPE: *value = NATIVE_WINDOW_SURFACE; return NO_ERROR; case NATIVE_WINDOW_DEFAULT_WIDTH: *value = static_cast( mUserWidth ? mUserWidth : mDefaultWidth); return NO_ERROR; case NATIVE_WINDOW_DEFAULT_HEIGHT: *value = static_cast( mUserHeight ? mUserHeight : mDefaultHeight); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: *value = static_cast(mTransformHint); return NO_ERROR; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { status_t err = NO_ERROR; if (!mConsumerRunningBehind) { *value = 0; } else { err = mGraphicBufferProducer->query(what, value); if (err == NO_ERROR) { mConsumerRunningBehind = *value; } } return err; } } } return mGraphicBufferProducer->query(what, value); } int Surface::perform(int operation, va_list args) { int res = NO_ERROR; switch (operation) { case NATIVE_WINDOW_CONNECT: // deprecated. must return NO_ERROR. break; case NATIVE_WINDOW_DISCONNECT: // deprecated. must return NO_ERROR. break; case NATIVE_WINDOW_SET_USAGE: res = dispatchSetUsage(args); break; case NATIVE_WINDOW_SET_CROP: res = dispatchSetCrop(args); break; case NATIVE_WINDOW_SET_BUFFER_COUNT: res = dispatchSetBufferCount(args); break; case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: res = dispatchSetBuffersGeometry(args); break; case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatchSetBuffersTransform(args); break; case NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM: res = dispatchSetBuffersStickyTransform(args); break; case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: res = dispatchSetBuffersTimestamp(args); break; case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: res = dispatchSetBuffersDimensions(args); break; case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: res = dispatchSetBuffersUserDimensions(args); break; case NATIVE_WINDOW_SET_BUFFERS_FORMAT: res = dispatchSetBuffersFormat(args); break; case NATIVE_WINDOW_LOCK: res = dispatchLock(args); break; case NATIVE_WINDOW_UNLOCK_AND_POST: res = dispatchUnlockAndPost(args); break; case NATIVE_WINDOW_SET_SCALING_MODE: res = dispatchSetScalingMode(args); break; case NATIVE_WINDOW_API_CONNECT: res = dispatchConnect(args); break; case NATIVE_WINDOW_API_DISCONNECT: res = dispatchDisconnect(args); break; case NATIVE_WINDOW_SET_SIDEBAND_STREAM: res = dispatchSetSidebandStream(args); break; case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: res = dispatchSetBuffersDataSpace(args); break; case NATIVE_WINDOW_SET_SURFACE_DAMAGE: res = dispatchSetSurfaceDamage(args); break; case NATIVE_WINDOW_SET_SHARED_BUFFER_MODE: res = dispatchSetSharedBufferMode(args); break; case NATIVE_WINDOW_SET_AUTO_REFRESH: res = dispatchSetAutoRefresh(args); break; default: res = NAME_NOT_FOUND; break; } return res; } int Surface::dispatchConnect(va_list args) { int api = va_arg(args, int); return connect(api); } int Surface::dispatchDisconnect(va_list args) { int api = va_arg(args, int); return disconnect(api); } int Surface::dispatchSetUsage(va_list args) { int usage = va_arg(args, int); return setUsage(static_cast(usage)); } int Surface::dispatchSetCrop(va_list args) { android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); return setCrop(reinterpret_cast(rect)); } int Surface::dispatchSetBufferCount(va_list args) { size_t bufferCount = va_arg(args, size_t); return setBufferCount(static_cast(bufferCount)); } int Surface::dispatchSetBuffersGeometry(va_list args) { uint32_t width = va_arg(args, uint32_t); uint32_t height = va_arg(args, uint32_t); PixelFormat format = va_arg(args, PixelFormat); int err = setBuffersDimensions(width, height); if (err != 0) { return err; } return setBuffersFormat(format); } int Surface::dispatchSetBuffersDimensions(va_list args) { uint32_t width = va_arg(args, uint32_t); uint32_t height = va_arg(args, uint32_t); return setBuffersDimensions(width, height); } int Surface::dispatchSetBuffersUserDimensions(va_list args) { uint32_t width = va_arg(args, uint32_t); uint32_t height = va_arg(args, uint32_t); return setBuffersUserDimensions(width, height); } int Surface::dispatchSetBuffersFormat(va_list args) { PixelFormat format = va_arg(args, PixelFormat); return setBuffersFormat(format); } int Surface::dispatchSetScalingMode(va_list args) { int mode = va_arg(args, int); return setScalingMode(mode); } int Surface::dispatchSetBuffersTransform(va_list args) { uint32_t transform = va_arg(args, uint32_t); return setBuffersTransform(transform); } int Surface::dispatchSetBuffersStickyTransform(va_list args) { uint32_t transform = va_arg(args, uint32_t); return setBuffersStickyTransform(transform); } int Surface::dispatchSetBuffersTimestamp(va_list args) { int64_t timestamp = va_arg(args, int64_t); return setBuffersTimestamp(timestamp); } int Surface::dispatchLock(va_list args) { ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); ARect* inOutDirtyBounds = va_arg(args, ARect*); return lock(outBuffer, inOutDirtyBounds); } int Surface::dispatchUnlockAndPost(va_list args __attribute__((unused))) { return unlockAndPost(); } int Surface::dispatchSetSidebandStream(va_list args) { native_handle_t* sH = va_arg(args, native_handle_t*); sp sidebandHandle = NativeHandle::create(sH, false); setSidebandStream(sidebandHandle); return OK; } int Surface::dispatchSetBuffersDataSpace(va_list args) { android_dataspace dataspace = static_cast(va_arg(args, int)); return setBuffersDataSpace(dataspace); } int Surface::dispatchSetSurfaceDamage(va_list args) { android_native_rect_t* rects = va_arg(args, android_native_rect_t*); size_t numRects = va_arg(args, size_t); setSurfaceDamage(rects, numRects); return NO_ERROR; } int Surface::dispatchSetSharedBufferMode(va_list args) { bool sharedBufferMode = va_arg(args, int); return setSharedBufferMode(sharedBufferMode); } int Surface::dispatchSetAutoRefresh(va_list args) { bool autoRefresh = va_arg(args, int); return setAutoRefresh(autoRefresh); } int Surface::connect(int api) { static sp listener = new DummyProducerListener(); return connect(api, listener); } int Surface::connect(int api, const sp& listener) { ATRACE_CALL(); ALOGV("Surface::connect"); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; uint32_t hint = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, &numPendingBuffers); // Disable transform hint if sticky transform is set. if (mStickyTransform == 0) { mTransformHint = hint; } mConsumerRunningBehind = (numPendingBuffers >= 2); } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; // Clear the dirty region in case we're switching from a non-CPU API mDirtyRegion.clear(); } else if (!err) { // Initialize the dirty region for tracking surface damage mDirtyRegion = Region::INVALID_REGION; } return err; } int Surface::disconnect(int api) { ATRACE_CALL(); ALOGV("Surface::disconnect"); Mutex::Autolock lock(mMutex); mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; mSharedBufferHasBeenQueued = false; freeAllBuffers(); int err = mGraphicBufferProducer->disconnect(api); if (!err) { mReqFormat = 0; mReqWidth = 0; mReqHeight = 0; mReqUsage = 0; mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; } } return err; } int Surface::detachNextBuffer(sp* outBuffer, sp* outFence) { ATRACE_CALL(); ALOGV("Surface::detachNextBuffer"); if (outBuffer == NULL || outFence == NULL) { return BAD_VALUE; } Mutex::Autolock lock(mMutex); sp buffer(NULL); sp fence(NULL); status_t result = mGraphicBufferProducer->detachNextBuffer( &buffer, &fence); if (result != NO_ERROR) { return result; } *outBuffer = buffer; if (fence != NULL && fence->isValid()) { *outFence = fence; } else { *outFence = Fence::NO_FENCE; } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { mSlots[i].buffer = NULL; } } return NO_ERROR; } int Surface::attachBuffer(ANativeWindowBuffer* buffer) { ATRACE_CALL(); ALOGV("Surface::attachBuffer"); Mutex::Autolock lock(mMutex); sp graphicBuffer(static_cast(buffer)); uint32_t priorGeneration = graphicBuffer->mGenerationNumber; graphicBuffer->mGenerationNumber = mGenerationNumber; int32_t attachedSlot = -1; status_t result = mGraphicBufferProducer->attachBuffer( &attachedSlot, graphicBuffer); if (result != NO_ERROR) { ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result); graphicBuffer->mGenerationNumber = priorGeneration; return result; } mSlots[attachedSlot].buffer = graphicBuffer; return NO_ERROR; } int Surface::setUsage(uint32_t reqUsage) { ALOGV("Surface::setUsage"); Mutex::Autolock lock(mMutex); if (reqUsage != mReqUsage) { mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; } mReqUsage = reqUsage; return OK; } int Surface::setCrop(Rect const* rect) { ATRACE_CALL(); Rect realRect(Rect::EMPTY_RECT); if (rect == NULL || rect->isEmpty()) { realRect.clear(); } else { realRect = *rect; } ALOGV("Surface::setCrop rect=[%d %d %d %d]", realRect.left, realRect.top, realRect.right, realRect.bottom); Mutex::Autolock lock(mMutex); mCrop = realRect; return NO_ERROR; } int Surface::setBufferCount(int bufferCount) { ATRACE_CALL(); ALOGV("Surface::setBufferCount"); Mutex::Autolock lock(mMutex); status_t err = NO_ERROR; if (bufferCount == 0) { err = mGraphicBufferProducer->setMaxDequeuedBufferCount(1); } else { int minUndequeuedBuffers = 0; err = mGraphicBufferProducer->query( NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers); if (err == NO_ERROR) { err = mGraphicBufferProducer->setMaxDequeuedBufferCount( bufferCount - minUndequeuedBuffers); } } ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", bufferCount, strerror(-err)); return err; } int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) { ATRACE_CALL(); ALOGV("Surface::setMaxDequeuedBufferCount"); Mutex::Autolock lock(mMutex); status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount( maxDequeuedBuffers); ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) " "returned %s", maxDequeuedBuffers, strerror(-err)); return err; } int Surface::setAsyncMode(bool async) { ATRACE_CALL(); ALOGV("Surface::setAsyncMode"); Mutex::Autolock lock(mMutex); status_t err = mGraphicBufferProducer->setAsyncMode(async); ALOGE_IF(err, "IGraphicBufferProducer::setAsyncMode(%d) returned %s", async, strerror(-err)); return err; } int Surface::setSharedBufferMode(bool sharedBufferMode) { ATRACE_CALL(); ALOGV("Surface::setSharedBufferMode (%d)", sharedBufferMode); Mutex::Autolock lock(mMutex); status_t err = mGraphicBufferProducer->setSharedBufferMode( sharedBufferMode); if (err == NO_ERROR) { mSharedBufferMode = sharedBufferMode; } ALOGE_IF(err, "IGraphicBufferProducer::setSharedBufferMode(%d) returned" "%s", sharedBufferMode, strerror(-err)); return err; } int Surface::setAutoRefresh(bool autoRefresh) { ATRACE_CALL(); ALOGV("Surface::setAutoRefresh (%d)", autoRefresh); Mutex::Autolock lock(mMutex); status_t err = mGraphicBufferProducer->setAutoRefresh(autoRefresh); if (err == NO_ERROR) { mAutoRefresh = autoRefresh; } ALOGE_IF(err, "IGraphicBufferProducer::setAutoRefresh(%d) returned %s", autoRefresh, strerror(-err)); return err; } int Surface::setBuffersDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersDimensions"); if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); if (width != mReqWidth || height != mReqHeight) { mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; } mReqWidth = width; mReqHeight = height; return NO_ERROR; } int Surface::setBuffersUserDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersUserDimensions"); if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); if (width != mUserWidth || height != mUserHeight) { mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; } mUserWidth = width; mUserHeight = height; return NO_ERROR; } int Surface::setBuffersFormat(PixelFormat format) { ALOGV("Surface::setBuffersFormat"); Mutex::Autolock lock(mMutex); if (format != mReqFormat) { mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT; } mReqFormat = format; return NO_ERROR; } int Surface::setScalingMode(int mode) { ATRACE_CALL(); ALOGV("Surface::setScalingMode(%d)", mode); switch (mode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: break; default: ALOGE("unknown scaling mode: %d", mode); return BAD_VALUE; } Mutex::Autolock lock(mMutex); mScalingMode = mode; return NO_ERROR; } int Surface::setBuffersTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersTransform"); Mutex::Autolock lock(mMutex); mTransform = transform; return NO_ERROR; } int Surface::setBuffersStickyTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersStickyTransform"); Mutex::Autolock lock(mMutex); mStickyTransform = transform; return NO_ERROR; } int Surface::setBuffersTimestamp(int64_t timestamp) { ALOGV("Surface::setBuffersTimestamp"); Mutex::Autolock lock(mMutex); mTimestamp = timestamp; return NO_ERROR; } int Surface::setBuffersDataSpace(android_dataspace dataSpace) { ALOGV("Surface::setBuffersDataSpace"); Mutex::Autolock lock(mMutex); mDataSpace = dataSpace; return NO_ERROR; } void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; } } void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { ATRACE_CALL(); ALOGV("Surface::setSurfaceDamage"); Mutex::Autolock lock(mMutex); if (mConnectedToCpu || numRects == 0) { mDirtyRegion = Region::INVALID_REGION; return; } mDirtyRegion.clear(); for (size_t r = 0; r < numRects; ++r) { // We intentionally flip top and bottom here, since because they're // specified with a bottom-left origin, top > bottom, which fails // validation in the Region class. We will fix this up when we flip to a // top-left origin in queueBuffer. Rect rect(rects[r].left, rects[r].bottom, rects[r].right, rects[r].top); mDirtyRegion.orSelf(rect); } } // ---------------------------------------------------------------------- // the lock/unlock APIs must be used from the same thread static status_t copyBlt( const sp& dst, const sp& src, const Region& reg) { // src and dst with, height and format must be identical. no verification // is done here. status_t err; uint8_t* src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), reinterpret_cast(&src_bits)); ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); uint8_t* dst_bits = NULL; err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), reinterpret_cast(&dst_bits)); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); Region::const_iterator head(reg.begin()); Region::const_iterator tail(reg.end()); if (head != tail && src_bits && dst_bits) { const size_t bpp = bytesPerPixel(src->format); const size_t dbpr = static_cast(dst->stride) * bpp; const size_t sbpr = static_cast(src->stride) * bpp; while (head != tail) { const Rect& r(*head++); int32_t h = r.height(); if (h <= 0) continue; size_t size = static_cast(r.width()) * bpp; uint8_t const * s = src_bits + static_cast(r.left + src->stride * r.top) * bpp; uint8_t * d = dst_bits + static_cast(r.left + dst->stride * r.top) * bpp; if (dbpr==sbpr && size==sbpr) { size *= static_cast(h); h = 1; } do { memcpy(d, s, size); d += dbpr; s += sbpr; } while (--h > 0); } } if (src_bits) src->unlock(); if (dst_bits) dst->unlock(); return err; } // ---------------------------------------------------------------------------- status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { if (mLockedBuffer != 0) { ALOGE("Surface::lock failed, already locked"); return INVALID_OPERATION; } if (!mConnectedToCpu) { int err = Surface::connect(NATIVE_WINDOW_API_CPU); if (err) { return err; } // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); } ANativeWindowBuffer* out; int fenceFd = -1; status_t err = dequeueBuffer(&out, &fenceFd); ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { sp backBuffer(GraphicBuffer::getSelf(out)); const Rect bounds(backBuffer->width, backBuffer->height); Region newDirtyRegion; if (inOutDirtyBounds) { newDirtyRegion.set(static_cast(*inOutDirtyBounds)); newDirtyRegion.andSelf(bounds); } else { newDirtyRegion.set(bounds); } // figure out if we can copy the frontbuffer back const sp& frontBuffer(mPostedBuffer); const bool canCopyBack = (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && backBuffer->format == frontBuffer->format); if (canCopyBack) { // copy the area that is invalid and not repainted this round const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); if (!copyback.isEmpty()) copyBlt(backBuffer, frontBuffer, copyback); } else { // if we can't copy-back anything, modify the user's dirty // region to make sure they redraw the whole buffer newDirtyRegion.set(bounds); mDirtyRegion.clear(); Mutex::Autolock lock(mMutex); for (size_t i=0 ; i= 0) { Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); mDirtyRegion.subtract(dirtyRegion); dirtyRegion = newDirtyRegion; } } mDirtyRegion.orSelf(newDirtyRegion); if (inOutDirtyBounds) { *inOutDirtyBounds = newDirtyRegion.getBounds(); } void* vaddr; status_t res = backBuffer->lockAsync( GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd); ALOGW_IF(res, "failed locking buffer (handle = %p)", backBuffer->handle); if (res != 0) { err = INVALID_OPERATION; } else { mLockedBuffer = backBuffer; outBuffer->width = backBuffer->width; outBuffer->height = backBuffer->height; outBuffer->stride = backBuffer->stride; outBuffer->format = backBuffer->format; outBuffer->bits = vaddr; } } return err; } status_t Surface::unlockAndPost() { if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } int fd = -1; status_t err = mLockedBuffer->unlockAsync(&fd); ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); err = queueBuffer(mLockedBuffer.get(), fd); ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; mLockedBuffer = 0; return err; } bool Surface::waitForNextFrame(uint64_t lastFrame, nsecs_t timeout) { Mutex::Autolock lock(mMutex); uint64_t currentFrame = mGraphicBufferProducer->getNextFrameNumber(); if (currentFrame > lastFrame) { return true; } return mQueueBufferCondition.waitRelative(mMutex, timeout) == OK; } status_t Surface::getUniqueId(uint64_t* outId) const { Mutex::Autolock lock(mMutex); return mGraphicBufferProducer->getUniqueId(outId); } namespace view { status_t Surface::writeToParcel(Parcel* parcel) const { return writeToParcel(parcel, false); } status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (parcel == nullptr) return BAD_VALUE; status_t res = OK; if (!nameAlreadyWritten) res = parcel->writeString16(name); if (res == OK) { res = parcel->writeStrongBinder( IGraphicBufferProducer::asBinder(graphicBufferProducer)); } return res; } status_t Surface::readFromParcel(const Parcel* parcel) { return readFromParcel(parcel, false); } status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { if (parcel == nullptr) return BAD_VALUE; if (!nameAlreadyRead) { name = readMaybeEmptyString16(parcel); } sp binder; status_t res = parcel->readStrongBinder(&binder); if (res != OK) return res; graphicBufferProducer = interface_cast(binder); return OK; } String16 Surface::readMaybeEmptyString16(const Parcel* parcel) { size_t len; const char16_t* str = parcel->readString16Inplace(&len); if (str != nullptr) { return String16(str, len); } else { return String16(); } } } // namespace view }; // namespace android libs/gui/SurfaceComposerClient.cpp0100644 0000000 0000000 00000071277 13077405420 016305 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "SurfaceComposerClient" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); ComposerService::ComposerService() : Singleton() { Mutex::Autolock _l(mLock); connectLocked(); } void ComposerService::connectLocked() { const String16 name("SurfaceFlinger"); while (getService(name, &mComposerService) != NO_ERROR) { usleep(250000); } assert(mComposerService != NULL); // Create the death listener. class DeathObserver : public IBinder::DeathRecipient { ComposerService& mComposerService; virtual void binderDied(const wp& who) { ALOGW("ComposerService remote (surfaceflinger) died [%p]", who.unsafe_get()); mComposerService.composerServiceDied(); } public: DeathObserver(ComposerService& mgr) : mComposerService(mgr) { } }; mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); } /*static*/ sp ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); if (instance.mComposerService == NULL) { ComposerService::getInstance().connectLocked(); assert(instance.mComposerService != NULL); ALOGD("ComposerService reconnected"); } return instance.mComposerService; } void ComposerService::composerServiceDied() { Mutex::Autolock _l(mLock); mComposerService = NULL; mDeathObserver = NULL; } // --------------------------------------------------------------------------- static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) { if (lhs.client < rhs.client) return -1; if (lhs.client > rhs.client) return 1; if (lhs.state.surface < rhs.state.surface) return -1; if (lhs.state.surface > rhs.state.surface) return 1; return 0; } static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) { return compare_type(lhs.token, rhs.token); } class Composer : public Singleton { friend class Singleton; mutable Mutex mLock; SortedVector mComposerStates; SortedVector mDisplayStates; uint32_t mForceSynchronous; uint32_t mTransactionNestCount; bool mAnimation; Composer() : Singleton(), mForceSynchronous(0), mTransactionNestCount(0), mAnimation(false) { } void openGlobalTransactionImpl(); void closeGlobalTransactionImpl(bool synchronous); void setAnimationTransactionImpl(); layer_state_t* getLayerStateLocked( const sp& client, const sp& id); DisplayState& getDisplayStateLocked(const sp& token); public: sp createDisplay(const String8& displayName, bool secure); void destroyDisplay(const sp& display); sp getBuiltInDisplay(int32_t id); status_t setPosition(const sp& client, const sp& id, float x, float y); status_t setSize(const sp& client, const sp& id, uint32_t w, uint32_t h); status_t setLayer(const sp& client, const sp& id, uint32_t z); status_t setFlags(const sp& client, const sp& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint( const sp& client, const sp& id, const Region& transparentRegion); status_t setAlpha(const sp& client, const sp& id, float alpha); status_t setMatrix(const sp& client, const sp& id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setOrientation(int orientation); status_t setCrop(const sp& client, const sp& id, const Rect& crop); status_t setFinalCrop(const sp& client, const sp& id, const Rect& crop); status_t setLayerStack(const sp& client, const sp& id, uint32_t layerStack); status_t deferTransactionUntil(const sp& client, const sp& id, const sp& handle, uint64_t frameNumber); status_t setOverrideScalingMode(const sp& client, const sp& id, int32_t overrideScalingMode); status_t setPositionAppliesWithResize(const sp& client, const sp& id); void setDisplaySurface(const sp& token, const sp& bufferProducer); void setDisplayLayerStack(const sp& token, uint32_t layerStack); void setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); void setDisplaySize(const sp& token, uint32_t width, uint32_t height); static void setAnimationTransaction() { Composer::getInstance().setAnimationTransactionImpl(); } static void openGlobalTransaction() { Composer::getInstance().openGlobalTransactionImpl(); } static void closeGlobalTransaction(bool synchronous) { Composer::getInstance().closeGlobalTransactionImpl(synchronous); } }; ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- sp Composer::createDisplay(const String8& displayName, bool secure) { return ComposerService::getComposerService()->createDisplay(displayName, secure); } void Composer::destroyDisplay(const sp& display) { return ComposerService::getComposerService()->destroyDisplay(display); } sp Composer::getBuiltInDisplay(int32_t id) { return ComposerService::getComposerService()->getBuiltInDisplay(id); } void Composer::openGlobalTransactionImpl() { { // scope for the lock Mutex::Autolock _l(mLock); mTransactionNestCount += 1; } } void Composer::closeGlobalTransactionImpl(bool synchronous) { sp sm(ComposerService::getComposerService()); Vector transaction; Vector displayTransaction; uint32_t flags = 0; { // scope for the lock Mutex::Autolock _l(mLock); mForceSynchronous |= synchronous; if (!mTransactionNestCount) { ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " "call to openGlobalTransaction()."); } else if (--mTransactionNestCount) { return; } transaction = mComposerStates; mComposerStates.clear(); displayTransaction = mDisplayStates; mDisplayStates.clear(); if (mForceSynchronous) { flags |= ISurfaceComposer::eSynchronous; } if (mAnimation) { flags |= ISurfaceComposer::eAnimation; } mForceSynchronous = false; mAnimation = false; } sm->setTransactionState(transaction, displayTransaction, flags); } void Composer::setAnimationTransactionImpl() { Mutex::Autolock _l(mLock); mAnimation = true; } layer_state_t* Composer::getLayerStateLocked( const sp& client, const sp& id) { ComposerState s; s.client = client->mClient; s.state.surface = id; ssize_t index = mComposerStates.indexOf(s); if (index < 0) { // we don't have it, add an initialized layer_state to our list index = mComposerStates.add(s); } ComposerState* const out = mComposerStates.editArray(); return &(out[index].state); } status_t Composer::setPosition(const sp& client, const sp& id, float x, float y) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; return NO_ERROR; } status_t Composer::setSize(const sp& client, const sp& id, uint32_t w, uint32_t h) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; // Resizing a surface makes the transaction synchronous. mForceSynchronous = true; return NO_ERROR; } status_t Composer::setLayer(const sp& client, const sp& id, uint32_t z) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eLayerChanged; s->z = z; return NO_ERROR; } status_t Composer::setFlags(const sp& client, const sp& id, uint32_t flags, uint32_t mask) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || (mask & layer_state_t::eLayerSecure)) { s->what |= layer_state_t::eFlagsChanged; } s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; return NO_ERROR; } status_t Composer::setTransparentRegionHint( const sp& client, const sp& id, const Region& transparentRegion) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; return NO_ERROR; } status_t Composer::setAlpha(const sp& client, const sp& id, float alpha) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; return NO_ERROR; } status_t Composer::setLayerStack(const sp& client, const sp& id, uint32_t layerStack) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; return NO_ERROR; } status_t Composer::setMatrix(const sp& client, const sp& id, float dsdx, float dtdx, float dsdy, float dtdy) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; matrix.dtdx = dtdx; matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; return NO_ERROR; } status_t Composer::setCrop(const sp& client, const sp& id, const Rect& crop) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; s->what |= layer_state_t::eCropChanged; s->crop = crop; return NO_ERROR; } status_t Composer::setFinalCrop(const sp& client, const sp& id, const Rect& crop) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) { return BAD_INDEX; } s->what |= layer_state_t::eFinalCropChanged; s->finalCrop = crop; return NO_ERROR; } status_t Composer::deferTransactionUntil( const sp& client, const sp& id, const sp& handle, uint64_t frameNumber) { Mutex::Autolock lock(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) { return BAD_INDEX; } s->what |= layer_state_t::eDeferTransaction; s->handle = handle; s->frameNumber = frameNumber; return NO_ERROR; } status_t Composer::setOverrideScalingMode( const sp& client, const sp& id, int32_t overrideScalingMode) { Mutex::Autolock lock(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) { return BAD_INDEX; } switch (overrideScalingMode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: case -1: break; default: ALOGE("unknown scaling mode: %d", overrideScalingMode); return BAD_VALUE; } s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; return NO_ERROR; } status_t Composer::setPositionAppliesWithResize( const sp& client, const sp& id) { Mutex::Autolock lock(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) { return BAD_INDEX; } s->what |= layer_state_t::ePositionAppliesWithResize; return NO_ERROR; } // --------------------------------------------------------------------------- DisplayState& Composer::getDisplayStateLocked(const sp& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); if (index < 0) { // we don't have it, add an initialized layer_state to our list s.what = 0; index = mDisplayStates.add(s); } return mDisplayStates.editItemAt(static_cast(index)); } void Composer::setDisplaySurface(const sp& token, const sp& bufferProducer) { Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; } void Composer::setDisplayLayerStack(const sp& token, uint32_t layerStack) { Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } void Composer::setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.orientation = orientation; s.viewport = layerStackRect; s.frame = displayRect; s.what |= DisplayState::eDisplayProjectionChanged; mForceSynchronous = true; // TODO: do we actually still need this? } void Composer::setDisplaySize(const sp& token, uint32_t width, uint32_t height) { Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); s.width = width; s.height = height; s.what |= DisplayState::eDisplaySizeChanged; } // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT), mComposer(Composer::getInstance()) { } void SurfaceComposerClient::onFirstRef() { sp sm(ComposerService::getComposerService()); if (sm != 0) { sp conn = sm->createConnection(); if (conn != 0) { mClient = conn; mStatus = NO_ERROR; } } } SurfaceComposerClient::~SurfaceComposerClient() { dispose(); } status_t SurfaceComposerClient::initCheck() const { return mStatus; } sp SurfaceComposerClient::connection() const { return IInterface::asBinder(mClient); } status_t SurfaceComposerClient::linkToComposerDeath( const sp& recipient, void* cookie, uint32_t flags) { sp sm(ComposerService::getComposerService()); return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. sp client; Mutex::Autolock _lm(mLock); if (mClient != 0) { client = mClient; // hold ref while lock is held mClient.clear(); } mStatus = NO_INIT; } sp SurfaceComposerClient::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { sp sur; if (mStatus == NO_ERROR) { sp handle; sp gbp; status_t err = mClient->createSurface(name, w, h, format, flags, &handle, &gbp); ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { sur = new SurfaceControl(this, handle, gbp); } } return sur; } sp SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { return Composer::getInstance().createDisplay(displayName, secure); } void SurfaceComposerClient::destroyDisplay(const sp& display) { Composer::getInstance().destroyDisplay(display); } sp SurfaceComposerClient::getBuiltInDisplay(int32_t id) { return Composer::getInstance().getBuiltInDisplay(id); } status_t SurfaceComposerClient::destroySurface(const sp& sid) { if (mStatus != NO_ERROR) return mStatus; status_t err = mClient->destroySurface(sid); return err; } status_t SurfaceComposerClient::clearLayerFrameStats(const sp& token) const { if (mStatus != NO_ERROR) { return mStatus; } return mClient->clearLayerFrameStats(token); } status_t SurfaceComposerClient::getLayerFrameStats(const sp& token, FrameStats* outStats) const { if (mStatus != NO_ERROR) { return mStatus; } return mClient->getLayerFrameStats(token, outStats); } inline Composer& SurfaceComposerClient::getComposer() { return mComposer; } // ---------------------------------------------------------------------------- void SurfaceComposerClient::openGlobalTransaction() { Composer::openGlobalTransaction(); } void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { Composer::closeGlobalTransaction(synchronous); } void SurfaceComposerClient::setAnimationTransaction() { Composer::setAnimationTransaction(); } // ---------------------------------------------------------------------------- status_t SurfaceComposerClient::setCrop(const sp& id, const Rect& crop) { return getComposer().setCrop(this, id, crop); } status_t SurfaceComposerClient::setFinalCrop(const sp& id, const Rect& crop) { return getComposer().setFinalCrop(this, id, crop); } status_t SurfaceComposerClient::setPosition(const sp& id, float x, float y) { return getComposer().setPosition(this, id, x, y); } status_t SurfaceComposerClient::setSize(const sp& id, uint32_t w, uint32_t h) { return getComposer().setSize(this, id, w, h); } status_t SurfaceComposerClient::setLayer(const sp& id, uint32_t z) { return getComposer().setLayer(this, id, z); } status_t SurfaceComposerClient::hide(const sp& id) { return getComposer().setFlags(this, id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } status_t SurfaceComposerClient::show(const sp& id) { return getComposer().setFlags(this, id, 0, layer_state_t::eLayerHidden); } status_t SurfaceComposerClient::setFlags(const sp& id, uint32_t flags, uint32_t mask) { return getComposer().setFlags(this, id, flags, mask); } status_t SurfaceComposerClient::setTransparentRegionHint(const sp& id, const Region& transparentRegion) { return getComposer().setTransparentRegionHint(this, id, transparentRegion); } status_t SurfaceComposerClient::setAlpha(const sp& id, float alpha) { return getComposer().setAlpha(this, id, alpha); } status_t SurfaceComposerClient::setLayerStack(const sp& id, uint32_t layerStack) { return getComposer().setLayerStack(this, id, layerStack); } status_t SurfaceComposerClient::setMatrix(const sp& id, float dsdx, float dtdx, float dsdy, float dtdy) { return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy); } status_t SurfaceComposerClient::deferTransactionUntil(const sp& id, const sp& handle, uint64_t frameNumber) { return getComposer().deferTransactionUntil(this, id, handle, frameNumber); } status_t SurfaceComposerClient::setOverrideScalingMode( const sp& id, int32_t overrideScalingMode) { return getComposer().setOverrideScalingMode( this, id, overrideScalingMode); } status_t SurfaceComposerClient::setPositionAppliesWithResize( const sp& id) { return getComposer().setPositionAppliesWithResize(this, id); } // ---------------------------------------------------------------------------- void SurfaceComposerClient::setDisplaySurface(const sp& token, const sp& bufferProducer) { Composer::getInstance().setDisplaySurface(token, bufferProducer); } void SurfaceComposerClient::setDisplayLayerStack(const sp& token, uint32_t layerStack) { Composer::getInstance().setDisplayLayerStack(token, layerStack); } void SurfaceComposerClient::setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { Composer::getInstance().setDisplayProjection(token, orientation, layerStackRect, displayRect); } void SurfaceComposerClient::setDisplaySize(const sp& token, uint32_t width, uint32_t height) { Composer::getInstance().setDisplaySize(token, width, height); } // ---------------------------------------------------------------------------- status_t SurfaceComposerClient::getDisplayConfigs( const sp& display, Vector* configs) { return ComposerService::getComposerService()->getDisplayConfigs(display, configs); } status_t SurfaceComposerClient::getDisplayInfo(const sp& display, DisplayInfo* info) { Vector configs; status_t result = getDisplayConfigs(display, &configs); if (result != NO_ERROR) { return result; } int activeId = getActiveConfig(display); if (activeId < 0) { ALOGE("No active configuration found"); return NAME_NOT_FOUND; } *info = configs[static_cast(activeId)]; return NO_ERROR; } int SurfaceComposerClient::getActiveConfig(const sp& display) { return ComposerService::getComposerService()->getActiveConfig(display); } status_t SurfaceComposerClient::setActiveConfig(const sp& display, int id) { return ComposerService::getComposerService()->setActiveConfig(display, id); } void SurfaceComposerClient::setDisplayPowerMode(const sp& token, int mode) { ComposerService::getComposerService()->setPowerMode(token, mode); } status_t SurfaceComposerClient::clearAnimationFrameStats() { return ComposerService::getComposerService()->clearAnimationFrameStats(); } status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { return ComposerService::getComposerService()->getAnimationFrameStats(outStats); } status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities) { return ComposerService::getComposerService()->getHdrCapabilities(display, outCapabilities); } // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture( const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform) { sp s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; return s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform); } ScreenshotClient::ScreenshotClient() : mHaveBuffer(false) { memset(&mBuffer, 0, sizeof(mBuffer)); } ScreenshotClient::~ScreenshotClient() { ScreenshotClient::release(); } sp ScreenshotClient::getCpuConsumer() const { if (mCpuConsumer == NULL) { sp consumer; BufferQueue::createBufferQueue(&mProducer, &consumer); mCpuConsumer = new CpuConsumer(consumer, 1); mCpuConsumer->setName(String8("ScreenshotClient")); } return mCpuConsumer; } status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, uint32_t rotation) { sp s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; sp cpuConsumer = getCpuConsumer(); if (mHaveBuffer) { mCpuConsumer->unlockBuffer(mBuffer); memset(&mBuffer, 0, sizeof(mBuffer)); mHaveBuffer = false; } status_t err = s->captureScreen(display, mProducer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, static_cast(rotation)); if (err == NO_ERROR) { err = mCpuConsumer->lockNextBuffer(&mBuffer); if (err == NO_ERROR) { mHaveBuffer = true; } } return err; } status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform) { return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone); } status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, bool useIdentityTransform) { return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone); } status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, 0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone); } void ScreenshotClient::release() { if (mHaveBuffer) { mCpuConsumer->unlockBuffer(mBuffer); memset(&mBuffer, 0, sizeof(mBuffer)); mHaveBuffer = false; } mCpuConsumer.clear(); } void const* ScreenshotClient::getPixels() const { return mBuffer.data; } uint32_t ScreenshotClient::getWidth() const { return mBuffer.width; } uint32_t ScreenshotClient::getHeight() const { return mBuffer.height; } PixelFormat ScreenshotClient::getFormat() const { return mBuffer.format; } uint32_t ScreenshotClient::getStride() const { return mBuffer.stride; } size_t ScreenshotClient::getSize() const { return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/SurfaceControl.cpp0100644 0000000 0000000 00000015601 13077405420 014764 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "SurfaceControl" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { // ============================================================================ // SurfaceControl // ============================================================================ SurfaceControl::SurfaceControl( const sp& client, const sp& handle, const sp& gbp) : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp) { } SurfaceControl::~SurfaceControl() { destroy(); } void SurfaceControl::destroy() { if (isValid()) { mClient->destroySurface(mHandle); } // clear all references and trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. mClient.clear(); mHandle.clear(); mGraphicBufferProducer.clear(); IPCThreadState::self()->flushCommands(); } void SurfaceControl::clear() { // here, the window manager tells us explicitly that we should destroy // the surface's resource. Soon after this call, it will also release // its last reference (which will call the dtor); however, it is possible // that a client living in the same process still holds references which // would delay the call to the dtor -- that is why we need this explicit // "clear()" call. destroy(); } void SurfaceControl::disconnect() { if (mGraphicBufferProducer != NULL) { mGraphicBufferProducer->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } } bool SurfaceControl::isSameSurface( const sp& lhs, const sp& rhs) { if (lhs == 0 || rhs == 0) return false; return lhs->mHandle == rhs->mHandle; } status_t SurfaceControl::setLayerStack(uint32_t layerStack) { status_t err = validate(); if (err < 0) return err; return mClient->setLayerStack(mHandle, layerStack); } status_t SurfaceControl::setLayer(uint32_t layer) { status_t err = validate(); if (err < 0) return err; return mClient->setLayer(mHandle, layer); } status_t SurfaceControl::setPosition(float x, float y) { status_t err = validate(); if (err < 0) return err; return mClient->setPosition(mHandle, x, y); } status_t SurfaceControl::setPositionAppliesWithResize() { status_t err = validate(); if (err < 0) return err; return mClient->setPositionAppliesWithResize(mHandle); } status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { status_t err = validate(); if (err < 0) return err; return mClient->setSize(mHandle, w, h); } status_t SurfaceControl::hide() { status_t err = validate(); if (err < 0) return err; return mClient->hide(mHandle); } status_t SurfaceControl::show() { status_t err = validate(); if (err < 0) return err; return mClient->show(mHandle); } status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { status_t err = validate(); if (err < 0) return err; return mClient->setFlags(mHandle, flags, mask); } status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { status_t err = validate(); if (err < 0) return err; return mClient->setTransparentRegionHint(mHandle, transparent); } status_t SurfaceControl::setAlpha(float alpha) { status_t err = validate(); if (err < 0) return err; return mClient->setAlpha(mHandle, alpha); } status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { status_t err = validate(); if (err < 0) return err; return mClient->setMatrix(mHandle, dsdx, dtdx, dsdy, dtdy); } status_t SurfaceControl::setCrop(const Rect& crop) { status_t err = validate(); if (err < 0) return err; return mClient->setCrop(mHandle, crop); } status_t SurfaceControl::setFinalCrop(const Rect& crop) { status_t err = validate(); if (err < 0) return err; return mClient->setFinalCrop(mHandle, crop); } status_t SurfaceControl::deferTransactionUntil(sp handle, uint64_t frameNumber) { status_t err = validate(); if (err < 0) return err; return mClient->deferTransactionUntil(mHandle, handle, frameNumber); } status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { status_t err = validate(); if (err < 0) return err; return mClient->setOverrideScalingMode(mHandle, overrideScalingMode); } status_t SurfaceControl::clearLayerFrameStats() const { status_t err = validate(); if (err < 0) return err; const sp& client(mClient); return client->clearLayerFrameStats(mHandle); } status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { status_t err = validate(); if (err < 0) return err; const sp& client(mClient); return client->getLayerFrameStats(mHandle, outStats); } status_t SurfaceControl::validate() const { if (mHandle==0 || mClient==0) { ALOGE("invalid handle (%p) or client (%p)", mHandle.get(), mClient.get()); return NO_INIT; } return NO_ERROR; } status_t SurfaceControl::writeSurfaceToParcel( const sp& control, Parcel* parcel) { sp bp; if (control != NULL) { bp = control->mGraphicBufferProducer; } return parcel->writeStrongBinder(IInterface::asBinder(bp)); } sp SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); if (mSurfaceData == 0) { // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. mSurfaceData = new Surface(mGraphicBufferProducer, false); } return mSurfaceData; } sp SurfaceControl::getHandle() const { Mutex::Autolock lock(mLock); return mHandle; } // ---------------------------------------------------------------------------- }; // namespace android libs/gui/SyncFeatures.cpp0100644 0000000 0000000 00000005736 13077405420 014456 0ustar000000000 0000000 /* ** Copyright 2013, 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. */ #define LOG_TAG "GLConsumer" #define EGL_EGLEXT_PROTOTYPES #include #include #include #include #include #include EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { ANDROID_SINGLETON_STATIC_INSTANCE(SyncFeatures); SyncFeatures::SyncFeatures() : Singleton(), mHasNativeFenceSync(false), mHasFenceSync(false), mHasWaitSync(false) { EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); // This can only be called after EGL has been initialized; otherwise the // check below will abort. const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed"); if (strstr(exts, "EGL_ANDROID_native_fence_sync")) { // This makes GLConsumer use the EGL_ANDROID_native_fence_sync // extension to create Android native fences to signal when all // GLES reads for a given buffer have completed. mHasNativeFenceSync = true; } if (strstr(exts, "EGL_KHR_fence_sync")) { mHasFenceSync = true; } if (strstr(exts, "EGL_KHR_wait_sync")) { mHasWaitSync = true; } mString.append("[using:"); if (useNativeFenceSync()) { mString.append(" EGL_ANDROID_native_fence_sync"); } if (useFenceSync()) { mString.append(" EGL_KHR_fence_sync"); } if (useWaitSync()) { mString.append(" EGL_KHR_wait_sync"); } mString.append("]"); } bool SyncFeatures::useNativeFenceSync() const { // EGL_ANDROID_native_fence_sync is not compatible with using the // EGL_KHR_fence_sync extension for the same purpose. return mHasNativeFenceSync; } bool SyncFeatures::useFenceSync() const { #ifdef DONT_USE_FENCE_SYNC // on some devices it's better to not use EGL_KHR_fence_sync // even if they have it return false; #else // currently we shall only attempt to use EGL_KHR_fence_sync if // USE_FENCE_SYNC is set in our makefile return !mHasNativeFenceSync && mHasFenceSync; #endif } bool SyncFeatures::useWaitSync() const { return (useNativeFenceSync() || useFenceSync()) && mHasWaitSync; } String8 SyncFeatures::toString() const { return mString; } } // namespace android libs/gui/tests/0040755 0000000 0000000 00000000000 13077405420 012471 5ustar000000000 0000000 libs/gui/tests/Android.mk0100644 0000000 0000000 00000002460 13077405420 014401 0ustar000000000 0000000 # Build the unit tests, LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true LOCAL_MODULE := libgui_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ BufferQueue_test.cpp \ CpuConsumer_test.cpp \ FillBuffer.cpp \ GLTest.cpp \ IGraphicBufferProducer_test.cpp \ MultiTextureConsumer_test.cpp \ SRGB_test.cpp \ StreamSplitter_test.cpp \ SurfaceTextureClient_test.cpp \ SurfaceTextureFBO_test.cpp \ SurfaceTextureGLThreadToGL_test.cpp \ SurfaceTextureGLToGL_test.cpp \ SurfaceTextureGL_test.cpp \ SurfaceTextureMultiContextGL_test.cpp \ Surface_test.cpp \ TextureRenderer.cpp \ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv1_CM \ libGLESv2 \ libbinder \ libcutils \ libgui \ libsync \ libui \ libutils \ # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) # Include subdirectory makefiles # ============================================================ # If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework # team really wants is to build the stuff defined by this makefile. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif libs/gui/tests/BufferQueue_test.cpp0100644 0000000 0000000 00000111036 13077405420 016451 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "BufferQueue_test" //#define LOG_NDEBUG 0 #include "DummyConsumer.h" #include #include #include #include #include #include #include #include #include #include namespace android { class BufferQueueTest : public ::testing::Test { public: protected: BufferQueueTest() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); } ~BufferQueueTest() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); } void GetMinUndequeuedBufferCount(int* bufferCount) { ASSERT_TRUE(bufferCount != NULL); ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, bufferCount)); ASSERT_GE(*bufferCount, 0); } void createBufferQueue() { BufferQueue::createBufferQueue(&mProducer, &mConsumer); } void testBufferItem(const IGraphicBufferProducer::QueueBufferInput& input, const BufferItem& item) { int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; sp fence; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &fence, NULL); ASSERT_EQ(timestamp, item.mTimestamp); ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp); ASSERT_EQ(dataSpace, item.mDataSpace); ASSERT_EQ(crop, item.mCrop); ASSERT_EQ(static_cast(scalingMode), item.mScalingMode); ASSERT_EQ(transform, item.mTransform); ASSERT_EQ(fence, item.mFence); } sp mProducer; sp mConsumer; }; static const uint32_t TEST_DATA = 0x12345678u; // XXX: Tests that fork a process to hold the BufferQueue must run before tests // that use a local BufferQueue, or else Binder will get unhappy TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { const String16 PRODUCER_NAME = String16("BQTestProducer"); const String16 CONSUMER_NAME = String16("BQTestConsumer"); pid_t forkPid = fork(); ASSERT_NE(forkPid, -1); if (forkPid == 0) { // Child process sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp serviceManager = defaultServiceManager(); serviceManager->addService(PRODUCER_NAME, IInterface::asBinder(producer)); serviceManager->addService(CONSUMER_NAME, IInterface::asBinder(consumer)); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOG_ALWAYS_FATAL("Shouldn't be here"); } sp serviceManager = defaultServiceManager(); sp binderProducer = serviceManager->getService(PRODUCER_NAME); mProducer = interface_cast(binderProducer); EXPECT_TRUE(mProducer != NULL); sp binderConsumer = serviceManager->getService(CONSUMER_NAME); mConsumer = interface_cast(binderConsumer); EXPECT_TRUE(mConsumer != NULL); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); IGraphicBufferProducer::QueueBufferOutput qbo; mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(3); int slot; sp fence; sp buf; IGraphicBufferProducer::QueueBufferInput qbi(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); // Acquire the third buffer, which should fail. ASSERT_EQ(INVALID_OPERATION, mConsumer->acquireBuffer(&item, 0)); } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(10)); IGraphicBufferProducer::QueueBufferOutput qbo; mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(3); int minBufferCount; ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount( minBufferCount - 1)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(0)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(-3)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount( BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100)); int slot; sp fence; sp buf; IGraphicBufferProducer::QueueBufferInput qbi(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferItem item; EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3)); for (int i = 0; i < 3; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); } EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(2)); } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); IGraphicBufferProducer::QueueBufferOutput qbo; mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo); mProducer->setMaxDequeuedBufferCount(2); int minBufferCount; ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount)); EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(2)); EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(minBufferCount)); int slot; sp fence; sp buf; IGraphicBufferProducer::QueueBufferInput qbi(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferItem item; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3)); for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); } EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount( BufferQueue::MAX_MAX_ACQUIRED_BUFFERS)); } TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) { createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); // Test shared buffer mode EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); } TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) { createBufferQueue(); sp dc(new DummyConsumer); mConsumer->consumerConnect(dc, false); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount( BufferQueue::NUM_BUFFER_SLOTS + 1)); EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(5)); EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(3)); } TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer( BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(0)); // Not dequeued int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not dequeued sp safeToClobberBuffer; // Can no longer request buffer from this slot ASSERT_EQ(BAD_VALUE, mProducer->requestBuffer(slot, &safeToClobberBuffer)); uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); int newSlot; ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(NULL, safeToClobberBuffer)); ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL)); ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output)); BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast(0))); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(-1)); // Index too low ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer( BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(0)); // Not acquired BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot)); ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mSlot)); // Not acquired uint32_t* dataIn; ASSERT_EQ(OK, item.mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); int newSlot; sp safeToClobberBuffer; ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(NULL, safeToClobberBuffer)); ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, NULL)); ASSERT_EQ(OK, mConsumer->attachBuffer(&newSlot, item.mGraphicBuffer)); ASSERT_EQ(OK, mConsumer->releaseBuffer(newSlot, 0, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataOut; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, buffer->unlock()); } TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot)); int newSlot; ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, item.mGraphicBuffer)); ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast(0))); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } TEST_F(BufferQueueTest, TestDisallowingAllocation) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); static const uint32_t WIDTH = 320; static const uint32_t HEIGHT = 240; ASSERT_EQ(OK, mConsumer->setDefaultBufferSize(WIDTH, HEIGHT)); int slot; sp fence; sp buffer; // This should return an error since it would require an allocation ASSERT_EQ(OK, mProducer->allowAllocation(false)); ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); // This should succeed, now that we've lifted the prohibition ASSERT_EQ(OK, mProducer->allowAllocation(true)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); // Release the previous buffer back to the BufferQueue mProducer->cancelBuffer(slot, fence); // This should fail since we're requesting a different size ASSERT_EQ(OK, mProducer->allowAllocation(false)); ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } TEST_F(BufferQueueTest, TestGenerationNumbers) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setGenerationNumber(1)); // Get one buffer to play with int slot; sp fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); sp buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); // Ensure that the generation number we set propagates to allocated buffers ASSERT_EQ(1U, buffer->getGenerationNumber()); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); ASSERT_EQ(OK, mProducer->setGenerationNumber(2)); // These should fail, since we've changed the generation number on the queue int outSlot; ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer)); ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer)); buffer->setGenerationNumber(2); // This should succeed now that we've changed the buffer's generation number ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(outSlot)); // This should also succeed with the new generation number ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer)); } TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setSharedBufferMode(true)); // Get a buffer int sharedSlot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); // Repeatedly queue and dequeue a buffer from the producer side, it should // always return the same one. And we won't run out of buffers because it's // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } // acquire the buffer BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(sharedSlot, item.mSlot); testBufferItem(input, item); ASSERT_EQ(true, item.mQueuedBuffer); ASSERT_EQ(false, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // attempt to acquire a second time should return no buffer available ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, mConsumer->acquireBuffer(&item, 0)); } TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); ASSERT_EQ(OK, mProducer->setSharedBufferMode(true)); ASSERT_EQ(OK, mProducer->setAutoRefresh(true)); // Get a buffer int sharedSlot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); // Repeatedly acquire and release a buffer from the consumer side, it should // always return the same one. BufferItem item; for (int i = 0; i < 5; i++) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(sharedSlot, item.mSlot); testBufferItem(input, item); ASSERT_EQ(i == 0, item.mQueuedBuffer); ASSERT_EQ(true, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); } // Repeatedly queue and dequeue a buffer from the producer side, it should // always return the same one. int slot; for (int i = 0; i < 5; i++) { ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } // Repeatedly acquire and release a buffer from the consumer side, it should // always return the same one. First grabbing them from the queue and then // when the queue is empty, returning the shared buffer. for (int i = 0; i < 10; i++) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(sharedSlot, item.mSlot); ASSERT_EQ(0, item.mTimestamp); ASSERT_EQ(false, item.mIsAutoTimestamp); ASSERT_EQ(HAL_DATASPACE_UNKNOWN, item.mDataSpace); ASSERT_EQ(Rect(0, 0, 1, 1), item.mCrop); ASSERT_EQ(NATIVE_WINDOW_SCALING_MODE_FREEZE, item.mScalingMode); ASSERT_EQ(0u, item.mTransform); ASSERT_EQ(Fence::NO_FENCE, item.mFence); ASSERT_EQ(i == 0, item.mQueuedBuffer); ASSERT_EQ(true, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); } } TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); // Dequeue a buffer int sharedSlot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Enable shared buffer mode ASSERT_EQ(OK, mProducer->setSharedBufferMode(true)); // Queue the buffer IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); // Repeatedly queue and dequeue a buffer from the producer side, it should // always return the same one. And we won't run out of buffers because it's // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } // acquire the buffer BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(sharedSlot, item.mSlot); testBufferItem(input, item); ASSERT_EQ(true, item.mQueuedBuffer); ASSERT_EQ(false, item.mAutoRefresh); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // attempt to acquire a second time should return no buffer available ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, mConsumer->acquireBuffer(&item, 0)); } TEST_F(BufferQueueTest, TestTimeouts) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); // Fill up the queue. Since the controlledByApp flags are set to true, this // queue should be in non-blocking mode, and we should be recycling the same // two buffers for (int i = 0; i < 5; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp fence = Fence::NO_FENCE; auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0); if (i < 2) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); } else { ASSERT_EQ(OK, result); } sp buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output{}; ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); } const auto TIMEOUT = ms2ns(250); mProducer->setDequeueTimeout(TIMEOUT); // Setting a timeout will change the BufferQueue into blocking mode (with // one droppable buffer in the queue and one free from the previous // dequeue/queues), so dequeue and queue two more buffers: one to replace // the current droppable buffer, and a second to max out the buffer count sp buffer; // Save a buffer to attach later for (int i = 0; i < 2; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp fence = Fence::NO_FENCE; ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); } int slot = BufferQueue::INVALID_BUFFER_SLOT; sp fence = Fence::NO_FENCE; auto startTime = systemTime(); ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_GE(systemTime() - startTime, TIMEOUT); // We're technically attaching the same buffer multiple times (since we // queued it previously), but that doesn't matter for this test startTime = systemTime(); ASSERT_EQ(TIMED_OUT, mProducer->attachBuffer(&slot, buffer)); ASSERT_GE(systemTime() - startTime, TIMEOUT); } TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, true, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; sp sourceFence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0)); sp buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); ASSERT_EQ(OK, mProducer->allowAllocation(false)); slot = BufferQueue::INVALID_BUFFER_SLOT; ASSERT_EQ(OK, mProducer->attachBuffer(&slot, buffer)); } TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); // Dequeue and queue the first buffer, storing the handle int slot = BufferQueue::INVALID_BUFFER_SLOT; sp fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); sp firstBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer)); IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Dequeue a second buffer slot = BufferQueue::INVALID_BUFFER_SLOT; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); sp secondBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer)); // Ensure it's a new buffer ASSERT_NE(firstBuffer->getNativeBuffer()->handle, secondBuffer->getNativeBuffer()->handle); // Queue the second buffer ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Acquire and release both buffers for (size_t i = 0; i < 2; ++i) { BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); } // Make sure we got the second buffer back sp returnedBuffer; sp returnedFence; float transform[16]; ASSERT_EQ(OK, mProducer->getLastQueuedBuffer(&returnedBuffer, &returnedFence, transform)); ASSERT_EQ(secondBuffer->getNativeBuffer()->handle, returnedBuffer->getNativeBuffer()->handle); } TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; sp fence = Fence::NO_FENCE; sp buffer = nullptr; IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferItem item{}; // Preallocate, dequeue, request, and cancel 4 buffers so we don't get // BUFFER_NEEDS_REALLOCATION below int slots[4] = {}; mProducer->setMaxDequeuedBufferCount(4); for (size_t i = 0; i < 4; ++i) { status_t result = mProducer->dequeueBuffer(&slots[i], &fence, 0, 0, 0, 0); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } for (size_t i = 0; i < 4; ++i) { ASSERT_EQ(OK, mProducer->cancelBuffer(slots[i], Fence::NO_FENCE)); } // Get buffers in all states: dequeued, filled, acquired, free // Fill 3 buffers ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Dequeue 1 buffer ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); // Acquire and free 1 buffer ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // Acquire 1 buffer, leaving 1 filled buffer in queue ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); // Now discard the free buffers ASSERT_EQ(OK, mConsumer->discardFreeBuffers()); // Check no free buffers in dump String8 dumpString; mConsumer->dump(dumpString, nullptr); // Parse the dump to ensure that all buffer slots that are FREE also // have a null GraphicBuffer // Fragile - assumes the following format for the dump for a buffer entry: // ":%p\][^:]*state=FREE" where %p is the buffer pointer in hex. ssize_t idx = dumpString.find("state=FREE"); while (idx != -1) { ssize_t bufferPtrIdx = idx - 1; while (bufferPtrIdx > 0) { if (dumpString[bufferPtrIdx] == ':') { bufferPtrIdx++; break; } bufferPtrIdx--; } ASSERT_GT(bufferPtrIdx, 0) << "Can't parse queue dump to validate"; ssize_t nullPtrIdx = dumpString.find("0x0]", bufferPtrIdx); ASSERT_EQ(bufferPtrIdx, nullPtrIdx) << "Free buffer not discarded"; idx = dumpString.find("FREE", idx + 1); } } } // namespace android libs/gui/tests/CpuConsumer_test.cpp0100644 0000000 0000000 00000061132 13077405420 016477 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "CpuConsumer_test" //#define LOG_NDEBUG 0 //#define LOG_NNDEBUG 0 #ifdef LOG_NNDEBUG #define ALOGVV(...) ALOGV(__VA_ARGS__) #else #define ALOGVV(...) ((void)0) #endif #include #include #include #include #include #include #include #include #define CPU_CONSUMER_TEST_FORMAT_RAW 0 #define CPU_CONSUMER_TEST_FORMAT_Y8 0 #define CPU_CONSUMER_TEST_FORMAT_Y16 0 #define CPU_CONSUMER_TEST_FORMAT_RGBA_8888 1 namespace android { struct CpuConsumerTestParams { uint32_t width; uint32_t height; int maxLockedBuffers; PixelFormat format; }; ::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) { return os << "[ (" << p.width << ", " << p.height << "), B:" << p.maxLockedBuffers << ", F:0x" << ::std::hex << p.format << "]"; } class CpuConsumerTest : public ::testing::TestWithParam { protected: virtual void SetUp() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); CpuConsumerTestParams params = GetParam(); ALOGV("** Starting test %s (%d x %d, %d, 0x%x)", test_info->name(), params.width, params.height, params.maxLockedBuffers, params.format); sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); mCC = new CpuConsumer(consumer, params.maxLockedBuffers); String8 name("CpuConsumer_Under_Test"); mCC->setName(name); mSTC = new Surface(producer); mANW = mSTC; } virtual void TearDown() { mANW.clear(); mSTC.clear(); mCC.clear(); } class FrameWaiter : public CpuConsumer::FrameAvailableListener { public: FrameWaiter(): mPendingFrames(0) { } void waitForFrame() { Mutex::Autolock lock(mMutex); while (mPendingFrames == 0) { mCondition.wait(mMutex); } mPendingFrames--; } virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); } int mPendingFrames; Mutex mMutex; Condition mCondition; }; // Note that SurfaceTexture will lose the notifications // onBuffersReleased and onFrameAvailable as there is currently // no way to forward the events. This DisconnectWaiter will not let the // disconnect finish until finishDisconnect() is called. It will // also block until a disconnect is called class DisconnectWaiter : public BufferQueue::ConsumerListener { public: DisconnectWaiter () : mWaitForDisconnect(false), mPendingFrames(0) { } void waitForFrame() { Mutex::Autolock lock(mMutex); while (mPendingFrames == 0) { mFrameCondition.wait(mMutex); } mPendingFrames--; } virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mFrameCondition.signal(); } virtual void onBuffersReleased() { Mutex::Autolock lock(mMutex); while (!mWaitForDisconnect) { mDisconnectCondition.wait(mMutex); } } void finishDisconnect() { Mutex::Autolock lock(mMutex); mWaitForDisconnect = true; mDisconnectCondition.signal(); } private: Mutex mMutex; bool mWaitForDisconnect; Condition mDisconnectCondition; int mPendingFrames; Condition mFrameCondition; }; sp mCC; sp mSTC; sp mANW; }; #define ASSERT_NO_ERROR(err, msg) \ ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err) void checkPixel(const CpuConsumer::LockedBuffer &buf, uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) { // Ignores components that don't exist for given pixel switch(buf.format) { case HAL_PIXEL_FORMAT_RAW16: { String8 msg; uint16_t *bPtr = (uint16_t*)buf.data; bPtr += y * buf.stride + x; // GRBG Bayer mosaic; only check the matching channel switch( ((y & 1) << 1) | (x & 1) ) { case 0: // G case 3: // G EXPECT_EQ(g, *bPtr); break; case 1: // R EXPECT_EQ(r, *bPtr); break; case 2: // B EXPECT_EQ(b, *bPtr); break; } break; } // ignores g,b case HAL_PIXEL_FORMAT_Y8: { uint8_t *bPtr = (uint8_t*)buf.data; bPtr += y * buf.stride + x; EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y; break; } // ignores g,b case HAL_PIXEL_FORMAT_Y16: { // stride is in pixels, not in bytes uint16_t *bPtr = ((uint16_t*)buf.data) + y * buf.stride + x; EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y; break; } case HAL_PIXEL_FORMAT_RGBA_8888: { const int bytesPerPixel = 4; uint8_t *bPtr = (uint8_t*)buf.data; bPtr += (y * buf.stride + x) * bytesPerPixel; EXPECT_EQ(r, bPtr[0]) << "at x = " << x << " y = " << y; EXPECT_EQ(g, bPtr[1]) << "at x = " << x << " y = " << y; EXPECT_EQ(b, bPtr[2]) << "at x = " << x << " y = " << y; break; } default: { ADD_FAILURE() << "Unknown format for check:" << buf.format; break; } } } // Fill a YV12 buffer with a multi-colored checkerboard pattern void fillYV12Buffer(uint8_t* buf, int w, int h, int stride); // Fill a Y8/Y16 buffer with a multi-colored checkerboard pattern template // T == uint8_t or uint16_t void fillGreyscaleBuffer(T* buf, int w, int h, int stride, int bpp) { const int blockWidth = w > 16 ? w / 16 : 1; const int blockHeight = h > 16 ? h / 16 : 1; const int yuvTexOffsetY = 0; ASSERT_TRUE(bpp == 8 || bpp == 16); ASSERT_TRUE(sizeof(T)*8 == bpp); // stride is in pixels, not in bytes int yuvTexStrideY = stride; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { int parityX = (x / blockWidth) & 1; int parityY = (y / blockHeight) & 1; T intensity = (parityX ^ parityY) ? 63 : 191; buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; } } } inline uint8_t chooseColorRgba8888(int blockX, int blockY, uint8_t channel) { const int colorVariations = 3; uint8_t color = ((blockX % colorVariations) + (blockY % colorVariations)) % (colorVariations) == channel ? 191: 63; return color; } // Fill a RGBA8888 buffer with a multi-colored checkerboard pattern void fillRgba8888Buffer(uint8_t* buf, int w, int h, int stride) { const int blockWidth = w > 16 ? w / 16 : 1; const int blockHeight = h > 16 ? h / 16 : 1; const int bytesPerPixel = 4; // stride is in pixels, not in bytes for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { int blockX = (x / blockWidth); int blockY = (y / blockHeight); uint8_t r = chooseColorRgba8888(blockX, blockY, 0); uint8_t g = chooseColorRgba8888(blockX, blockY, 1); uint8_t b = chooseColorRgba8888(blockX, blockY, 2); buf[(y*stride + x)*bytesPerPixel + 0] = r; buf[(y*stride + x)*bytesPerPixel + 1] = g; buf[(y*stride + x)*bytesPerPixel + 2] = b; buf[(y*stride + x)*bytesPerPixel + 3] = 255; } } } // Fill a RAW sensor buffer with a multi-colored checkerboard pattern. // Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern // of [ R, B; G, W] void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride); // Blocks need to be even-width/height, aim for 8-wide otherwise const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; for (int y = 0; y < h; y+=2) { uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y; uint16_t *bPtr2 = bPtr1 + stride; for (int x = 0; x < w; x+=2) { int blockX = (x / blockWidth ) & 1; int blockY = (y / blockHeight) & 1; unsigned short r = (blockX == blockY) ? 1000 : 200; unsigned short g = blockY ? 1000: 200; unsigned short b = blockX ? 1000: 200; // GR row *bPtr1++ = g; *bPtr1++ = r; // BG row *bPtr2++ = b; *bPtr2++ = g; } } } template // uint8_t or uint16_t void checkGreyscaleBuffer(const CpuConsumer::LockedBuffer &buf) { uint32_t w = buf.width; uint32_t h = buf.height; const int blockWidth = w > 16 ? w / 16 : 1; const int blockHeight = h > 16 ? h / 16 : 1; const int blockRows = h / blockHeight; const int blockCols = w / blockWidth; // Top-left square is bright checkPixel(buf, 0, 0, 191); checkPixel(buf, 1, 0, 191); checkPixel(buf, 0, 1, 191); checkPixel(buf, 1, 1, 191); // One-right square is dark checkPixel(buf, blockWidth, 0, 63); checkPixel(buf, blockWidth + 1, 0, 63); checkPixel(buf, blockWidth, 1, 63); checkPixel(buf, blockWidth + 1, 1, 63); // One-down square is dark checkPixel(buf, 0, blockHeight, 63); checkPixel(buf, 1, blockHeight, 63); checkPixel(buf, 0, blockHeight + 1, 63); checkPixel(buf, 1, blockHeight + 1, 63); // One-diag square is bright checkPixel(buf, blockWidth, blockHeight, 191); checkPixel(buf, blockWidth + 1, blockHeight, 191); checkPixel(buf, blockWidth, blockHeight + 1, 191); checkPixel(buf, blockWidth + 1, blockHeight + 1, 191); // Test bottom-right pixel const int maxBlockX = ((w-1 + (blockWidth-1)) / blockWidth) & 0x1; const int maxBlockY = ((h-1 + (blockHeight-1)) / blockHeight) & 0x1; uint32_t pixelValue = ((maxBlockX % 2) == (maxBlockY % 2)) ? 191 : 63; checkPixel(buf, w-1, h-1, pixelValue); } void checkRgba8888Buffer(const CpuConsumer::LockedBuffer &buf) { uint32_t w = buf.width; uint32_t h = buf.height; const int blockWidth = w > 16 ? w / 16 : 1; const int blockHeight = h > 16 ? h / 16 : 1; const int blockRows = h / blockHeight; const int blockCols = w / blockWidth; // Top-left square is bright red checkPixel(buf, 0, 0, 191, 63, 63); checkPixel(buf, 1, 0, 191, 63, 63); checkPixel(buf, 0, 1, 191, 63, 63); checkPixel(buf, 1, 1, 191, 63, 63); // One-right square is bright green checkPixel(buf, blockWidth, 0, 63, 191, 63); checkPixel(buf, blockWidth + 1, 0, 63, 191, 63); checkPixel(buf, blockWidth, 1, 63, 191, 63); checkPixel(buf, blockWidth + 1, 1, 63, 191, 63); // One-down square is bright green checkPixel(buf, 0, blockHeight, 63, 191, 63); checkPixel(buf, 1, blockHeight, 63, 191, 63); checkPixel(buf, 0, blockHeight + 1, 63, 191, 63); checkPixel(buf, 1, blockHeight + 1, 63, 191, 63); // One-diag square is bright blue checkPixel(buf, blockWidth, blockHeight, 63, 63, 191); checkPixel(buf, blockWidth + 1, blockHeight, 63, 63, 191); checkPixel(buf, blockWidth, blockHeight + 1, 63, 63, 191); checkPixel(buf, blockWidth + 1, blockHeight + 1, 63, 63, 191); // Test bottom-right pixel { const int maxBlockX = ((w-1) / blockWidth); const int maxBlockY = ((h-1) / blockHeight); uint8_t r = chooseColorRgba8888(maxBlockX, maxBlockY, 0); uint8_t g = chooseColorRgba8888(maxBlockX, maxBlockY, 1); uint8_t b = chooseColorRgba8888(maxBlockX, maxBlockY, 2); checkPixel(buf, w-1, h-1, r, g, b); } } void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { uint32_t w = buf.width; uint32_t h = buf.height; const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; const int blockRows = h / blockHeight; const int blockCols = w / blockWidth; // Top-left square is red checkPixel(buf, 0, 0, 1000, 200, 200); checkPixel(buf, 1, 0, 1000, 200, 200); checkPixel(buf, 0, 1, 1000, 200, 200); checkPixel(buf, 1, 1, 1000, 200, 200); // One-right square is blue checkPixel(buf, blockWidth, 0, 200, 200, 1000); checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000); checkPixel(buf, blockWidth, 1, 200, 200, 1000); checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000); // One-down square is green checkPixel(buf, 0, blockHeight, 200, 1000, 200); checkPixel(buf, 1, blockHeight, 200, 1000, 200); checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200); checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200); // One-diag square is white checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000); checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000); checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000); checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000); // Test bottom-right pixel const int maxBlockX = ((w-1) / blockWidth) & 0x1; const int maxBlockY = ((w-1) / blockHeight) & 0x1; unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200; unsigned short maxG = maxBlockY ? 1000: 200; unsigned short maxB = maxBlockX ? 1000: 200; checkPixel(buf, w-1, h-1, maxR, maxG, maxB); } void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) { switch (format) { case HAL_PIXEL_FORMAT_RAW16: checkBayerRawBuffer(buf); break; case HAL_PIXEL_FORMAT_Y8: checkGreyscaleBuffer(buf); break; case HAL_PIXEL_FORMAT_Y16: checkGreyscaleBuffer(buf); break; case HAL_PIXEL_FORMAT_RGBA_8888: checkRgba8888Buffer(buf); break; } } // Configures the ANativeWindow producer-side interface based on test parameters void configureANW(const sp& anw, const CpuConsumerTestParams& params, int maxBufferSlack) { status_t err; err = native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU); ASSERT_NO_ERROR(err, "connect error: "); err = native_window_set_buffers_dimensions(anw.get(), params.width, params.height); ASSERT_NO_ERROR(err, "set_buffers_dimensions error: "); err = native_window_set_buffers_format(anw.get(), params.format); ASSERT_NO_ERROR(err, "set_buffers_format error: "); err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); ASSERT_NO_ERROR(err, "set_usage error: "); int minUndequeuedBuffers; err = anw.get()->query(anw.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers); ASSERT_NO_ERROR(err, "query error: "); ALOGVV("Setting buffer count to %d", maxBufferSlack + 1 + minUndequeuedBuffers); err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); ASSERT_NO_ERROR(err, "set_buffer_count error: "); } // Produce one frame of image data; assumes format and resolution configuration // is already done. void produceOneFrame(const sp& anw, const CpuConsumerTestParams& params, int64_t timestamp, uint32_t *stride) { status_t err; ANativeWindowBuffer* anb; ALOGVV("Dequeue buffer from %p", anw.get()); err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); ASSERT_NO_ERROR(err, "dequeueBuffer error: "); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); *stride = buf->getStride(); uint8_t* img = NULL; ALOGVV("Lock buffer from %p for write", anw.get()); err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); ASSERT_NO_ERROR(err, "lock error: "); switch (params.format) { case HAL_PIXEL_FORMAT_YV12: fillYV12Buffer(img, params.width, params.height, *stride); break; case HAL_PIXEL_FORMAT_RAW16: fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); break; case HAL_PIXEL_FORMAT_Y8: fillGreyscaleBuffer(img, params.width, params.height, buf->getStride(), /*bpp*/8); break; case HAL_PIXEL_FORMAT_Y16: fillGreyscaleBuffer((uint16_t*)img, params.width, params.height, buf->getStride(), /*bpp*/16); break; case HAL_PIXEL_FORMAT_RGBA_8888: fillRgba8888Buffer(img, params.width, params.height, buf->getStride()); break; default: FAIL() << "Unknown pixel format under test!"; break; } ALOGVV("Unlock buffer from %p", anw.get()); err = buf->unlock(); ASSERT_NO_ERROR(err, "unlock error: "); ALOGVV("Set timestamp to %p", anw.get()); err = native_window_set_buffers_timestamp(anw.get(), timestamp); ASSERT_NO_ERROR(err, "set_buffers_timestamp error: "); ALOGVV("Queue buffer to %p", anw.get()); err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1); ASSERT_NO_ERROR(err, "queueBuffer error:"); }; // This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuSingle) { status_t err; CpuConsumerTestParams params = GetParam(); // Set up ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1)); // Produce const int64_t time = 12345678L; uint32_t stride; ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); // Consume CpuConsumer::LockedBuffer b; err = mCC->lockNextBuffer(&b); ASSERT_NO_ERROR(err, "getNextBuffer error: "); ASSERT_TRUE(b.data != NULL); EXPECT_EQ(params.width, b.width); EXPECT_EQ(params.height, b.height); EXPECT_EQ(params.format, b.format); EXPECT_EQ(stride, b.stride); EXPECT_EQ(time, b.timestamp); checkAnyBuffer(b, GetParam().format); mCC->unlockBuffer(b); } // This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuManyInQueue) { status_t err; CpuConsumerTestParams params = GetParam(); const int numInQueue = 5; // Set up ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue)); // Produce const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L}; uint32_t stride[numInQueue]; for (int i = 0; i < numInQueue; i++) { ALOGV("Producing frame %d", i); ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i], &stride[i])); } // Consume for (int i = 0; i < numInQueue; i++) { ALOGV("Consuming frame %d", i); CpuConsumer::LockedBuffer b; err = mCC->lockNextBuffer(&b); ASSERT_NO_ERROR(err, "getNextBuffer error: "); ASSERT_TRUE(b.data != NULL); EXPECT_EQ(params.width, b.width); EXPECT_EQ(params.height, b.height); EXPECT_EQ(params.format, b.format); EXPECT_EQ(stride[i], b.stride); EXPECT_EQ(time[i], b.timestamp); checkAnyBuffer(b, GetParam().format); mCC->unlockBuffer(b); } } // This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuLockMax) { status_t err; CpuConsumerTestParams params = GetParam(); // Set up ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); // Produce const int64_t time = 1234L; uint32_t stride; for (int i = 0; i < params.maxLockedBuffers + 1; i++) { ALOGV("Producing frame %d", i); ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); } // Consume CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers]; for (int i = 0; i < params.maxLockedBuffers; i++) { ALOGV("Locking frame %d", i); err = mCC->lockNextBuffer(&b[i]); ASSERT_NO_ERROR(err, "getNextBuffer error: "); ASSERT_TRUE(b[i].data != NULL); EXPECT_EQ(params.width, b[i].width); EXPECT_EQ(params.height, b[i].height); EXPECT_EQ(params.format, b[i].format); EXPECT_EQ(stride, b[i].stride); EXPECT_EQ(time, b[i].timestamp); checkAnyBuffer(b[i], GetParam().format); } ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); CpuConsumer::LockedBuffer bTooMuch; err = mCC->lockNextBuffer(&bTooMuch); ASSERT_TRUE(err == NOT_ENOUGH_DATA) << "Allowing too many locks"; ALOGV("Unlocking frame 0"); err = mCC->unlockBuffer(b[0]); ASSERT_NO_ERROR(err, "Could not unlock buffer 0: "); ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers); err = mCC->lockNextBuffer(&bTooMuch); ASSERT_NO_ERROR(err, "Did not allow new lock after unlock"); ASSERT_TRUE(bTooMuch.data != NULL); EXPECT_EQ(params.width, bTooMuch.width); EXPECT_EQ(params.height, bTooMuch.height); EXPECT_EQ(params.format, bTooMuch.format); EXPECT_EQ(stride, bTooMuch.stride); EXPECT_EQ(time, bTooMuch.timestamp); checkAnyBuffer(bTooMuch, GetParam().format); ALOGV("Unlocking extra buffer"); err = mCC->unlockBuffer(bTooMuch); ASSERT_NO_ERROR(err, "Could not unlock extra buffer: "); ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1); err = mCC->lockNextBuffer(&b[0]); ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow"; for (int i = 1; i < params.maxLockedBuffers; i++) { mCC->unlockBuffer(b[i]); } delete[] b; } CpuConsumerTestParams y8TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y8}, { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y8}, { 100, 100, 1, HAL_PIXEL_FORMAT_Y8}, { 100, 100, 3, HAL_PIXEL_FORMAT_Y8}, }; CpuConsumerTestParams y16TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y16}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y16}, { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y16}, { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y16}, { 100, 100, 1, HAL_PIXEL_FORMAT_Y16}, { 100, 100, 3, HAL_PIXEL_FORMAT_Y16}, }; CpuConsumerTestParams rawTestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_RAW16}, { 512, 512, 3, HAL_PIXEL_FORMAT_RAW16}, { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW16}, { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW16}, { 100, 100, 1, HAL_PIXEL_FORMAT_RAW16}, { 100, 100, 3, HAL_PIXEL_FORMAT_RAW16}, }; CpuConsumerTestParams rgba8888TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_RGBA_8888}, { 512, 512, 3, HAL_PIXEL_FORMAT_RGBA_8888}, { 2608, 1960, 1, HAL_PIXEL_FORMAT_RGBA_8888}, { 2608, 1960, 3, HAL_PIXEL_FORMAT_RGBA_8888}, { 100, 100, 1, HAL_PIXEL_FORMAT_RGBA_8888}, { 100, 100, 3, HAL_PIXEL_FORMAT_RGBA_8888}, }; #if CPU_CONSUMER_TEST_FORMAT_Y8 INSTANTIATE_TEST_CASE_P(Y8Tests, CpuConsumerTest, ::testing::ValuesIn(y8TestSets)); #endif #if CPU_CONSUMER_TEST_FORMAT_Y16 INSTANTIATE_TEST_CASE_P(Y16Tests, CpuConsumerTest, ::testing::ValuesIn(y16TestSets)); #endif #if CPU_CONSUMER_TEST_FORMAT_RAW INSTANTIATE_TEST_CASE_P(RawTests, CpuConsumerTest, ::testing::ValuesIn(rawTestSets)); #endif #if CPU_CONSUMER_TEST_FORMAT_RGBA_8888 INSTANTIATE_TEST_CASE_P(Rgba8888Tests, CpuConsumerTest, ::testing::ValuesIn(rgba8888TestSets)); #endif } // namespace android libs/gui/tests/DisconnectWaiter.h0100644 0000000 0000000 00000004176 13077405420 016114 0ustar000000000 0000000 /* * Copyright 2013 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_DISCONNECT_WAITER_H #define ANDROID_DISCONNECT_WAITER_H #include #include #include namespace android { // Note that GLConsumer will lose the notifications // onBuffersReleased and onFrameAvailable as there is currently // no way to forward the events. This DisconnectWaiter will not let the // disconnect finish until finishDisconnect() is called. It will // also block until a disconnect is called class DisconnectWaiter : public BnConsumerListener { public: DisconnectWaiter () : mWaitForDisconnect(false), mPendingFrames(0) { } void waitForFrame() { Mutex::Autolock lock(mMutex); while (mPendingFrames == 0) { mFrameCondition.wait(mMutex); } mPendingFrames--; } virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); mPendingFrames++; mFrameCondition.signal(); } virtual void onBuffersReleased() { Mutex::Autolock lock(mMutex); while (!mWaitForDisconnect) { mDisconnectCondition.wait(mMutex); } } virtual void onSidebandStreamChanged() {} void finishDisconnect() { Mutex::Autolock lock(mMutex); mWaitForDisconnect = true; mDisconnectCondition.signal(); } private: Mutex mMutex; bool mWaitForDisconnect; Condition mDisconnectCondition; int mPendingFrames; Condition mFrameCondition; }; } // namespace android #endif libs/gui/tests/DummyConsumer.h0100644 0000000 0000000 00000001611 13077405420 015445 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace android { struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; } // namespace android libs/gui/tests/FillBuffer.cpp0100644 0000000 0000000 00000010056 13077405420 015214 0ustar000000000 0000000 /* * Copyright 2013 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 "FillBuffer.h" #include #include namespace android { void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) { const int blockWidth = w > 16 ? w / 16 : 1; const int blockHeight = h > 16 ? h / 16 : 1; const int yuvTexOffsetY = 0; int yuvTexStrideY = stride; int yuvTexOffsetV = yuvTexStrideY * h; int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; int yuvTexStrideU = yuvTexStrideV; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { int parityX = (x / blockWidth) & 1; int parityY = (y / blockHeight) & 1; unsigned char intensity = (parityX ^ parityY) ? 63 : 191; buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; if (x < w / 2 && y < h / 2) { buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; if (x * 2 < w / 2 && y * 2 < h / 2) { buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity; } } } } } void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, const android_native_rect_t& rect) { const int yuvTexOffsetY = 0; int yuvTexStrideY = stride; int yuvTexOffsetV = yuvTexStrideY * h; int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; int yuvTexStrideU = yuvTexStrideV; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { bool inside = rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom; buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64; if (x < w / 2 && y < h / 2) { bool inside = rect.left <= 2*x && 2*x < rect.right && rect.top <= 2*y && 2*y < rect.bottom; buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16; buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = inside ? 16 : 255; } } } } void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { const size_t PIXEL_SIZE = 4; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { off_t offset = (y * stride + x) * PIXEL_SIZE; for (int c = 0; c < 4; c++) { int parityX = (x / (1 << (c+2))) & 1; int parityY = (y / (1 << (c+2))) & 1; buf[offset + c] = (parityX ^ parityY) ? 231 : 35; } } } } void produceOneRGBA8Frame(const sp& anw) { android_native_buffer_t* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), &anb)); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); uint8_t* img = NULL; ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img))); fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride()); ASSERT_EQ(NO_ERROR, buf->unlock()); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1)); } } // namespace android libs/gui/tests/FillBuffer.h0100644 0000000 0000000 00000002765 13077405420 014671 0ustar000000000 0000000 /* * Copyright 2013 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_FILL_BUFFER_H #define ANDROID_FILL_BUFFER_H #include #include namespace android { // Fill a YV12 buffer with a multi-colored checkerboard pattern void fillYV12Buffer(uint8_t* buf, int w, int h, int stride); // Fill a YV12 buffer with red outside a given rectangle and green inside it. void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, const android_native_rect_t& rect); void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride); // Produce a single RGBA8 frame by filling a buffer with a checkerboard pattern // using the CPU. This assumes that the ANativeWindow is already configured to // allow this to be done (e.g. the format is set to RGBA8). // // Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE(). void produceOneRGBA8Frame(const sp& anw); } // namespace android #endif libs/gui/tests/FrameWaiter.h0100644 0000000 0000000 00000002450 13077405420 015046 0ustar000000000 0000000 /* * Copyright 2013 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_FRAME_WAITER_H #define ANDROID_FRAME_WAITER_H #include namespace android { class FrameWaiter : public GLConsumer::FrameAvailableListener { public: FrameWaiter(): mPendingFrames(0) { } void waitForFrame() { Mutex::Autolock lock(mMutex); while (mPendingFrames == 0) { mCondition.wait(mMutex); } mPendingFrames--; } virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); } private: int mPendingFrames; Mutex mMutex; Condition mCondition; }; } // namespace android #endif libs/gui/tests/GLTest.cpp0100644 0000000 0000000 00000026245 13077405420 014345 0ustar000000000 0000000 /* * Copyright 2013 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 "GLTest.h" #include #include namespace android { static int abs(int value) { return value > 0 ? value : -value; } void GLTest::SetUp() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); EGLint majorVersion; EGLint minorVersion; EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); RecordProperty("EglVersionMajor", majorVersion); RecordProperty("EglVersionMinor", minorVersion); EGLint numConfigs = 0; EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS"); if (displaySecsEnv != NULL) { mDisplaySecs = atoi(displaySecsEnv); if (mDisplaySecs < 0) { mDisplaySecs = 0; } } else { mDisplaySecs = 0; } if (mDisplaySecs > 0) { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(), PIXEL_FORMAT_RGB_888, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(); sp window = mSurfaceControl->getSurface(); mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); } else { EGLint pbufferAttribs[] = { EGL_WIDTH, getSurfaceWidth(), EGL_HEIGHT, getSurfaceHeight(), EGL_NONE }; mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig, pbufferAttribs); } ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mEglSurface); mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mEglContext); EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLint w, h; EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); RecordProperty("EglSurfaceWidth", w); RecordProperty("EglSurfaceHeight", h); glViewport(0, 0, w, h); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } void GLTest::TearDown() { // Display the result if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) { eglSwapBuffers(mEglDisplay, mEglSurface); sleep(mDisplaySecs); } if (mComposerClient != NULL) { mComposerClient->dispose(); } if (mEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mEglContext); } if (mEglSurface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, mEglSurface); } if (mEglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(mEglDisplay); } ASSERT_EQ(EGL_SUCCESS, eglGetError()); const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); } EGLint const* GLTest::getConfigAttribs() { static const EGLint sDefaultConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, 8, EGL_NONE }; return sDefaultConfigAttribs; } EGLint const* GLTest::getContextAttribs() { static const EGLint sDefaultContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; return sDefaultContextAttribs; } EGLint GLTest::getSurfaceWidth() { return 512; } EGLint GLTest::getSurfaceHeight() { return 512; } EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, sp& window) const { return eglCreateWindowSurface(display, config, window.get(), NULL); } ::testing::AssertionResult GLTest::checkPixel(int x, int y, int r, int g, int b, int a, int tolerance) { GLubyte pixel[4]; String8 msg; glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); GLenum err = glGetError(); if (err != GL_NO_ERROR) { msg += String8::format("error reading pixel: %#x", err); while ((err = glGetError()) != GL_NO_ERROR) { msg += String8::format(", %#x", err); } return ::testing::AssertionFailure(::testing::Message(msg.string())); } if (r >= 0 && abs(r - int(pixel[0])) > tolerance) { msg += String8::format("r(%d isn't %d)", pixel[0], r); } if (g >= 0 && abs(g - int(pixel[1])) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("g(%d isn't %d)", pixel[1], g); } if (b >= 0 && abs(b - int(pixel[2])) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("b(%d isn't %d)", pixel[2], b); } if (a >= 0 && abs(a - int(pixel[3])) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("a(%d isn't %d)", pixel[3], a); } if (!msg.isEmpty()) { return ::testing::AssertionFailure(::testing::Message(msg.string())); } else { return ::testing::AssertionSuccess(); } } ::testing::AssertionResult GLTest::assertRectEq(const Rect &r1, const Rect &r2, int tolerance) { String8 msg; if (abs(r1.left - r2.left) > tolerance) { msg += String8::format("left(%d isn't %d)", r1.left, r2.left); } if (abs(r1.top - r2.top) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("top(%d isn't %d)", r1.top, r2.top); } if (abs(r1.right - r2.right) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("right(%d isn't %d)", r1.right, r2.right); } if (abs(r1.bottom - r2.bottom) > tolerance) { if (!msg.isEmpty()) { msg += " "; } msg += String8::format("bottom(%d isn't %d)", r1.bottom, r2.bottom); } if (!msg.isEmpty()) { msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]", r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom); fprintf(stderr, "assertRectEq: %s\n", msg.string()); return ::testing::AssertionFailure(::testing::Message(msg.string())); } else { return ::testing::AssertionSuccess(); } } void GLTest::loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) { GLuint shader = glCreateShader(shaderType); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); if (shader) { glShaderSource(shader, 1, &pSource, NULL); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glCompileShader(shader); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); printf("Shader compile log:\n%s\n", buf); free(buf); FAIL(); } } else { char* buf = (char*) malloc(0x1000); if (buf) { glGetShaderInfoLog(shader, 0x1000, NULL, buf); printf("Shader compile log:\n%s\n", buf); free(buf); FAIL(); } } glDeleteShader(shader); shader = 0; } } ASSERT_TRUE(shader != 0); *outShader = shader; } void GLTest::createProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm) { GLuint vertexShader, fragmentShader; { SCOPED_TRACE("compiling vertex shader"); ASSERT_NO_FATAL_FAILURE(loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader)); } { SCOPED_TRACE("compiling fragment shader"); ASSERT_NO_FATAL_FAILURE(loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader)); } GLuint program = glCreateProgram(); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); if (program) { glAttachShader(program, vertexShader); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glAttachShader(program, fragmentShader); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); printf("Program link log:\n%s\n", buf); free(buf); FAIL(); } } glDeleteProgram(program); program = 0; } } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); ASSERT_TRUE(program != 0); *outPgm = program; } } // namespace android libs/gui/tests/GLTest.h0100644 0000000 0000000 00000004137 13077405420 014006 0ustar000000000 0000000 /* * Copyright 2013 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_GL_TEST_H #define ANDROID_GL_TEST_H #include #include #include #include namespace android { class GLTest : public ::testing::Test { public: static void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader); static void createProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm); protected: GLTest() : mDisplaySecs(0), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT), mGlConfig(NULL) { } virtual void SetUp(); virtual void TearDown(); virtual EGLint const* getConfigAttribs(); virtual EGLint const* getContextAttribs(); virtual EGLint getSurfaceWidth(); virtual EGLint getSurfaceHeight(); virtual EGLSurface createWindowSurface(EGLDisplay display, EGLConfig config, sp& window) const; ::testing::AssertionResult checkPixel(int x, int y, int r, int g, int b, int a, int tolerance = 2); ::testing::AssertionResult assertRectEq(const Rect &r1, const Rect &r2, int tolerance = 1); int mDisplaySecs; sp mComposerClient; sp mSurfaceControl; EGLDisplay mEglDisplay; EGLSurface mEglSurface; EGLContext mEglContext; EGLConfig mGlConfig; }; } // namespace android #endif libs/gui/tests/IGraphicBufferProducer_test.cpp0100644 0000000 0000000 00000063454 13077405420 020571 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "IGraphicBufferProducer_test" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #define ASSERT_OK(x) ASSERT_EQ(OK, (x)) #define EXPECT_OK(x) EXPECT_EQ(OK, (x)) #define TEST_TOKEN ((IProducerListener*)(NULL)) #define TEST_API NATIVE_WINDOW_API_CPU #define TEST_API_OTHER NATIVE_WINDOW_API_EGL // valid API that's not TEST_API #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) namespace android { namespace { // Default dimensions before setDefaultBufferSize is called const uint32_t DEFAULT_WIDTH = 1; const uint32_t DEFAULT_HEIGHT = 1; // Default format before setDefaultBufferFormat is called const PixelFormat DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888; // Default transform hint before setTransformHint is called const uint32_t DEFAULT_TRANSFORM_HINT = 0; // TODO: Make these constants in header const int DEFAULT_CONSUMER_USAGE_BITS = 0; // Parameters for a generic "valid" input for queueBuffer. const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611; const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false; const android_dataspace QUEUE_BUFFER_INPUT_DATASPACE = HAL_DATASPACE_UNKNOWN; const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; const sp QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; }; // namespace anonymous struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; class IGraphicBufferProducerTest : public ::testing::Test { protected: IGraphicBufferProducerTest() {} virtual void SetUp() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); mDC = new DummyConsumer; BufferQueue::createBufferQueue(&mProducer, &mConsumer); // Test check: Can't connect producer if no consumer yet ASSERT_EQ(NO_INIT, TryConnectProducer()); // Must connect consumer before producer connects will succeed. ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false)); } virtual void TearDown() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); } status_t TryConnectProducer() { IGraphicBufferProducer::QueueBufferOutput output; return mProducer->connect(TEST_TOKEN, TEST_API, TEST_CONTROLLED_BY_APP, &output); // TODO: use params to vary token, api, producercontrolledbyapp, etc } // Connect to a producer in a 'correct' fashion. // Precondition: Consumer is connected. void ConnectProducer() { ASSERT_OK(TryConnectProducer()); } // Create a generic "valid" input for queueBuffer // -- uses the default buffer format, width, etc. static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() { return QueueBufferInputBuilder().build(); } // Builder pattern to slightly vary *almost* correct input // -- avoids copying and pasting struct QueueBufferInputBuilder { QueueBufferInputBuilder() { timestamp = QUEUE_BUFFER_INPUT_TIMESTAMP; isAutoTimestamp = QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP; dataSpace = QUEUE_BUFFER_INPUT_DATASPACE; crop = QUEUE_BUFFER_INPUT_RECT; scalingMode = QUEUE_BUFFER_INPUT_SCALING_MODE; transform = QUEUE_BUFFER_INPUT_TRANSFORM; fence = QUEUE_BUFFER_INPUT_FENCE; } IGraphicBufferProducer::QueueBufferInput build() { return IGraphicBufferProducer::QueueBufferInput( timestamp, isAutoTimestamp, dataSpace, crop, scalingMode, transform, fence); } QueueBufferInputBuilder& setTimestamp(int64_t timestamp) { this->timestamp = timestamp; return *this; } QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) { this->isAutoTimestamp = isAutoTimestamp; return *this; } QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) { this->dataSpace = dataSpace; return *this; } QueueBufferInputBuilder& setCrop(Rect crop) { this->crop = crop; return *this; } QueueBufferInputBuilder& setScalingMode(int scalingMode) { this->scalingMode = scalingMode; return *this; } QueueBufferInputBuilder& setTransform(uint32_t transform) { this->transform = transform; return *this; } QueueBufferInputBuilder& setFence(sp fence) { this->fence = fence; return *this; } private: int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; sp fence; }; // struct QueueBufferInputBuilder // To easily store dequeueBuffer results into containers struct DequeueBufferResult { int slot; sp fence; }; status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) { return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage); } void setupDequeueRequestBuffer(int *slot, sp *fence, sp *buffer) { ASSERT_TRUE(slot != NULL); ASSERT_TRUE(fence != NULL); ASSERT_TRUE(buffer != NULL); ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); EXPECT_LE(0, *slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot); // Request the buffer (pre-requisite for queueing) ASSERT_OK(mProducer->requestBuffer(*slot, buffer)); } private: // hide from test body sp mDC; protected: // accessible from test body sp mProducer; sp mConsumer; }; TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { IGraphicBufferProducer::QueueBufferOutput output; // NULL output returns BAD_VALUE EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN, TEST_API, TEST_CONTROLLED_BY_APP, /*output*/NULL)); // Invalid API returns bad value EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN, /*api*/0xDEADBEEF, TEST_CONTROLLED_BY_APP, &output)); // TODO: get a token from a dead process somehow } TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Can't connect when there is already a producer connected IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN, TEST_API, TEST_CONTROLLED_BY_APP, &output)); ASSERT_OK(mConsumer->consumerDisconnect()); // Can't connect when IGBP is abandoned EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, TEST_API, TEST_CONTROLLED_BY_APP, &output)); } TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->disconnect(TEST_API)); } TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Must disconnect with same API number ASSERT_EQ(BAD_VALUE, mProducer->disconnect(TEST_API_OTHER)); // API must not be out of range ASSERT_EQ(BAD_VALUE, mProducer->disconnect(/*api*/0xDEADBEEF)); // TODO: somehow kill mProducer so that this returns DEAD_OBJECT } TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int32_t value = -1; EXPECT_OK(mProducer->query(NATIVE_WINDOW_WIDTH, &value)); EXPECT_EQ(DEFAULT_WIDTH, static_cast(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_HEIGHT, &value)); EXPECT_EQ(DEFAULT_HEIGHT, static_cast(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_FORMAT, &value)); EXPECT_EQ(DEFAULT_FORMAT, value); EXPECT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value)); EXPECT_LE(0, value); EXPECT_GE(BufferQueue::NUM_BUFFER_SLOTS, value); EXPECT_OK(mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value)); EXPECT_FALSE(value); // Can't run behind when we haven't touched the queue EXPECT_OK(mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value)); EXPECT_EQ(DEFAULT_CONSUMER_USAGE_BITS, value); } TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // One past the end of the last 'query' enum value. Update this if we add more enums. const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; int value; // What was out of range EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/-1, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/0xDEADBEEF, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value)); // Some enums from window.h are 'invalid' EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value)); EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value)); // TODO: Consider documented the above enums as unsupported or make a new enum for IGBP // Value was NULL EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/NULL)); ASSERT_OK(mConsumer->consumerDisconnect()); // BQ was abandoned EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); // TODO: other things in window.h that are supported by Surface::query // but not by BufferQueue::query } // TODO: queue under more complicated situations not involving just a single buffer TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; sp dequeuedFence; ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); EXPECT_LE(0, dequeuedSlot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot); // Request the buffer (pre-requisite for queueing) sp dequeuedBuffer; ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); // A generic "valid" input IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; // Queue the buffer back into the BQ ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); { uint32_t width; uint32_t height; uint32_t transformHint; uint32_t numPendingBuffers; output.deflate(&width, &height, &transformHint, &numPendingBuffers); EXPECT_EQ(DEFAULT_WIDTH, width); EXPECT_EQ(DEFAULT_HEIGHT, height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint); EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once } // Buffer was not in the dequeued state EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Invalid slot number { // A generic "valid" input IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/-1, input, &output)); EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/0xDEADBEEF, input, &output)); EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueue::NUM_BUFFER_SLOTS, input, &output)); } // Slot was not in the dequeued state (all slots start out in Free state) { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/0, input, &output)); } // Put the slot into the "dequeued" state for the rest of the test int dequeuedSlot = -1; sp dequeuedFence; ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); // Slot was enqueued without requesting a buffer { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } // Request the buffer so that the rest of the tests don't fail on earlier checks. sp dequeuedBuffer; ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); // Fence was NULL { sp nullFence = NULL; IGraphicBufferProducer::QueueBufferInput input = QueueBufferInputBuilder().setFence(nullFence).build(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } // Scaling mode was unknown { IGraphicBufferProducer::QueueBufferInput input = QueueBufferInputBuilder().setScalingMode(-1).build(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build(); EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } // Crop rect is out of bounds of the buffer dimensions { IGraphicBufferProducer::QueueBufferInput input = QueueBufferInputBuilder().setCrop(Rect(DEFAULT_WIDTH + 1, DEFAULT_HEIGHT + 1)) .build(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } // Abandon the buffer queue so that the last test fails ASSERT_OK(mConsumer->consumerDisconnect()); // The buffer queue has been abandoned. { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output)); } } TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; sp dequeuedFence; ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); // No return code, but at least test that it doesn't blow up... // TODO: add a return code mProducer->cancelBuffer(dequeuedSlot, dequeuedFence); } TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers)); const int minBuffers = 1; const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers; ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false; ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers)) << "bufferCount: " << minBuffers; // Should now be able to dequeue up to minBuffers times DequeueBufferResult result; for (int i = 0; i < minBuffers; ++i) { EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, &result))) << "iteration: " << i << ", slot: " << result.slot; } ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers)); // queue the first buffer to enable max dequeued buffer count checking IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; sp buffer; ASSERT_OK(mProducer->requestBuffer(result.slot, &buffer)); ASSERT_OK(mProducer->queueBuffer(result.slot, input, &output)); // Should now be able to dequeue up to maxBuffers times int dequeuedSlot = -1; sp dequeuedFence; for (int i = 0; i < maxBuffers; ++i) { EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))) << "iteration: " << i << ", slot: " << dequeuedSlot; } // Cancel a buffer, so we can decrease the buffer count ASSERT_OK(mProducer->cancelBuffer(dequeuedSlot, dequeuedFence)); // Should now be able to decrease the max dequeued count by 1 ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1)); } TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers)); const int minBuffers = 1; const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers; ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false; // Buffer count was out of range EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0)) << "bufferCount: " << 0; EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1)) << "bufferCount: " << maxBuffers + 1; // Set max dequeue count to 2 ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2)); // Dequeue 2 buffers int dequeuedSlot = -1; sp dequeuedFence; for (int i = 0; i < 2; i++) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot; } // Client has too many buffers dequeued EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1)) << "bufferCount: " << minBuffers; // Abandon buffer queue ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) << "bufferCount: " << minBuffers; } TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1; ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true; ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1)) << "maxDequeue: " << 1; int dequeuedSlot = -1; sp dequeuedFence; IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; sp dequeuedBuffer; // Should now be able to queue/dequeue as many buffers as we want without // blocking for (int i = 0; i < 5; ++i) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))) << "slot : " << dequeuedSlot; ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); } } TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Prerequisite to fail out a valid setBufferCount call { int dequeuedSlot = -1; sp dequeuedFence; ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot; } // Abandon buffer queue ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false; } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_dequeueBuffer) { int slot = -1; sp fence; ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachNextBuffer) { sp fence; sp buffer; ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_requestBuffer) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int slot = -1; sp fence; ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); EXPECT_LE(0, slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot); ASSERT_OK(mProducer->disconnect(TEST_API)); sp buffer; ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachBuffer) { int slot = -1; sp fence; sp buffer; setupDequeueRequestBuffer(&slot, &fence, &buffer); ASSERT_OK(mProducer->disconnect(TEST_API)); ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_queueBuffer) { int slot = -1; sp fence; sp buffer; setupDequeueRequestBuffer(&slot, &fence, &buffer); ASSERT_OK(mProducer->disconnect(TEST_API)); // A generic "valid" input IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_cancelBuffer) { int slot = -1; sp fence; sp buffer; setupDequeueRequestBuffer(&slot, &fence, &buffer); ASSERT_OK(mProducer->disconnect(TEST_API)); ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence)); } TEST_F(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_attachBuffer) { int slot = -1; sp fence; sp buffer; setupDequeueRequestBuffer(&slot, &fence, &buffer); ASSERT_OK(mProducer->detachBuffer(slot)); ASSERT_OK(mProducer->disconnect(TEST_API)); ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); } } // namespace android libs/gui/tests/MultiTextureConsumer_test.cpp0100644 0000000 0000000 00000010276 13077405420 020426 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "MultiTextureConsumer_test" //#define LOG_NDEBUG 0 #include "GLTest.h" #include #include #include #include namespace android { class MultiTextureConsumerTest : public GLTest { protected: enum { TEX_ID = 123 }; virtual void SetUp() { GLTest::SetUp(); sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); mGlConsumer = new GLConsumer(consumer, TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false); mSurface = new Surface(producer); mANW = mSurface.get(); } virtual void TearDown() { GLTest::TearDown(); } virtual EGLint const* getContextAttribs() { return NULL; } virtual EGLint const* getConfigAttribs() { static EGLint sDefaultConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; return sDefaultConfigAttribs; } sp mGlConsumer; sp mSurface; ANativeWindow* mANW; }; TEST_F(MultiTextureConsumerTest, EGLImageTargetWorks) { ANativeWindow_Buffer buffer; ASSERT_EQ(native_window_set_usage(mANW, GRALLOC_USAGE_SW_WRITE_OFTEN), NO_ERROR); ASSERT_EQ(native_window_set_buffers_format(mANW, HAL_PIXEL_FORMAT_RGBA_8888), NO_ERROR); glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_CULL_FACE); glViewport(0, 0, getSurfaceWidth(), getSurfaceHeight()); glOrthof(0, getSurfaceWidth(), 0, getSurfaceHeight(), 0, 1); glEnableClientState(GL_VERTEX_ARRAY); glColor4f(1, 1, 1, 1); glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); uint32_t texel = 0x80808080; glBindTexture(GL_TEXTURE_2D, TEX_ID+1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texel); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, TEX_ID+1); glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID); glEnable(GL_TEXTURE_EXTERNAL_OES); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glClear(GL_COLOR_BUFFER_BIT); for (int i=0 ; i<8 ; i++) { mSurface->lock(&buffer, NULL); memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4); mSurface->unlockAndPost(); mGlConsumer->updateTexImage(); GLfloat vertices[][2] = { {i*16.0f, 0}, {(i+1)*16.0f, 0}, {(i+1)*16.0f, 16.0f}, {i*16.0f, 16.0f} }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } for (int i=0 ; i<8 ; i++) { EXPECT_TRUE(checkPixel(i*16 + 8, 8, i*16, i*16, i*16, i*16, 0)); } } } // namespace android libs/gui/tests/SRGB_test.cpp0100644 0000000 0000000 00000042404 13077405420 014772 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "SRGB_test" //#define LOG_NDEBUG 0 // Ignore for this file because it flags every instance of // ASSERT_EQ(GL_NO_ERROR, glGetError()); #pragma clang diagnostic ignored "-Wsign-compare" #include "GLTest.h" #include #include #include #include #include #include #include #include #include namespace android { class SRGBTest : public ::testing::Test { protected: // Class constants enum { DISPLAY_WIDTH = 512, DISPLAY_HEIGHT = 512, PIXEL_SIZE = 4, // bytes or components DISPLAY_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT * PIXEL_SIZE, ALPHA_VALUE = 223, // should be in [0, 255] TOLERANCE = 1, }; static const char SHOW_DEBUG_STRING[]; SRGBTest() : mInputSurface(), mCpuConsumer(), mLockedBuffer(), mEglDisplay(EGL_NO_DISPLAY), mEglConfig(), mEglContext(EGL_NO_CONTEXT), mEglSurface(EGL_NO_SURFACE), mComposerClient(), mSurfaceControl(), mOutputSurface() { } virtual ~SRGBTest() { if (mEglDisplay != EGL_NO_DISPLAY) { if (mEglSurface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, mEglSurface); } if (mEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mEglContext); } eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(mEglDisplay); } } virtual void SetUp() { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize( DISPLAY_WIDTH, DISPLAY_HEIGHT)); mCpuConsumer = new CpuConsumer(consumer, 1); String8 name("CpuConsumer_for_SRGBTest"); mCpuConsumer->setName(name); mInputSurface = new Surface(producer); ASSERT_NO_FATAL_FAILURE(createEGLSurface(mInputSurface.get())); ASSERT_NO_FATAL_FAILURE(createDebugSurface()); } virtual void TearDown() { ASSERT_NO_FATAL_FAILURE(copyToDebugSurface()); ASSERT_TRUE(mLockedBuffer.data != NULL); ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer)); } static float linearToSRGB(float l) { if (l <= 0.0031308f) { return l * 12.92f; } else { return 1.055f * pow(l, (1 / 2.4f)) - 0.055f; } } static float srgbToLinear(float s) { if (s <= 0.04045) { return s / 12.92f; } else { return pow(((s + 0.055f) / 1.055f), 2.4f); } } static uint8_t srgbToLinear(uint8_t u) { float f = u / 255.0f; return static_cast(srgbToLinear(f) * 255.0f + 0.5f); } void fillTexture(bool writeAsSRGB) { uint8_t* textureData = new uint8_t[DISPLAY_SIZE]; for (int y = 0; y < DISPLAY_HEIGHT; ++y) { for (int x = 0; x < DISPLAY_WIDTH; ++x) { float realValue = static_cast(x) / (DISPLAY_WIDTH - 1); realValue *= ALPHA_VALUE / 255.0f; // Premultiply by alpha if (writeAsSRGB) { realValue = linearToSRGB(realValue); } int offset = (y * DISPLAY_WIDTH + x) * PIXEL_SIZE; for (int c = 0; c < 3; ++c) { uint8_t intValue = static_cast( realValue * 255.0f + 0.5f); textureData[offset + c] = intValue; } textureData[offset + 3] = ALPHA_VALUE; } } glTexImage2D(GL_TEXTURE_2D, 0, writeAsSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); ASSERT_EQ(GL_NO_ERROR, glGetError()); delete[] textureData; } void initShaders() { static const char vertexSource[] = "attribute vec4 vPosition;\n" "varying vec2 texCoords;\n" "void main() {\n" " texCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n" " gl_Position = vPosition;\n" "}\n"; static const char fragmentSource[] = "precision mediump float;\n" "uniform sampler2D texSampler;\n" "varying vec2 texCoords;\n" "void main() {\n" " gl_FragColor = texture2D(texSampler, texCoords);\n" "}\n"; GLuint program; { SCOPED_TRACE("Creating shader program"); ASSERT_NO_FATAL_FAILURE(GLTest::createProgram( vertexSource, fragmentSource, &program)); } GLint positionHandle = glGetAttribLocation(program, "vPosition"); ASSERT_EQ(GL_NO_ERROR, glGetError()); ASSERT_NE(-1, positionHandle); GLint samplerHandle = glGetUniformLocation(program, "texSampler"); ASSERT_EQ(GL_NO_ERROR, glGetError()); ASSERT_NE(-1, samplerHandle); static const GLfloat vertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, }; glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); ASSERT_EQ(GL_NO_ERROR, glGetError()); glEnableVertexAttribArray(positionHandle); ASSERT_EQ(GL_NO_ERROR, glGetError()); glUseProgram(program); ASSERT_EQ(GL_NO_ERROR, glGetError()); glUniform1i(samplerHandle, 0); ASSERT_EQ(GL_NO_ERROR, glGetError()); GLuint textureHandle; glGenTextures(1, &textureHandle); ASSERT_EQ(GL_NO_ERROR, glGetError()); glBindTexture(GL_TEXTURE_2D, textureHandle); ASSERT_EQ(GL_NO_ERROR, glGetError()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ASSERT_EQ(GL_NO_ERROR, glGetError()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ASSERT_EQ(GL_NO_ERROR, glGetError()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ASSERT_EQ(GL_NO_ERROR, glGetError()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ASSERT_EQ(GL_NO_ERROR, glGetError()); } void drawTexture(bool asSRGB, GLint x, GLint y, GLsizei width, GLsizei height) { ASSERT_NO_FATAL_FAILURE(fillTexture(asSRGB)); glViewport(x, y, width, height); ASSERT_EQ(GL_NO_ERROR, glGetError()); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); ASSERT_EQ(GL_NO_ERROR, glGetError()); } void checkLockedBuffer(PixelFormat format, android_dataspace dataSpace) { ASSERT_EQ(mLockedBuffer.format, format); ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH); ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT); ASSERT_EQ(mLockedBuffer.dataSpace, dataSpace); } static bool withinTolerance(int a, int b) { int diff = a - b; return diff >= 0 ? diff <= TOLERANCE : -diff <= TOLERANCE; } // Primary producer and consumer sp mInputSurface; sp mCpuConsumer; CpuConsumer::LockedBuffer mLockedBuffer; EGLDisplay mEglDisplay; EGLConfig mEglConfig; EGLContext mEglContext; EGLSurface mEglSurface; // Auxiliary display output sp mComposerClient; sp mSurfaceControl; sp mOutputSurface; private: void createEGLSurface(Surface* inputSurface) { mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); EXPECT_TRUE(eglInitialize(mEglDisplay, NULL, NULL)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); static const EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; EGLint numConfigs = 0; EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &mEglConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_GT(numConfigs, 0); static const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE } ; mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttribs); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mEglContext); mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, inputSurface, NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mEglSurface); EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); } void createDebugSurface() { if (getenv(SHOW_DEBUG_STRING) == NULL) return; mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( String8("SRGBTest Surface"), DISPLAY_WIDTH, DISPLAY_HEIGHT, PIXEL_FORMAT_RGBA_8888); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(); ANativeWindow_Buffer outBuffer; ARect inOutDirtyBounds; mOutputSurface = mSurfaceControl->getSurface(); mOutputSurface->lock(&outBuffer, &inOutDirtyBounds); uint8_t* bytePointer = reinterpret_cast(outBuffer.bits); for (int y = 0; y < outBuffer.height; ++y) { int rowOffset = y * outBuffer.stride; // pixels for (int x = 0; x < outBuffer.width; ++x) { int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes for (int c = 0; c < PIXEL_SIZE; ++c) { int offset = colOffset + c; bytePointer[offset] = ((c + 1) * 56) - 1; } } } mOutputSurface->unlockAndPost(); } void copyToDebugSurface() { if (!mOutputSurface.get()) return; size_t bufferSize = mLockedBuffer.height * mLockedBuffer.stride * PIXEL_SIZE; ANativeWindow_Buffer outBuffer; ARect outBufferBounds; mOutputSurface->lock(&outBuffer, &outBufferBounds); ASSERT_EQ(mLockedBuffer.width, static_cast(outBuffer.width)); ASSERT_EQ(mLockedBuffer.height, static_cast(outBuffer.height)); ASSERT_EQ(mLockedBuffer.stride, static_cast(outBuffer.stride)); if (mLockedBuffer.format == outBuffer.format) { memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize); } else { ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_RGBA_8888); ASSERT_EQ(mLockedBuffer.dataSpace, HAL_DATASPACE_SRGB); ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888); uint8_t* outPointer = reinterpret_cast(outBuffer.bits); for (int y = 0; y < outBuffer.height; ++y) { int rowOffset = y * outBuffer.stride; // pixels for (int x = 0; x < outBuffer.width; ++x) { int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes // RGB are converted for (int c = 0; c < (PIXEL_SIZE - 1); ++c) { outPointer[colOffset + c] = srgbToLinear( mLockedBuffer.data[colOffset + c]); } // Alpha isn't converted outPointer[colOffset + 3] = mLockedBuffer.data[colOffset + 3]; } } } mOutputSurface->unlockAndPost(); int sleepSeconds = atoi(getenv(SHOW_DEBUG_STRING)); sleep(sleepSeconds); } }; const char SRGBTest::SHOW_DEBUG_STRING[] = "DEBUG_OUTPUT_SECONDS"; TEST_F(SRGBTest, GLRenderFromSRGBTexture) { ASSERT_NO_FATAL_FAILURE(initShaders()); // The RGB texture is displayed in the top half ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, DISPLAY_HEIGHT / 2, DISPLAY_WIDTH, DISPLAY_HEIGHT / 2)); // The SRGB texture is displayed in the bottom half ASSERT_NO_FATAL_FAILURE(drawTexture(true, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT / 2)); eglSwapBuffers(mEglDisplay, mEglSurface); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); ASSERT_NO_FATAL_FAILURE( checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Compare a pixel in the middle of each texture int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride * PIXEL_SIZE; int midRGBOffset = midSRGBOffset * 3; midRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE; midSRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE; for (int c = 0; c < PIXEL_SIZE; ++c) { int expectedValue = mLockedBuffer.data[midRGBOffset + c]; int actualValue = mLockedBuffer.data[midSRGBOffset + c]; ASSERT_PRED2(withinTolerance, expectedValue, actualValue); } // mLockedBuffer is unlocked in TearDown so we can copy data from it to // the debug surface if necessary } // XXX: Disabled since we don't currently expect this to work TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) { ASSERT_NO_FATAL_FAILURE(initShaders()); // By default, the first buffer we write into will be RGB // Render an RGB texture across the whole surface ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); eglSwapBuffers(mEglDisplay, mEglSurface); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); ASSERT_NO_FATAL_FAILURE( checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Save the values of the middle pixel for later comparison against SRGB uint8_t values[PIXEL_SIZE] = {}; int middleOffset = (DISPLAY_HEIGHT / 2) * mLockedBuffer.stride * PIXEL_SIZE; middleOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE; for (int c = 0; c < PIXEL_SIZE; ++c) { values[c] = mLockedBuffer.data[middleOffset + c]; } // Unlock ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer)); // Switch to SRGB window surface #define EGL_GL_COLORSPACE_KHR EGL_VG_COLORSPACE #define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB static const int srgbAttribs[] = { EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE, }; EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mInputSurface.get(), srgbAttribs); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mEglSurface); EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Render the texture again ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); eglSwapBuffers(mEglDisplay, mEglSurface); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); // Make sure we actually got the SRGB buffer on the consumer side ASSERT_NO_FATAL_FAILURE( checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_SRGB)); // Verify that the stored value is the same, accounting for RGB/SRGB for (int c = 0; c < PIXEL_SIZE; ++c) { // The alpha value should be equivalent before linear->SRGB float rgbAsSRGB = (c == 3) ? values[c] / 255.0f : linearToSRGB(values[c] / 255.0f); int expectedValue = rgbAsSRGB * 255.0f + 0.5f; int actualValue = mLockedBuffer.data[middleOffset + c]; ASSERT_PRED2(withinTolerance, expectedValue, actualValue); } // mLockedBuffer is unlocked in TearDown so we can copy data from it to // the debug surface if necessary } } // namespace android libs/gui/tests/StreamSplitter_test.cpp0100644 0000000 0000000 00000021744 13077405420 017223 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "StreamSplitter_test" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include namespace android { class StreamSplitterTest : public ::testing::Test { protected: StreamSplitterTest() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); } ~StreamSplitterTest() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); } }; struct DummyListener : public BnConsumerListener { virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; static const uint32_t TEST_DATA = 0x12345678u; TEST_F(StreamSplitterTest, OneInputOneOutput) { sp inputProducer; sp inputConsumer; BufferQueue::createBufferQueue(&inputProducer, &inputConsumer); sp outputProducer; sp outputConsumer; BufferQueue::createBufferQueue(&outputProducer, &outputConsumer); ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false)); sp splitter; status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter); ASSERT_EQ(OK, status); ASSERT_EQ(OK, splitter->addOutput(outputProducer)); // Never allow the output BufferQueue to allocate a buffer ASSERT_EQ(OK, outputProducer->allowAllocation(false)); IGraphicBufferProducer::QueueBufferOutput qbOutput; ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); // Now that we have dequeued/allocated one buffer, prevent any further // allocations ASSERT_EQ(OK, inputProducer->allowAllocation(false)); BufferItem item; ASSERT_EQ(OK, outputConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); // This should succeed even with allocation disabled since it will have // received the buffer back from the output BufferQueue ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { const int NUM_OUTPUTS = 4; sp inputProducer; sp inputConsumer; BufferQueue::createBufferQueue(&inputProducer, &inputConsumer); sp outputProducers[NUM_OUTPUTS] = {}; sp outputConsumers[NUM_OUTPUTS] = {}; for (int output = 0; output < NUM_OUTPUTS; ++output) { BufferQueue::createBufferQueue(&outputProducers[output], &outputConsumers[output]); ASSERT_EQ(OK, outputConsumers[output]->consumerConnect( new DummyListener, false)); } sp splitter; status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter); ASSERT_EQ(OK, status); for (int output = 0; output < NUM_OUTPUTS; ++output) { ASSERT_EQ(OK, splitter->addOutput(outputProducers[output])); // Never allow the output BufferQueues to allocate a buffer ASSERT_EQ(OK, outputProducers[output]->allowAllocation(false)); } IGraphicBufferProducer::QueueBufferOutput qbOutput; ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast(&dataIn))); *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); // Now that we have dequeued/allocated one buffer, prevent any further // allocations ASSERT_EQ(OK, inputProducer->allowAllocation(false)); for (int output = 0; output < NUM_OUTPUTS; ++output) { BufferItem item; ASSERT_EQ(OK, outputConsumers[output]->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast(&dataOut))); ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); } // This should succeed even with allocation disabled since it will have // received the buffer back from the output BufferQueues ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } TEST_F(StreamSplitterTest, OutputAbandonment) { sp inputProducer; sp inputConsumer; BufferQueue::createBufferQueue(&inputProducer, &inputConsumer); sp outputProducer; sp outputConsumer; BufferQueue::createBufferQueue(&outputProducer, &outputConsumer); ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false)); sp splitter; status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter); ASSERT_EQ(OK, status); ASSERT_EQ(OK, splitter->addOutput(outputProducer)); IGraphicBufferProducer::QueueBufferOutput qbOutput; ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput)); int slot; sp fence; sp buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); // Abandon the output outputConsumer->consumerDisconnect(); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); // Input should be abandoned ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); } } // namespace android libs/gui/tests/SurfaceTextureClient_test.cpp0100644 0000000 0000000 00000076736 13077405420 020364 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "SurfaceTextureClient_test" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define CROP_EXT_STR "EGL_ANDROID_image_crop" namespace android { class SurfaceTextureClientTest : public ::testing::Test { protected: SurfaceTextureClientTest(): mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT), mEglConfig(NULL) { } virtual void SetUp() { const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); mST = new GLConsumer(consumer, 123, GLConsumer::TEXTURE_EXTERNAL, true, false); mSTC = new Surface(producer); mANW = mSTC; // We need a valid GL context so we can test updateTexImage() // This initializes EGL and create a dummy GL context with a // pbuffer render target. mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); EGLint majorVersion, minorVersion; EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLConfig myConfig; EGLint numConfigs = 0; EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mEglConfig = myConfig; EGLint pbufferAttribs[] = { EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE }; mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig, pbufferAttribs); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mEglSurface); mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mEglContext); EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); } virtual void TearDown() { mST.clear(); mSTC.clear(); mANW.clear(); eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(mEglDisplay, mEglContext); eglDestroySurface(mEglDisplay, mEglSurface); eglTerminate(mEglDisplay); const ::testing::TestInfo* const testInfo = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("End test: %s.%s", testInfo->test_case_name(), testInfo->name()); } virtual EGLint const* getConfigAttribs() { static EGLint sDefaultConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT, EGL_NONE }; return sDefaultConfigAttribs; } sp mST; sp mSTC; sp mANW; EGLDisplay mEglDisplay; EGLSurface mEglSurface; EGLContext mEglContext; EGLConfig mEglConfig; }; TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) { sp ist(mSTC->getIGraphicBufferProducer()); ASSERT_TRUE(ist != NULL); } TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) { int result = -123; int err = mANW->query(mANW.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result); EXPECT_EQ(NO_ERROR, err); EXPECT_EQ(0, result); } TEST_F(SurfaceTextureClientTest, ConcreteTypeIsSurfaceTextureClient) { int result = -123; int err = mANW->query(mANW.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result); EXPECT_EQ(NO_ERROR, err); EXPECT_EQ(NATIVE_WINDOW_SURFACE, result); } TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) { EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_DISPLAY, dpy); EGLint majorVersion; EGLint minorVersion; EXPECT_TRUE(eglInitialize(dpy, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLConfig myConfig = {0}; EGLint numConfigs = 0; EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, 8, EGL_NONE }; EXPECT_TRUE(eglChooseConfig(dpy, configAttribs, &myConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, mANW.get(), NULL); EXPECT_NE(EGL_NO_SURFACE, eglSurface); EXPECT_EQ(EGL_SUCCESS, eglGetError()); if (eglSurface != EGL_NO_SURFACE) { eglDestroySurface(dpy, eglSurface); } eglTerminate(dpy); } TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) { EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL); EXPECT_NE(EGL_NO_SURFACE, eglSurface); EXPECT_EQ(EGL_SUCCESS, eglGetError()); EGLBoolean success = eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext); EXPECT_TRUE(success); glClear(GL_COLOR_BUFFER_BIT); success = eglSwapBuffers(mEglDisplay, eglSurface); EXPECT_TRUE(success); mST->abandon(); glClear(GL_COLOR_BUFFER_BIT); success = eglSwapBuffers(mEglDisplay, eglSurface); EXPECT_FALSE(success); EXPECT_EQ(EGL_BAD_SURFACE, eglGetError()); success = eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); ASSERT_TRUE(success); if (eglSurface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, eglSurface); } } TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 8)); EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 0)); } TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer* buf; EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); sp st(mST); ANativeWindowBuffer* buf; EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { ANativeWindowBuffer* buf[2]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(16, buf[0]->width); EXPECT_EQ(16, buf[1]->width); EXPECT_EQ(8, buf[0]->height); EXPECT_EQ(8, buf[1]->height); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { ANativeWindowBuffer* buf[2]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(16, buf[0]->width); EXPECT_EQ(16, buf[1]->width); EXPECT_EQ(8, buf[0]->height); EXPECT_EQ(8, buf[1]->height); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 12, 24)); EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); EXPECT_EQ(12, buf[0]->width); EXPECT_EQ(12, buf[1]->width); EXPECT_EQ(24, buf[0]->height); EXPECT_EQ(24, buf[1]->height); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); } TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); EXPECT_NE(buf[1], buf[2]); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]); } // XXX: We currently have no hardware that properly handles dequeuing the // buffer that is currently bound to the texture. TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { android_native_buffer_t* buf[3]; android_native_buffer_t* firstBuf; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), firstBuf); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); EXPECT_NE(buf[0], buf[1]); EXPECT_NE(buf[1], buf[2]); EXPECT_NE(buf[2], buf[0]); EXPECT_EQ(firstBuf, buf[2]); } TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); // Once we've queued a buffer, however we should not be able to dequeue more // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case. EXPECT_EQ(INVALID_OPERATION, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); } TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); android_native_rect_t rect = {-2, -13, 40, 18}; native_window_set_crop(mANW.get(), &rect); ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 4, 4)); android_native_buffer_t* buf; ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf, -1)); ASSERT_EQ(OK, mST->updateTexImage()); Rect crop = mST->getCurrentCrop(); EXPECT_EQ(0, crop.left); EXPECT_EQ(0, crop.top); EXPECT_EQ(4, crop.right); EXPECT_EQ(4, crop.bottom); } // XXX: This is not expected to pass until the synchronization hacks are removed // from the SurfaceTexture class. TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { class MyThread : public Thread { sp mST; EGLContext ctx; EGLSurface sur; EGLDisplay dpy; bool mBufferRetired; Mutex mLock; virtual bool threadLoop() { eglMakeCurrent(dpy, sur, sur, ctx); usleep(20000); Mutex::Autolock _l(mLock); mST->updateTexImage(); mBufferRetired = true; eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return false; } public: MyThread(const sp& mST) : mST(mST), mBufferRetired(false) { ctx = eglGetCurrentContext(); sur = eglGetCurrentSurface(EGL_DRAW); dpy = eglGetCurrentDisplay(); eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } ~MyThread() { eglMakeCurrent(dpy, sur, sur, ctx); } void bufferDequeued() { Mutex::Autolock _l(mLock); EXPECT_EQ(true, mBufferRetired); } }; android_native_buffer_t* buf[3]; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); mST->updateTexImage(); MyThread* thread = new MyThread(mST); sp threadBase(thread); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); thread->run("MyThread"); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1)); //ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2])); //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1)); thread->bufferDequeued(); thread->requestExitAndWait(); } TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) { android_native_buffer_t* buf[3]; float mtx[16] = {}; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); mST->getTransformMatrix(mtx); EXPECT_EQ(1.f, mtx[0]); EXPECT_EQ(0.f, mtx[1]); EXPECT_EQ(0.f, mtx[2]); EXPECT_EQ(0.f, mtx[3]); EXPECT_EQ(0.f, mtx[4]); EXPECT_EQ(-1.f, mtx[5]); EXPECT_EQ(0.f, mtx[6]); EXPECT_EQ(0.f, mtx[7]); EXPECT_EQ(0.f, mtx[8]); EXPECT_EQ(0.f, mtx[9]); EXPECT_EQ(1.f, mtx[10]); EXPECT_EQ(0.f, mtx[11]); EXPECT_EQ(0.f, mtx[12]); EXPECT_EQ(1.f, mtx[13]); EXPECT_EQ(0.f, mtx[14]); EXPECT_EQ(1.f, mtx[15]); } TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) { android_native_buffer_t* buf[3]; float mtx[16] = {}; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); EXPECT_EQ(1.f, mtx[0]); EXPECT_EQ(0.f, mtx[1]); EXPECT_EQ(0.f, mtx[2]); EXPECT_EQ(0.f, mtx[3]); EXPECT_EQ(0.f, mtx[4]); EXPECT_EQ(-1.f, mtx[5]); EXPECT_EQ(0.f, mtx[6]); EXPECT_EQ(0.f, mtx[7]); EXPECT_EQ(0.f, mtx[8]); EXPECT_EQ(0.f, mtx[9]); EXPECT_EQ(1.f, mtx[10]); EXPECT_EQ(0.f, mtx[11]); EXPECT_EQ(0.f, mtx[12]); EXPECT_EQ(1.f, mtx[13]); EXPECT_EQ(0.f, mtx[14]); EXPECT_EQ(1.f, mtx[15]); } TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) { // Query to see if the image crop extension exists EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); size_t cropExtLen = strlen(CROP_EXT_STR); size_t extsLen = strlen(exts); bool equal = !strcmp(CROP_EXT_STR, exts); bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1); bool atEnd = (cropExtLen+1) < extsLen && !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1)); bool inMiddle = strstr(exts, " " CROP_EXT_STR " "); bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle; android_native_buffer_t* buf[3]; float mtx[16] = {}; android_native_rect_t crop; crop.left = 0; crop.top = 0; crop.right = 5; crop.bottom = 5; ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8)); ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); // If the egl image crop extension is not present, this accounts for the // .5 texel shrink for each edge that's included in the transform matrix // to avoid texturing outside the crop region. Otherwise the crop is not // included in the transform matrix. EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]); EXPECT_EQ(0.f, mtx[1]); EXPECT_EQ(0.f, mtx[2]); EXPECT_EQ(0.f, mtx[3]); EXPECT_EQ(0.f, mtx[4]); EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]); EXPECT_EQ(0.f, mtx[6]); EXPECT_EQ(0.f, mtx[7]); EXPECT_EQ(0.f, mtx[8]); EXPECT_EQ(0.f, mtx[9]); EXPECT_EQ(1.f, mtx[10]); EXPECT_EQ(0.f, mtx[11]); EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]); EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]); EXPECT_EQ(0.f, mtx[14]); EXPECT_EQ(1.f, mtx[15]); } // This test verifies that the buffer format can be queried immediately after // it is set. TEST_F(SurfaceTextureClientTest, QueryFormatAfterSettingWorks) { sp anw(mSTC); int fmts[] = { // RGBA_8888 should not come first, as it's the default HAL_PIXEL_FORMAT_RGBX_8888, HAL_PIXEL_FORMAT_RGBA_8888, HAL_PIXEL_FORMAT_RGB_888, HAL_PIXEL_FORMAT_RGB_565, HAL_PIXEL_FORMAT_BGRA_8888, HAL_PIXEL_FORMAT_YV12, }; const int numFmts = (sizeof(fmts) / sizeof(fmts[0])); for (int i = 0; i < numFmts; i++) { int fmt = -1; ASSERT_EQ(OK, native_window_set_buffers_dimensions(anw.get(), 0, 0)); ASSERT_EQ(OK, native_window_set_buffers_format(anw.get(), fmts[i])); ASSERT_EQ(OK, anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt)); EXPECT_EQ(fmts[i], fmt); } } class MultiSurfaceTextureClientTest : public ::testing::Test { public: MultiSurfaceTextureClientTest() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) { for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { mEglSurfaces[i] = EGL_NO_CONTEXT; } } protected: enum { NUM_SURFACE_TEXTURES = 32 }; virtual void SetUp() { mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); EGLint majorVersion, minorVersion; EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLConfig myConfig; EGLint numConfigs = 0; EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mEglContext); for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp st(new GLConsumer(consumer, i, GLConsumer::TEXTURE_EXTERNAL, true, false)); sp stc(new Surface(producer)); mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig, static_cast(stc.get()), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]); } } virtual void TearDown() { eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { if (mEglSurfaces[i] != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, mEglSurfaces[i]); } } if (mEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mEglContext); } if (mEglDisplay != EGL_NO_DISPLAY) { eglTerminate(mEglDisplay); } } EGLDisplay mEglDisplay; EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES]; EGLContext mEglContext; }; // XXX: This test is disabled because it causes a hang on some devices. See bug // 5015672. TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) { for (int iter = 0; iter < 8; iter++) { for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i], mEglContext); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mEglSurfaces[i]); } } } } // namespace android libs/gui/tests/SurfaceTextureFBO.h0100644 0000000 0000000 00000004315 13077405420 016142 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_TEXTURE_FBO_H #define ANDROID_SURFACE_TEXTURE_FBO_H #include "SurfaceTextureGL.h" #include namespace android { class SurfaceTextureFBOTest : public SurfaceTextureGLTest { protected: virtual void SetUp() { SurfaceTextureGLTest::SetUp(); glGenFramebuffers(1, &mFbo); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glGenTextures(1, &mFboTex); glBindTexture(GL_TEXTURE_2D, mFboTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(), getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glBindFramebuffer(GL_FRAMEBUFFER, mFbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboTex, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } virtual void TearDown() { SurfaceTextureGLTest::TearDown(); glDeleteTextures(1, &mFboTex); glDeleteFramebuffers(1, &mFbo); } GLuint mFbo; GLuint mFboTex; }; void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { const size_t PIXEL_SIZE = 4; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { off_t offset = (y * stride + x) * PIXEL_SIZE; buf[offset + 0] = r; buf[offset + 1] = g; buf[offset + 2] = b; buf[offset + 3] = a; } } } } // namespace android #endif libs/gui/tests/SurfaceTextureFBO_test.cpp0100644 0000000 0000000 00000005766 13077405420 017547 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "SurfaceTextureFBO_test" //#define LOG_NDEBUG 0 #include "SurfaceTextureFBO.h" namespace android { // This test is intended to verify that proper synchronization is done when // rendering into an FBO. TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { const int texWidth = 64; const int texHeight = 64; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); android_native_buffer_t* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); // Fill the buffer with green uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255, 0, 255); buf->unlock(); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glBindFramebuffer(GL_FRAMEBUFFER, mFbo); drawTexture(); glBindFramebuffer(GL_FRAMEBUFFER, 0); for (int i = 0; i < 4; i++) { SCOPED_TRACE(String8::format("frame %d", i).string()); ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); buf = new GraphicBuffer(anb, false); // Fill the buffer with red ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img))); fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0, 0, 255); ASSERT_EQ(NO_ERROR, buf->unlock()); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); drawTexture(); EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255)); } glBindFramebuffer(GL_FRAMEBUFFER, mFbo); EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255)); } } // namespace android libs/gui/tests/SurfaceTextureGL.h0100644 0000000 0000000 00000003646 13077405420 016044 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_TEXTURE_GL_H #define ANDROID_SURFACE_TEXTURE_GL_H #include "GLTest.h" #include "FrameWaiter.h" #include "TextureRenderer.h" #include #include namespace android { class FrameWaiter; class GLConsumer; class TextureRenderer; class SurfaceTextureGLTest : public GLTest { protected: enum { TEX_ID = 123 }; void SetUp() { GLTest::SetUp(); sp producer; BufferQueue::createBufferQueue(&producer, &mConsumer); mST = new GLConsumer(mConsumer, TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false); mSTC = new Surface(producer); mANW = mSTC; mTextureRenderer = new TextureRenderer(TEX_ID, mST); ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp()); mFW = new FrameWaiter; mST->setFrameAvailableListener(mFW); } void TearDown() { mTextureRenderer.clear(); mANW.clear(); mSTC.clear(); mST.clear(); GLTest::TearDown(); } void drawTexture() { mTextureRenderer->drawTexture(); } sp mConsumer; sp mST; sp mSTC; sp mANW; sp mTextureRenderer; sp mFW; }; } // namespace android #endif libs/gui/tests/SurfaceTextureGLThreadToGL.h0100644 0000000 0000000 00000013774 13077405420 017725 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_TEXTURE_GL_THREAD_TO_GL_H #define ANDROID_SURFACE_TEXTURE_GL_THREAD_TO_GL_H #include "SurfaceTextureGLToGL.h" namespace android { /* * This test fixture is for testing GL -> GL texture streaming from one thread * to another. It contains functionality to create a producer thread that will * perform GL rendering to an ANativeWindow that feeds frames to a * GLConsumer. Additionally it supports interlocking the producer and * consumer threads so that a specific sequence of calls can be * deterministically created by the test. * * The intended usage is as follows: * * TEST_F(...) { * class PT : public ProducerThread { * virtual void render() { * ... * swapBuffers(); * } * }; * * runProducerThread(new PT()); * * // The order of these calls will vary from test to test and may include * // multiple frames and additional operations (e.g. GL rendering from the * // texture). * fc->waitForFrame(); * mST->updateTexImage(); * fc->finishFrame(); * } * */ class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest { protected: // ProducerThread is an abstract base class to simplify the creation of // OpenGL ES frame producer threads. class ProducerThread : public Thread { public: virtual ~ProducerThread() { } void setEglObjects(EGLDisplay producerEglDisplay, EGLSurface producerEglSurface, EGLContext producerEglContext) { mProducerEglDisplay = producerEglDisplay; mProducerEglSurface = producerEglSurface; mProducerEglContext = producerEglContext; } virtual bool threadLoop() { eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext); render(); eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return false; } protected: virtual void render() = 0; void swapBuffers() { eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface); } EGLDisplay mProducerEglDisplay; EGLSurface mProducerEglSurface; EGLContext mProducerEglContext; }; // FrameCondition is a utility class for interlocking between the producer // and consumer threads. The FrameCondition object should be created and // destroyed in the consumer thread only. The consumer thread should set // the FrameCondition as the FrameAvailableListener of the GLConsumer, // and should call both waitForFrame and finishFrame once for each expected // frame. // // This interlocking relies on the fact that onFrameAvailable gets called // synchronously from GLConsumer::queueBuffer. class FrameCondition : public GLConsumer::FrameAvailableListener { public: FrameCondition(): mFrameAvailable(false), mFrameFinished(false) { } // waitForFrame waits for the next frame to arrive. This should be // called from the consumer thread once for every frame expected by the // test. void waitForFrame() { Mutex::Autolock lock(mMutex); ALOGV("+waitForFrame"); while (!mFrameAvailable) { mFrameAvailableCondition.wait(mMutex); } mFrameAvailable = false; ALOGV("-waitForFrame"); } // Allow the producer to return from its swapBuffers call and continue // on to produce the next frame. This should be called by the consumer // thread once for every frame expected by the test. void finishFrame() { Mutex::Autolock lock(mMutex); ALOGV("+finishFrame"); mFrameFinished = true; mFrameFinishCondition.signal(); ALOGV("-finishFrame"); } // This should be called by GLConsumer on the producer thread. virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); ALOGV("+onFrameAvailable"); mFrameAvailable = true; mFrameAvailableCondition.signal(); while (!mFrameFinished) { mFrameFinishCondition.wait(mMutex); } mFrameFinished = false; ALOGV("-onFrameAvailable"); } protected: bool mFrameAvailable; bool mFrameFinished; Mutex mMutex; Condition mFrameAvailableCondition; Condition mFrameFinishCondition; }; virtual void SetUp() { SurfaceTextureGLToGLTest::SetUp(); mFC = new FrameCondition(); mST->setFrameAvailableListener(mFC); } virtual void TearDown() { if (mProducerThread != NULL) { mProducerThread->requestExitAndWait(); } mProducerThread.clear(); mFC.clear(); SurfaceTextureGLToGLTest::TearDown(); } void runProducerThread(const sp producerThread) { ASSERT_TRUE(mProducerThread == NULL); mProducerThread = producerThread; producerThread->setEglObjects(mEglDisplay, mProducerEglSurface, mProducerEglContext); producerThread->run("ProducerThread"); } sp mProducerThread; sp mFC; }; } // namespace android #endif libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp0100644 0000000 0000000 00000013753 13077405420 021314 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "SurfaceTextureGLThreadToGL_test" //#define LOG_NDEBUG 0 #include "SurfaceTextureGLThreadToGL.h" namespace android { TEST_F(SurfaceTextureGLThreadToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); swapBuffers(); } }; SetUpWindowAndContext(); runProducerThread(new PT()); mFC->waitForFrame(); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); mFC->finishFrame(); // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } TEST_F(SurfaceTextureGLThreadToGLTest, UpdateTexImageAfterFrameFinishedCompletes) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); swapBuffers(); } }; SetUpWindowAndContext(); runProducerThread(new PT()); mFC->waitForFrame(); mFC->finishFrame(); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } TEST_F(SurfaceTextureGLThreadToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { virtual void render() { for (int i = 0; i < NUM_ITERATIONS; i++) { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ALOGV("+swapBuffers"); swapBuffers(); ALOGV("-swapBuffers"); } } }; SetUpWindowAndContext(); runProducerThread(new PT()); for (int i = 0; i < NUM_ITERATIONS; i++) { mFC->waitForFrame(); ALOGV("+updateTexImage"); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ALOGV("-updateTexImage"); mFC->finishFrame(); // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } } TEST_F(SurfaceTextureGLThreadToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { virtual void render() { for (int i = 0; i < NUM_ITERATIONS; i++) { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ALOGV("+swapBuffers"); swapBuffers(); ALOGV("-swapBuffers"); } } }; SetUpWindowAndContext(); runProducerThread(new PT()); for (int i = 0; i < NUM_ITERATIONS; i++) { mFC->waitForFrame(); mFC->finishFrame(); ALOGV("+updateTexImage"); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ALOGV("-updateTexImage"); // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } } // XXX: This test is disabled because it is currently hanging on some devices. TEST_F(SurfaceTextureGLThreadToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) { enum { NUM_ITERATIONS = 64 }; class PT : public ProducerThread { virtual void render() { for (int i = 0; i < NUM_ITERATIONS; i++) { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ALOGV("+swapBuffers"); swapBuffers(); ALOGV("-swapBuffers"); } } }; SetUpWindowAndContext(); runProducerThread(new PT()); // Allow three frames to be rendered and queued before starting the // rendering in this thread. For the latter two frames we don't call // updateTexImage so the next dequeue from the producer thread will block // waiting for a frame to become available. mFC->waitForFrame(); mFC->finishFrame(); // We must call updateTexImage to consume the first frame so that the // SurfaceTexture is able to reduce the buffer count to 2. This is because // the GL driver may dequeue a buffer when the EGLSurface is created, and // that happens before we call setDefaultMaxBufferCount. It's possible that the // driver does not dequeue a buffer at EGLSurface creation time, so we // cannot rely on this to cause the second dequeueBuffer call to block. ASSERT_EQ(NO_ERROR, mST->updateTexImage()); mFC->waitForFrame(); mFC->finishFrame(); mFC->waitForFrame(); mFC->finishFrame(); // Sleep for 100ms to allow the producer thread's dequeueBuffer call to // block waiting for a buffer to become available. usleep(100000); // Render and present a number of images. This thread should not be blocked // by the fact that the producer thread is blocking in dequeue. for (int i = 0; i < NUM_ITERATIONS; i++) { glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mEglSurface); } // Consume the two pending buffers to unblock the producer thread. ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); // Consume the remaining buffers from the producer thread. for (int i = 0; i < NUM_ITERATIONS-3; i++) { mFC->waitForFrame(); mFC->finishFrame(); ALOGV("+updateTexImage"); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ALOGV("-updateTexImage"); } } } // namespace android libs/gui/tests/SurfaceTextureGLToGL.h0100644 0000000 0000000 00000004106 13077405420 016562 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_TEXTURE_GL_TO_GL_H #define ANDROID_SURFACE_TEXTURE_GL_TO_GL_H #include "SurfaceTextureGL.h" namespace android { /* * This test fixture is for testing GL -> GL texture streaming. It creates an * EGLSurface and an EGLContext for the image producer to use. */ class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest { protected: SurfaceTextureGLToGLTest(): mProducerEglSurface(EGL_NO_SURFACE), mProducerEglContext(EGL_NO_CONTEXT) { } virtual void SetUp() { SurfaceTextureGLTest::SetUp(); } void SetUpWindowAndContext() { mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mANW.get(), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface); mProducerEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext); } virtual void TearDown() { if (mProducerEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mProducerEglContext); } if (mProducerEglSurface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, mProducerEglSurface); } SurfaceTextureGLTest::TearDown(); } EGLSurface mProducerEglSurface; EGLContext mProducerEglContext; }; } // namespace android #endif libs/gui/tests/SurfaceTextureGLToGL_test.cpp0100644 0000000 0000000 00000044303 13077405420 020157 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "SurfaceTextureGLToGL_test" //#define LOG_NDEBUG 0 #include "SurfaceTextureGLToGL.h" namespace android { TEST_F(SurfaceTextureGLToGLTest, TransformHintGetsRespected) { const uint32_t texWidth = 32; const uint32_t texHeight = 64; mST->setDefaultBufferSize(texWidth, texHeight); mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); // This test requires 3 buffers to avoid deadlock because we're // both producer and consumer, and only using one thread. Set max dequeued // to 2, and max acquired already defaults to 1. ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); SetUpWindowAndContext(); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Start a buffer with our chosen size and transform hint moving // through the system. glClear(GL_COLOR_BUFFER_BIT); // give the driver something to do eglSwapBuffers(mEglDisplay, mProducerEglSurface); mST->updateTexImage(); // consume it // Swap again. glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); mST->updateTexImage(); // The current buffer should either show the effects of the transform // hint (in the form of an inverse transform), or show that the // transform hint has been ignored. sp buf = mST->getCurrentBuffer(); if (mST->getCurrentTransform() == NATIVE_WINDOW_TRANSFORM_ROT_270) { ASSERT_EQ(texWidth, buf->getHeight()); ASSERT_EQ(texHeight, buf->getWidth()); } else { ASSERT_EQ(texWidth, buf->getWidth()); ASSERT_EQ(texHeight, buf->getHeight()); } // Reset the transform hint and confirm that it takes. mST->setTransformHint(0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); mST->updateTexImage(); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); mST->updateTexImage(); buf = mST->getCurrentBuffer(); ASSERT_EQ((uint32_t) 0, mST->getCurrentTransform()); ASSERT_EQ(texWidth, buf->getWidth()); ASSERT_EQ(texHeight, buf->getHeight()); } TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; mST->setDefaultBufferSize(texWidth, texHeight); // This test requires 3 buffers to complete run on a single thread. // Set max dequeued to 2, and max acquired already defaults to 1. ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); SetUpWindowAndContext(); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // This is needed to ensure we pick up a buffer of the correct size. eglSwapBuffers(mEglDisplay, mProducerEglSurface); glClearColor(0.6, 0.6, 0.6, 0.6); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); glScissor(4, 4, 4, 4); glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glScissor(24, 48, 4, 4); glClearColor(0.0, 1.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glScissor(37, 17, 4, 4); glClearColor(0.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glDisable(GL_SCISSOR_TEST); // Skip the first frame, which was empty ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255)); EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255)); EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255)); EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153)); } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { SetUpWindowAndContext(); sp buffers[2]; // This test requires async mode to run on a single thread. EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); for (int i = 0; i < 2; i++) { // Produce a frame EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Consume a frame EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mFW->waitForFrame(); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); buffers[i] = mST->getCurrentBuffer(); } // Destroy the GL texture object to release its ref on buffers[2]. GLuint texID = TEX_ID; glDeleteTextures(1, &texID); // Destroy the EGLSurface EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; // This test should have the only reference to buffer 0. EXPECT_EQ(1, buffers[0]->getStrongCount()); // The GLConsumer should hold one reference to buffer 1 in its // mCurrentTextureImage member and another reference in mEglSlots. The third // reference is in this test. EXPECT_EQ(3, buffers[1]->getStrongCount()); } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { SetUpWindowAndContext(); sp buffers[3]; // This test requires async mode to run on a single thread. EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); for (int i = 0; i < 3; i++) { // Produce a frame EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Consume a frame EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mFW->waitForFrame(); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); buffers[i] = mST->getCurrentBuffer(); } // Abandon the GLConsumer, releasing the ref that the GLConsumer has // on buffers[2]. mST->abandon(); // Destroy the GL texture object to release its ref on buffers[2]. GLuint texID = TEX_ID; glDeleteTextures(1, &texID); // Destroy the EGLSurface. EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; EXPECT_EQ(1, buffers[1]->getStrongCount()); // Depending on how lazily the GL driver dequeues buffers, we may end up // with either two or three total buffers. If there are three, each entry // of the buffers array will be unique and there should only be one // reference (the one in this test). If there are two the first and last // element in the array will be equal meaning that buffer representing both // 0 and 2 will have two references (one for 0 and one for 2). if (buffers[2] != buffers[0]) { EXPECT_EQ(1, buffers[0]->getStrongCount()); EXPECT_EQ(1, buffers[2]->getStrongCount()); } else { EXPECT_EQ(2, buffers[0]->getStrongCount()); } } TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) { SetUpWindowAndContext(); sp buffer; EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); // Produce a frame glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Destroy the EGLSurface. EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; mSTC.clear(); mANW.clear(); mTextureRenderer.clear(); // Consume a frame ASSERT_EQ(NO_ERROR, mST->updateTexImage()); buffer = mST->getCurrentBuffer(); // Destroy the GL texture object to release its ref GLuint texID = TEX_ID; glDeleteTextures(1, &texID); // make un-current, all references to buffer should be gone EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); // Destroy consumer mST.clear(); EXPECT_EQ(1, buffer->getStrongCount()); } TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) { SetUpWindowAndContext(); sp buffer; EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); // Produce a frame glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Destroy the EGLSurface. EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; mSTC.clear(); mANW.clear(); mTextureRenderer.clear(); // Consume a frame ASSERT_EQ(NO_ERROR, mST->updateTexImage()); buffer = mST->getCurrentBuffer(); // Destroy the GL texture object to release its ref GLuint texID = TEX_ID; glDeleteTextures(1, &texID); // Destroy consumer mST.clear(); // make un-current, all references to buffer should be gone EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); EXPECT_EQ(1, buffer->getStrongCount()); } TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) { enum { texWidth = 64 }; enum { texHeight = 64 }; // This test requires 3 buffers to complete run on a single thread. // Set max dequeued to 2, and max acquired already defaults to 1. ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); SetUpWindowAndContext(); // Set the user buffer size. native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // This is needed to ensure we pick up a buffer of the correct size. eglSwapBuffers(mEglDisplay, mProducerEglSurface); glClearColor(0.6, 0.6, 0.6, 0.6); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); glScissor(4, 4, 1, 1); glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glDisable(GL_SCISSOR_TEST); // Skip the first frame, which was empty ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 4, 4, 255, 0, 0, 255)); EXPECT_TRUE(checkPixel( 5, 5, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 3, 3, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(45, 52, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(12, 36, 153, 153, 153, 153)); } TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedUserSizedGLFilledBuffer) { enum { texWidth = 64 }; enum { texHeight = 16 }; // This test requires 3 buffers to complete run on a single thread. // Set max dequeued to 2, and max acquired already defaults to 1. ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); SetUpWindowAndContext(); // Set the transform hint. mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); // Set the user buffer size. native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // This is needed to ensure we pick up a buffer of the correct size and the // new rotation hint. eglSwapBuffers(mEglDisplay, mProducerEglSurface); glClearColor(0.6, 0.6, 0.6, 0.6); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); glScissor(24, 4, 1, 1); glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glDisable(GL_SCISSOR_TEST); // Skip the first frame, which was empty ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 15, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 0, 15, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(24, 4, 255, 0, 0, 255)); EXPECT_TRUE(checkPixel(25, 5, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(23, 3, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(45, 13, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(12, 8, 153, 153, 153, 153)); } TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) { enum { texWidth = 64 }; enum { texHeight = 16 }; // This test requires 3 buffers to complete run on a single thread. // Set max dequeued to 2, and max acquired already defaults to 1. ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2)); SetUpWindowAndContext(); // Set the transform hint. mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90); // Set the default buffer size. mST->setDefaultBufferSize(texWidth, texHeight); // Do the producer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // This is needed to ensure we pick up a buffer of the correct size and the // new rotation hint. eglSwapBuffers(mEglDisplay, mProducerEglSurface); glClearColor(0.6, 0.6, 0.6, 0.6); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); glScissor(24, 4, 1, 1); glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); glDisable(GL_SCISSOR_TEST); // Skip the first frame, which was empty ASSERT_EQ(NO_ERROR, mST->updateTexImage()); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(63, 15, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel( 0, 15, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(24, 4, 255, 0, 0, 255)); EXPECT_TRUE(checkPixel(25, 5, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(23, 3, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(45, 13, 153, 153, 153, 153)); EXPECT_TRUE(checkPixel(12, 8, 153, 153, 153, 153)); } } // namespace android libs/gui/tests/SurfaceTextureGL_test.cpp0100644 0000000 0000000 00000064011 13077405420 017427 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "SurfaceTextureGL_test" //#define LOG_NDEBUG 0 #include "SurfaceTextureGL.h" #include "DisconnectWaiter.h" #include "FillBuffer.h" namespace android { TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { const int texWidth = 64; const int texHeight = 66; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12Buffer(img, texWidth, texHeight, buf->getStride()); buf->unlock(); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255, 3)); EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255, 3)); EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255, 3)); EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255, 3)); EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255, 3)); EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255, 3)); EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255, 3)); EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255, 3)); EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255, 3)); EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255, 3)); EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255, 3)); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { const int texWidth = 64; const int texHeight = 64; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); // Fill the buffer with the a checkerboard pattern uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12Buffer(img, texWidth, texHeight, buf->getStride()); buf->unlock(); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255)); EXPECT_TRUE(checkPixel(63, 0, 255, 127, 255, 255)); EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255)); EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255)); EXPECT_TRUE(checkPixel(22, 19, 100, 255, 74, 255)); EXPECT_TRUE(checkPixel(45, 11, 100, 255, 74, 255)); EXPECT_TRUE(checkPixel(52, 12, 155, 0, 181, 255)); EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255)); EXPECT_TRUE(checkPixel(31, 54, 0, 71, 117, 255)); EXPECT_TRUE(checkPixel(29, 28, 0, 133, 0, 255)); EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255)); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { const int texWidth = 64; const int texHeight = 66; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); android_native_rect_t crops[] = { {4, 6, 22, 36}, {0, 6, 22, 36}, {4, 0, 22, 36}, {4, 6, texWidth, 36}, {4, 6, 22, texHeight}, }; for (int i = 0; i < 5; i++) { const android_native_rect_t& crop(crops[i]); SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left, crop.top, crop.right, crop.bottom).string()); ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); sp buf(new GraphicBuffer(anb, false)); uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop); buf->unlock(); ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 64, 64); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255)); EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255)); } } // This test is intended to catch synchronization bugs between the CPU-written // and GPU-read buffers. TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { enum { texWidth = 16 }; enum { texHeight = 16 }; enum { numFrames = 1024 }; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_WRITE_OFTEN)); struct TestPixel { int x; int y; }; const TestPixel testPixels[] = { { 4, 11 }, { 12, 14 }, { 7, 2 }, }; enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])}; class ProducerThread : public Thread { public: ProducerThread(const sp& anw, const TestPixel* testPixels): mANW(anw), mTestPixels(testPixels) { } virtual ~ProducerThread() { } virtual bool threadLoop() { for (int i = 0; i < numFrames; i++) { ANativeWindowBuffer* anb; if (native_window_dequeue_buffer_and_wait(mANW.get(), &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } sp buf(new GraphicBuffer(anb, false)); const int yuvTexOffsetY = 0; int stride = buf->getStride(); int yuvTexStrideY = stride; int yuvTexOffsetV = yuvTexStrideY * texHeight; int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2; int yuvTexStrideU = yuvTexStrideV; uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); // Gray out all the test pixels first, so we're more likely to // see a failure if GL is still texturing from the buffer we // just dequeued. for (int j = 0; j < numTestPixels; j++) { int x = mTestPixels[j].x; int y = mTestPixels[j].y; uint8_t value = 128; img[y*stride + x] = value; } // Fill the buffer with gray. for (int y = 0; y < texHeight; y++) { for (int x = 0; x < texWidth; x++) { img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128; img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128; img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128; } } // Set the test pixels to either white or black. for (int j = 0; j < numTestPixels; j++) { int x = mTestPixels[j].x; int y = mTestPixels[j].y; uint8_t value = 0; if (j == (i % numTestPixels)) { value = 255; } img[y*stride + x] = value; } buf->unlock(); if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1) != NO_ERROR) { return false; } } return false; } sp mANW; const TestPixel* mTestPixels; }; sp pt(new ProducerThread(mANW, testPixels)); pt->run("ProducerThread"); glViewport(0, 0, texWidth, texHeight); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); // We wait for the first two frames up front so that the producer will be // likely to dequeue the buffer that's currently being textured from. mFW->waitForFrame(); mFW->waitForFrame(); for (int i = 0; i < numFrames; i++) { SCOPED_TRACE(String8::format("frame %d", i).string()); // We must wait for each frame to come in because if we ever do an // updateTexImage call that doesn't consume a newly available buffer // then the producer and consumer will get out of sync, which will cause // a deadlock. if (i > 1) { mFW->waitForFrame(); } ASSERT_EQ(NO_ERROR, mST->updateTexImage()); drawTexture(); for (int j = 0; j < numTestPixels; j++) { int x = testPixels[j].x; int y = testPixels[j].y; uint8_t value = 0; if (j == (i % numTestPixels)) { // We must y-invert the texture coords EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255)); } else { // We must y-invert the texture coords EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255)); } } } pt->requestExitAndWait(); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) { const int texWidth = 64; const int texHeight = 66; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231)); EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231)); EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231)); EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35)); EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35)); EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35)); EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231)); EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231)); EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231)); EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231)); EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35)); EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231)); EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231)); EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231)); EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231)); EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35)); EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231)); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), texWidth, texHeight)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); ASSERT_EQ(NO_ERROR, mST->updateTexImage()); glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, texWidth, texHeight); drawTexture(); EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231)); EXPECT_TRUE(checkPixel(63, 0, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231)); EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231, 35)); EXPECT_TRUE(checkPixel(16, 1, 231, 231, 35, 231)); EXPECT_TRUE(checkPixel(21, 12, 231, 35, 35, 231)); EXPECT_TRUE(checkPixel(26, 51, 231, 35, 231, 35)); EXPECT_TRUE(checkPixel( 5, 32, 35, 231, 231, 35)); EXPECT_TRUE(checkPixel(13, 8, 35, 231, 231, 231)); EXPECT_TRUE(checkPixel(46, 3, 35, 35, 231, 35)); EXPECT_TRUE(checkPixel(30, 33, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel( 6, 52, 231, 231, 35, 35)); EXPECT_TRUE(checkPixel(55, 33, 35, 231, 35, 231)); EXPECT_TRUE(checkPixel(16, 29, 35, 35, 231, 231)); EXPECT_TRUE(checkPixel( 1, 30, 35, 35, 35, 231)); EXPECT_TRUE(checkPixel(41, 37, 35, 35, 231, 231)); EXPECT_TRUE(checkPixel(46, 29, 231, 231, 35, 35)); EXPECT_TRUE(checkPixel(15, 25, 35, 231, 35, 231)); EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35)); } // Tests if GLConsumer and BufferQueue are robust enough // to handle a special case where updateTexImage is called // in the middle of disconnect. This ordering is enforced // by blocking in the disconnect callback. TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { class ProducerThread : public Thread { public: ProducerThread(const sp& anw): mANW(anw) { } virtual ~ProducerThread() { } virtual bool threadLoop() { ANativeWindowBuffer* anb; if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) != NO_ERROR) { return false; } for (int numFrames =0 ; numFrames < 2; numFrames ++) { if (native_window_dequeue_buffer_and_wait(mANW.get(), &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } } if (native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU) != NO_ERROR) { return false; } return false; } private: sp mANW; }; sp dw(new DisconnectWaiter()); mConsumer->consumerConnect(dw, false); sp pt(new ProducerThread(mANW)); pt->run("ProducerThread"); // eat a frame so GLConsumer will own an at least one slot dw->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); dw->waitForFrame(); // Could fail here as GLConsumer thinks it still owns the slot // but bufferQueue has released all slots EXPECT_EQ(OK,mST->updateTexImage()); dw->finishDisconnect(); } // This test ensures that the GLConsumer clears the mCurrentTexture // when it is disconnected and reconnected. Otherwise it will // attempt to release a buffer that it does not owned TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer *anb; EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(OK,mST->updateTexImage()); EXPECT_EQ(OK,mST->updateTexImage()); ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); // Will fail here if mCurrentTexture is not cleared properly mFW->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU)); } TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); // The producer image size ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 512, 512)); // The consumer image size (16 x 9) ratio mST->setDefaultBufferSize(1280, 720); ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ANativeWindowBuffer *anb; android_native_rect_t odd = {23, 78, 123, 477}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &odd)); EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK, mST->updateTexImage()); Rect r = mST->getCurrentCrop(); assertRectEq(Rect(23, 78, 123, 477), r); ASSERT_EQ(OK, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU)); } // This test ensures the scaling mode does the right thing // ie NATIVE_WINDOW_SCALING_MODE_CROP should crop // the image such that it has the same aspect ratio as the // default buffer size TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)); // The producer image size ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 512, 512)); // The consumer image size (16 x 9) ratio mST->setDefaultBufferSize(1280, 720); native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU); ANativeWindowBuffer *anb; // The crop is in the shape of (320, 180) === 16 x 9 android_native_rect_t standard = {10, 20, 330, 200}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &standard)); EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK, mST->updateTexImage()); Rect r = mST->getCurrentCrop(); // crop should be the same as crop (same aspect ratio) assertRectEq(Rect(10, 20, 330, 200), r); // make this wider then desired aspect 239 x 100 (2.39:1) android_native_rect_t wide = {20, 30, 259, 130}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &wide)); EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK, mST->updateTexImage()); r = mST->getCurrentCrop(); // crop should be the same height, but have cropped left and right borders // offset is 30.6 px L+, R- assertRectEq(Rect(51, 30, 228, 130), r); // This image is taller then desired aspect 400 x 300 (4:3) android_native_rect_t narrow = {0, 0, 400, 300}; ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &narrow)); EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); mFW->waitForFrame(); EXPECT_EQ(OK, mST->updateTexImage()); r = mST->getCurrentCrop(); // crop should be the same width, but have cropped top and bottom borders // offset is 37.5 px assertRectEq(Rect(0, 37, 400, 262), r); native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); } TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { class ProducerThread : public Thread { public: ProducerThread(const sp& anw): mANW(anw), mDequeueError(NO_ERROR) { } virtual ~ProducerThread() { } virtual bool threadLoop() { Mutex::Autolock lock(mMutex); ANativeWindowBuffer* anb; if (native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU) != NO_ERROR) { return false; } // Frame 1 if (native_window_dequeue_buffer_and_wait(mANW.get(), &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } // Frame 2 if (native_window_dequeue_buffer_and_wait(mANW.get(), &anb) != NO_ERROR) { return false; } if (anb == NULL) { return false; } if (mANW->queueBuffer(mANW.get(), anb, -1) != NO_ERROR) { return false; } // Frame 3 - error expected mDequeueError = native_window_dequeue_buffer_and_wait(mANW.get(), &anb); return false; } status_t getDequeueError() { Mutex::Autolock lock(mMutex); return mDequeueError; } private: sp mANW; status_t mDequeueError; Mutex mMutex; }; sp pt(new ProducerThread(mANW)); pt->run("ProducerThread"); mFW->waitForFrame(); mFW->waitForFrame(); // Sleep for 100ms to allow the producer thread's dequeueBuffer call to // block waiting for a buffer to become available. usleep(100000); mST->abandon(); pt->requestExitAndWait(); ASSERT_EQ(NO_INIT, reinterpret_cast(pt.get())->getDequeueError()); } TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { int texHeight = 16; ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); GLint maxTextureSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); // make sure it works with small textures mST->setDefaultBufferSize(16, texHeight); EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(16, anb->width); EXPECT_EQ(texHeight, anb->height); EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(NO_ERROR, mST->updateTexImage()); // make sure it works with GL_MAX_TEXTURE_SIZE mST->setDefaultBufferSize(maxTextureSize, texHeight); EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(maxTextureSize, anb->width); EXPECT_EQ(texHeight, anb->height); EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); EXPECT_EQ(NO_ERROR, mST->updateTexImage()); // make sure it fails with GL_MAX_TEXTURE_SIZE+1 mST->setDefaultBufferSize(maxTextureSize+1, texHeight); EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(maxTextureSize+1, anb->width); EXPECT_EQ(texHeight, anb->height); EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1)); ASSERT_NE(NO_ERROR, mST->updateTexImage()); } } // namespace android libs/gui/tests/SurfaceTextureMultiContextGL.h0100644 0000000 0000000 00000005637 13077405420 020426 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_TEXTURE_MULTI_CONTEXT_GL_H #define ANDROID_SURFACE_TEXTURE_MULTI_CONTEXT_GL_H #include "SurfaceTextureGL.h" namespace android { class SurfaceTextureMultiContextGLTest : public SurfaceTextureGLTest { protected: enum { SECOND_TEX_ID = 123 }; enum { THIRD_TEX_ID = 456 }; SurfaceTextureMultiContextGLTest(): mSecondEglContext(EGL_NO_CONTEXT), mThirdEglContext(EGL_NO_CONTEXT) { } virtual void SetUp() { SurfaceTextureGLTest::SetUp(); // Set up the secondary context and texture renderer. mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext); ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mSecondTextureRenderer = new TextureRenderer(SECOND_TEX_ID, mST); ASSERT_NO_FATAL_FAILURE(mSecondTextureRenderer->SetUp()); // Set up the tertiary context and texture renderer. mThirdEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mThirdEglContext); ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mThirdEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); mThirdTextureRenderer = new TextureRenderer(THIRD_TEX_ID, mST); ASSERT_NO_FATAL_FAILURE(mThirdTextureRenderer->SetUp()); // Switch back to the primary context to start the tests. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); } virtual void TearDown() { if (mThirdEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mThirdEglContext); } if (mSecondEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mSecondEglContext); } SurfaceTextureGLTest::TearDown(); } EGLContext mSecondEglContext; sp mSecondTextureRenderer; EGLContext mThirdEglContext; sp mThirdTextureRenderer; }; } #endif libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp0100644 0000000 0000000 00000041074 13077405420 022013 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "SurfaceTextureMultiContextGL_test" //#define LOG_NDEBUG 0 #include "SurfaceTextureMultiContextGL.h" #include "FillBuffer.h" #include namespace android { TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Attempt to latch the texture on the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage()); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Check that the GL texture was deleted. EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceedsAfterProducerDisconnect) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); ASSERT_EQ(OK, mST->detachFromContext()); // Check that the GL texture was deleted. EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Attempt to detach from the primary context. mST->abandon(); ASSERT_EQ(NO_INIT, mST->detachFromContext()); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attempt to detach from the primary context again. ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Make there be no current display. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Attempt to detach from the primary context. ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); } TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Make current context be incorrect. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Attempt to detach from the primary context. ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); } TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attempt to latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage()); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Verify that the texture object was created and bound. GLint texBinding = -1; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); EXPECT_EQ(SECOND_TEX_ID, texBinding); // Try to use the texture from the secondary context. glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 1, 1); mSecondTextureRenderer->drawTexture(); ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsAfterProducerDisconnect) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Verify that the texture object was created and bound. GLint texBinding = -1; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); EXPECT_EQ(SECOND_TEX_ID, texBinding); // Try to use the texture from the secondary context. glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 1, 1); mSecondTextureRenderer->drawTexture(); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsBeforeUpdateTexImage) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Verify that the texture object was created and bound. GLint texBinding = -1; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); EXPECT_EQ(SECOND_TEX_ID, texBinding); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Try to use the texture from the secondary context. glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 1, 1); mSecondTextureRenderer->drawTexture(); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attempt to attach to the secondary context. mST->abandon(); // Attempt to attach to the primary context. ASSERT_EQ(NO_INIT, mST->attachToContext(SECOND_TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Attempt to attach to the primary context. ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttachedBeforeUpdateTexImage) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Attempt to attach to the primary context. ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Make there be no current display. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Attempt to attach with no context current. ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Latch the texture contents on the primary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Detach from the secondary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the tertiary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mThirdEglContext)); ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID)); // Verify that the texture object was created and bound. GLint texBinding = -1; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); EXPECT_EQ(THIRD_TEX_ID, texBinding); // Try to use the texture from the tertiary context. glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 1, 1); mThirdTextureRenderer->drawTexture(); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); } TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwiceBeforeUpdateTexImage) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the secondary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Detach from the secondary context. ASSERT_EQ(OK, mST->detachFromContext()); // Attach to the tertiary context. ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mThirdEglContext)); ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID)); // Verify that the texture object was created and bound. GLint texBinding = -1; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); EXPECT_EQ(THIRD_TEX_ID, texBinding); // Latch the texture contents on the tertiary context. mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // Try to use the texture from the tertiary context. glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 1, 1); mThirdTextureRenderer->drawTexture(); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35)); } TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageSucceedsForBufferConsumedBeforeDetach) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); // produce two frames and consume them both on the primary context ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // produce one more frame ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context and attach to the secondary context ASSERT_EQ(OK, mST->detachFromContext()); ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); // Consume final frame on secondary context mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); } TEST_F(SurfaceTextureMultiContextGLTest, AttachAfterDisplayTerminatedSucceeds) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); // produce two frames and consume them both on the primary context ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); // produce one more frame ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); // Detach from the primary context. ASSERT_EQ(OK, mST->releaseTexImage()); ASSERT_EQ(OK, mST->detachFromContext()); // Terminate and then initialize the display. All contexts, surfaces // and images are invalid at this point. EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); EGLint majorVersion = 0; EGLint minorVersion = 0; EXPECT_TRUE(eglTerminate(display)); EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // The surface is invalid so create it again. EGLint pbufferAttribs[] = { EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE }; mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig, pbufferAttribs); // The second context is invalid so create it again. mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext); ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mSecondEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); // Now attach to and consume final frame on secondary context. ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); mFW->waitForFrame(); ASSERT_EQ(OK, mST->updateTexImage()); } } // namespace android libs/gui/tests/Surface_test.cpp0100644 0000000 0000000 00000022400 13077405420 015617 0ustar000000000 0000000 /* * 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 "DummyConsumer.h" #include #include #include #include #include #include #include #include #include #include namespace android { class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { ProcessState::self()->startThreadPool(); } virtual void SetUp() { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); } virtual void TearDown() { mComposerClient->dispose(); } sp mSurface; sp mComposerClient; sp mSurfaceControl; }; TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { sp anw(mSurface); int result = -123; int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result); EXPECT_EQ(NO_ERROR, err); EXPECT_EQ(1, result); } TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { mSurfaceControl.clear(); sp anw(mSurface); int result = -123; int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result); EXPECT_EQ(NO_ERROR, err); EXPECT_EQ(1, result); } // This test probably doesn't belong here. TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp anw(mSurface); // Verify the screenshot works with no protected buffers. sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp cpuConsumer = new CpuConsumer(consumer, 1); sp sf(ComposerService::getComposerService()); sp display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 64, 64, 0, 0x7fffffff, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); // Set the PROTECTED usage bit and verify that the screenshot fails. Note // that we need to dequeue a buffer in order for it to actually get // allocated in SurfaceFlinger. ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), GRALLOC_USAGE_PROTECTED)); ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); ANativeWindowBuffer* buf = 0; status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf); if (err) { // we could fail if GRALLOC_USAGE_PROTECTED is not supported. // that's okay as long as this is the reason for the failure. // try again without the GRALLOC_USAGE_PROTECTED bit. ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0)); ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), &buf)); return; } ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf, -1)); for (int i = 0; i < 4; i++) { // Loop to make sure SurfaceFlinger has retired a protected buffer. ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(), &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 64, 64, 0, 0x7fffffff, false)); } TEST_F(SurfaceTest, ConcreteTypeIsSurface) { sp anw(mSurface); int result = -123; int err = anw->query(anw.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result); EXPECT_EQ(NO_ERROR, err); EXPECT_EQ(NATIVE_WINDOW_SURFACE, result); } TEST_F(SurfaceTest, QueryConsumerUsage) { const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp c = new BufferItemConsumer(consumer, TEST_USAGE_FLAGS); sp s = new Surface(producer); sp anw(s); int flags = -1; int err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &flags); ASSERT_EQ(NO_ERROR, err); ASSERT_EQ(TEST_USAGE_FLAGS, flags); } TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { const android_dataspace TEST_DATASPACE = HAL_DATASPACE_SRGB; sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp cpuConsumer = new CpuConsumer(consumer, 1); cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE); sp s = new Surface(producer); sp anw(s); android_dataspace dataSpace; int err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, reinterpret_cast(&dataSpace)); ASSERT_EQ(NO_ERROR, err); ASSERT_EQ(TEST_DATASPACE, dataSpace); } TEST_F(SurfaceTest, SettingGenerationNumber) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp cpuConsumer = new CpuConsumer(consumer, 1); sp surface = new Surface(producer); sp window(surface); // Allocate a buffer with a generation number of 0 ANativeWindowBuffer* buffer; int fenceFd; ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU)); ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd)); // Detach the buffer and check its generation number sp graphicBuffer; sp fence; ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence)); ASSERT_EQ(0U, graphicBuffer->getGenerationNumber()); ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1)); buffer = static_cast(graphicBuffer.get()); // This should change the generation number of the GraphicBuffer ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer)); // Check that the new generation number sticks with the buffer ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1)); ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); graphicBuffer = static_cast(buffer); ASSERT_EQ(1U, graphicBuffer->getGenerationNumber()); } TEST_F(SurfaceTest, GetConsumerName) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp dummyConsumer(new DummyConsumer); consumer->consumerConnect(dummyConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp surface = new Surface(producer); sp window(surface); native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); EXPECT_STREQ("TestConsumer", surface->getConsumerName().string()); } TEST_F(SurfaceTest, DynamicSetBufferCount) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp dummyConsumer(new DummyConsumer); consumer->consumerConnect(dummyConsumer, false); consumer->setConsumerName(String8("TestConsumer")); sp surface = new Surface(producer); sp window(surface); ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU)); native_window_set_buffer_count(window.get(), 4); int fence; ANativeWindowBuffer* buffer; ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); native_window_set_buffer_count(window.get(), 3); ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); native_window_set_buffer_count(window.get(), 2); ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); } } libs/gui/tests/TextureRenderer.cpp0100644 0000000 0000000 00000007724 13077405420 016333 0ustar000000000 0000000 /* * Copyright 2013 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 "TextureRenderer.h" #include "GLTest.h" #include #include #include #include namespace android { TextureRenderer::TextureRenderer(GLuint texName, const sp& st) : mTexName(texName), mST(st), mPgm(0), mPositionHandle(-1), mTexSamplerHandle(-1), mTexMatrixHandle(-1) { } void TextureRenderer::SetUp() { const char vsrc[] = "attribute vec4 vPosition;\n" "varying vec2 texCoords;\n" "uniform mat4 texMatrix;\n" "void main() {\n" " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n" " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n" " gl_Position = vPosition;\n" "}\n"; const char fsrc[] = "#extension GL_OES_EGL_image_external : require\n" "precision mediump float;\n" "uniform samplerExternalOES texSampler;\n" "varying vec2 texCoords;\n" "void main() {\n" " gl_FragColor = texture2D(texSampler, texCoords);\n" "}\n"; { SCOPED_TRACE("creating shader program"); ASSERT_NO_FATAL_FAILURE(GLTest::createProgram(vsrc, fsrc, &mPgm)); } mPositionHandle = glGetAttribLocation(mPgm, "vPosition"); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_NE(-1, mPositionHandle); mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler"); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_NE(-1, mTexSamplerHandle); mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix"); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); ASSERT_NE(-1, mTexMatrixHandle); } // drawTexture draws the GLConsumer over the entire GL viewport. void TextureRenderer::drawTexture() { static const GLfloat triangleVertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, }; glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glEnableVertexAttribArray(mPositionHandle); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glUseProgram(mPgm); glUniform1i(mTexSamplerHandle, 0); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as // they're setting the defautls for that target, but when hacking // things to use GL_TEXTURE_2D they are needed to achieve the same // behavior. glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); GLfloat texMatrix[16]; mST->getTransformMatrix(texMatrix); glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } } // namespace android libs/gui/tests/TextureRenderer.h0100644 0000000 0000000 00000002144 13077405420 015767 0ustar000000000 0000000 /* * Copyright 2013 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_TEXTURE_RENDERER_H #define ANDROID_TEXTURE_RENDERER_H #include #include namespace android { class GLConsumer; class TextureRenderer : public RefBase { public: TextureRenderer(GLuint texName, const sp& st); void SetUp(); void drawTexture(); private: GLuint mTexName; sp mST; GLuint mPgm; GLint mPositionHandle; GLint mTexSamplerHandle; GLint mTexMatrixHandle; }; } // namespace android #endif libs/input/0040755 0000000 0000000 00000000000 13077405420 011702 5ustar000000000 0000000 libs/input/Android.mk0100644 0000000 0000000 00000003716 13077405420 013617 0ustar000000000 0000000 # Copyright (C) 2013 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. LOCAL_PATH:= $(call my-dir) # libinput is partially built for the host (used by build time keymap validation tool) # These files are common to host and target builds. commonSources := \ Input.cpp \ InputDevice.cpp \ Keyboard.cpp \ KeyCharacterMap.cpp \ KeyLayoutMap.cpp \ VirtualKeyMap.cpp deviceSources := \ $(commonSources) \ IInputFlinger.cpp \ InputTransport.cpp \ VelocityControl.cpp \ VelocityTracker.cpp hostSources := \ $(commonSources) # For the host # ===================================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(hostSources) LOCAL_MODULE:= libinput LOCAL_MODULE_TAGS := optional include $(BUILD_HOST_STATIC_LIBRARY) # For the device # ===================================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(deviceSources) LOCAL_CLANG := true LOCAL_SANITIZE := integer LOCAL_SHARED_LIBRARIES := \ liblog \ libcutils \ libutils \ libbinder LOCAL_MODULE:= libinput LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) # Include subdirectory makefiles # ============================================================ # If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework # team really wants is to build the stuff defined by this makefile. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif libs/input/IInputFlinger.cpp0100644 0000000 0000000 00000003251 13077405420 015123 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include #include namespace android { class BpInputFlinger : public BpInterface { public: BpInputFlinger(const sp& impl) : BpInterface(impl) { } virtual status_t doSomething() { Parcel data, reply; data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply); return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger"); status_t BnInputFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case DO_SOMETHING_TRANSACTION: { CHECK_INTERFACE(IInputFlinger, data, reply); reply->writeInt32(0); break; } default: return BBinder::onTransact(code, data, reply, flags); } return NO_ERROR; } }; libs/input/Input.cpp0100644 0000000 0000000 00000043361 13077405420 013511 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 #include #include #include #include #ifdef __ANDROID__ #include #endif namespace android { // --- InputEvent --- void InputEvent::initialize(int32_t deviceId, int32_t source) { mDeviceId = deviceId; mSource = source; } void InputEvent::initialize(const InputEvent& from) { mDeviceId = from.mDeviceId; mSource = from.mSource; } // --- KeyEvent --- const char* KeyEvent::getLabel(int32_t keyCode) { return getLabelByKeyCode(keyCode); } int32_t KeyEvent::getKeyCodeFromLabel(const char* label) { return getKeyCodeByLabel(label); } void KeyEvent::initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { InputEvent::initialize(deviceId, source); mAction = action; mFlags = flags; mKeyCode = keyCode; mScanCode = scanCode; mMetaState = metaState; mRepeatCount = repeatCount; mDownTime = downTime; mEventTime = eventTime; } void KeyEvent::initialize(const KeyEvent& from) { InputEvent::initialize(from); mAction = from.mAction; mFlags = from.mFlags; mKeyCode = from.mKeyCode; mScanCode = from.mScanCode; mMetaState = from.mMetaState; mRepeatCount = from.mRepeatCount; mDownTime = from.mDownTime; mEventTime = from.mEventTime; } // --- PointerCoords --- float PointerCoords::getAxisValue(int32_t axis) const { if (axis < 0 || axis > 63 || !BitSet64::hasBit(bits, axis)){ return 0; } return values[BitSet64::getIndexOfBit(bits, axis)]; } status_t PointerCoords::setAxisValue(int32_t axis, float value) { if (axis < 0 || axis > 63) { return NAME_NOT_FOUND; } uint32_t index = BitSet64::getIndexOfBit(bits, axis); if (!BitSet64::hasBit(bits, axis)) { if (value == 0) { return OK; // axes with value 0 do not need to be stored } uint32_t count = BitSet64::count(bits); if (count >= MAX_AXES) { tooManyAxes(axis); return NO_MEMORY; } BitSet64::markBit(bits, axis); for (uint32_t i = count; i > index; i--) { values[i] = values[i - 1]; } } values[index] = value; return OK; } static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { float value = c.getAxisValue(axis); if (value != 0) { c.setAxisValue(axis, value * scaleFactor); } } void PointerCoords::scale(float scaleFactor) { // No need to scale pressure or size since they are normalized. // No need to scale orientation since it is meaningless to do so. scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); } void PointerCoords::applyOffset(float xOffset, float yOffset) { setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); } #ifdef __ANDROID__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); uint32_t count = BitSet64::count(bits); if (count > MAX_AXES) { return BAD_VALUE; } for (uint32_t i = 0; i < count; i++) { values[i] = parcel->readFloat(); } return OK; } status_t PointerCoords::writeToParcel(Parcel* parcel) const { parcel->writeInt64(bits); uint32_t count = BitSet64::count(bits); for (uint32_t i = 0; i < count; i++) { parcel->writeFloat(values[i]); } return OK; } #endif void PointerCoords::tooManyAxes(int axis) { ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " "cannot contain more than %d axis values.", axis, int(MAX_AXES)); } bool PointerCoords::operator==(const PointerCoords& other) const { if (bits != other.bits) { return false; } uint32_t count = BitSet64::count(bits); for (uint32_t i = 0; i < count; i++) { if (values[i] != other.values[i]) { return false; } } return true; } void PointerCoords::copyFrom(const PointerCoords& other) { bits = other.bits; uint32_t count = BitSet64::count(bits); for (uint32_t i = 0; i < count; i++) { values[i] = other.values[i]; } } // --- PointerProperties --- bool PointerProperties::operator==(const PointerProperties& other) const { return id == other.id && toolType == other.toolType; } void PointerProperties::copyFrom(const PointerProperties& other) { id = other.id; toolType = other.toolType; } // --- MotionEvent --- void MotionEvent::initialize( int32_t deviceId, int32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; mActionButton = actionButton; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; mButtonState = buttonState; mXOffset = xOffset; mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); } void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { InputEvent::initialize(other->mDeviceId, other->mSource); mAction = other->mAction; mActionButton = other->mActionButton; mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; mButtonState = other->mButtonState; mXOffset = other->mXOffset; mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; if (keepHistory) { mSampleEventTimes = other->mSampleEventTimes; mSamplePointerCoords = other->mSamplePointerCoords; } else { mSampleEventTimes.clear(); mSampleEventTimes.push(other->getEventTime()); mSamplePointerCoords.clear(); size_t pointerCount = other->getPointerCount(); size_t historySize = other->getHistorySize(); mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() + (historySize * pointerCount), pointerCount); } } void MotionEvent::addSample( int64_t eventTime, const PointerCoords* pointerCoords) { mSampleEventTimes.push(eventTime); mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); } const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { return getRawPointerCoords(pointerIndex)->getAxisValue(axis); } float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: return value + mXOffset; case AMOTION_EVENT_AXIS_Y: return value + mYOffset; } return value; } const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( size_t pointerIndex, size_t historicalIndex) const { return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; } float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: return value + mXOffset; case AMOTION_EVENT_AXIS_Y: return value + mYOffset; } return value; } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { if (mPointerProperties.itemAt(i).id == pointerId) { return i; } } return -1; } void MotionEvent::offsetLocation(float xOffset, float yOffset) { mXOffset += xOffset; mYOffset += yOffset; } void MotionEvent::scale(float scaleFactor) { mXOffset *= scaleFactor; mYOffset *= scaleFactor; mXPrecision *= scaleFactor; mYPrecision *= scaleFactor; size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { mSamplePointerCoords.editItemAt(i).scale(scaleFactor); } } static void transformPoint(const float matrix[9], float x, float y, float *outX, float *outY) { // Apply perspective transform like Skia. float newX = matrix[0] * x + matrix[1] * y + matrix[2]; float newY = matrix[3] * x + matrix[4] * y + matrix[5]; float newZ = matrix[6] * x + matrix[7] * y + matrix[8]; if (newZ) { newZ = 1.0f / newZ; } *outX = newX * newZ; *outY = newY * newZ; } static float transformAngle(const float matrix[9], float angleRadians, float originX, float originY) { // Construct and transform a vector oriented at the specified clockwise angle from vertical. // Coordinate system: down is increasing Y, right is increasing X. float x = sinf(angleRadians); float y = -cosf(angleRadians); transformPoint(matrix, x, y, &x, &y); x -= originX; y -= originY; // Derive the transformed vector's clockwise angle from vertical. float result = atan2f(x, -y); if (result < - M_PI_2) { result += M_PI; } else if (result > M_PI_2) { result -= M_PI; } return result; } void MotionEvent::transform(const float matrix[9]) { // The tricky part of this implementation is to preserve the value of // rawX and rawY. So we apply the transformation to the first point // then derive an appropriate new X/Y offset that will preserve rawX // and rawY for that point. float oldXOffset = mXOffset; float oldYOffset = mYOffset; float newX, newY; float rawX = getRawX(0); float rawY = getRawY(0); transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY); mXOffset = newX - rawX; mYOffset = newY - rawY; // Determine how the origin is transformed by the matrix so that we // can transform orientation vectors. float originX, originY; transformPoint(matrix, 0, 0, &originX, &originY); // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { PointerCoords& c = mSamplePointerCoords.editItemAt(i); float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; transformPoint(matrix, x, y, &x, &y); c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset); c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset); float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation, originX, originY)); } } #ifdef __ANDROID__ status_t MotionEvent::readFromParcel(Parcel* parcel) { size_t pointerCount = parcel->readInt32(); size_t sampleCount = parcel->readInt32(); if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0 || sampleCount > MAX_SAMPLES) { return BAD_VALUE; } mDeviceId = parcel->readInt32(); mSource = parcel->readInt32(); mAction = parcel->readInt32(); mActionButton = parcel->readInt32(); mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); mButtonState = parcel->readInt32(); mXOffset = parcel->readFloat(); mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); mPointerProperties.setCapacity(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.setCapacity(sampleCount); mSamplePointerCoords.clear(); mSamplePointerCoords.setCapacity(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { mPointerProperties.push(); PointerProperties& properties = mPointerProperties.editTop(); properties.id = parcel->readInt32(); properties.toolType = parcel->readInt32(); } while (sampleCount > 0) { sampleCount--; mSampleEventTimes.push(parcel->readInt64()); for (size_t i = 0; i < pointerCount; i++) { mSamplePointerCoords.push(); status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); if (status) { return status; } } } return OK; } status_t MotionEvent::writeToParcel(Parcel* parcel) const { size_t pointerCount = mPointerProperties.size(); size_t sampleCount = mSampleEventTimes.size(); parcel->writeInt32(pointerCount); parcel->writeInt32(sampleCount); parcel->writeInt32(mDeviceId); parcel->writeInt32(mSource); parcel->writeInt32(mAction); parcel->writeInt32(mActionButton); parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); parcel->writeInt32(mButtonState); parcel->writeFloat(mXOffset); parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { const PointerProperties& properties = mPointerProperties.itemAt(i); parcel->writeInt32(properties.id); parcel->writeInt32(properties.toolType); } const PointerCoords* pc = mSamplePointerCoords.array(); for (size_t h = 0; h < sampleCount; h++) { parcel->writeInt64(mSampleEventTimes.itemAt(h)); for (size_t i = 0; i < pointerCount; i++) { status_t status = (pc++)->writeToParcel(parcel); if (status) { return status; } } } return OK; } #endif bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { if (source & AINPUT_SOURCE_CLASS_POINTER) { // Specifically excludes HOVER_MOVE and SCROLL. switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_OUTSIDE: return true; } } return false; } const char* MotionEvent::getLabel(int32_t axis) { return getAxisLabel(axis); } int32_t MotionEvent::getAxisFromLabel(const char* label) { return getAxisByLabel(label); } // --- PooledInputEventFactory --- PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : mMaxPoolSize(maxPoolSize) { } PooledInputEventFactory::~PooledInputEventFactory() { for (size_t i = 0; i < mKeyEventPool.size(); i++) { delete mKeyEventPool.itemAt(i); } for (size_t i = 0; i < mMotionEventPool.size(); i++) { delete mMotionEventPool.itemAt(i); } } KeyEvent* PooledInputEventFactory::createKeyEvent() { if (!mKeyEventPool.isEmpty()) { KeyEvent* event = mKeyEventPool.top(); mKeyEventPool.pop(); return event; } return new KeyEvent(); } MotionEvent* PooledInputEventFactory::createMotionEvent() { if (!mMotionEventPool.isEmpty()) { MotionEvent* event = mMotionEventPool.top(); mMotionEventPool.pop(); return event; } return new MotionEvent(); } void PooledInputEventFactory::recycle(InputEvent* event) { switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: if (mKeyEventPool.size() < mMaxPoolSize) { mKeyEventPool.push(static_cast(event)); return; } break; case AINPUT_EVENT_TYPE_MOTION: if (mMotionEventPool.size() < mMaxPoolSize) { mMotionEventPool.push(static_cast(event)); return; } break; } delete event; } } // namespace android libs/input/InputDevice.cpp0100644 0000000 0000000 00000013631 13077405420 014626 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "InputDevice" #include #include #include #include namespace android { static const char* CONFIGURATION_FILE_DIR[] = { "idc/", "keylayout/", "keychars/", }; static const char* CONFIGURATION_FILE_EXTENSION[] = { ".idc", ".kl", ".kcm", }; static bool isValidNameChar(char ch) { return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); } static void appendInputDeviceConfigurationFileRelativePath(String8& path, const String8& name, InputDeviceConfigurationFileType type) { path.append(CONFIGURATION_FILE_DIR[type]); for (size_t i = 0; i < name.length(); i++) { char ch = name[i]; if (!isValidNameChar(ch)) { ch = '_'; } path.append(&ch, 1); } path.append(CONFIGURATION_FILE_EXTENSION[type]); } String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type) { if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { if (deviceIdentifier.version != 0) { // Try vendor product version. String8 versionPath(getInputDeviceConfigurationFilePathByName( String8::format("Vendor_%04x_Product_%04x_Version_%04x", deviceIdentifier.vendor, deviceIdentifier.product, deviceIdentifier.version), type)); if (!versionPath.isEmpty()) { return versionPath; } } // Try vendor product. String8 productPath(getInputDeviceConfigurationFilePathByName( String8::format("Vendor_%04x_Product_%04x", deviceIdentifier.vendor, deviceIdentifier.product), type)); if (!productPath.isEmpty()) { return productPath; } } // Try device name. return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); } String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type) { // Search system repository. String8 path; path.setTo(getenv("ANDROID_ROOT")); path.append("/usr/"); appendInputDeviceConfigurationFileRelativePath(path, name, type); #if DEBUG_PROBE ALOGD("Probing for system provided input device configuration file: path='%s'", path.string()); #endif if (!access(path.string(), R_OK)) { #if DEBUG_PROBE ALOGD("Found"); #endif return path; } // Search user repository. // TODO Should only look here if not in safe mode. path.setTo(getenv("ANDROID_DATA")); path.append("/system/devices/"); appendInputDeviceConfigurationFileRelativePath(path, name, type); #if DEBUG_PROBE ALOGD("Probing for system user input device configuration file: path='%s'", path.string()); #endif if (!access(path.string(), R_OK)) { #if DEBUG_PROBE ALOGD("Found"); #endif return path; } // Not found. #if DEBUG_PROBE ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", name.string(), type); #endif return String8(); } // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), mHasMic(other.mHasMic), mSources(other.mSources), mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) { } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, bool hasMic) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; mHasMic = hasMic; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; mHasButtonUnderPad = false; mMotionRanges.clear(); } const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { size_t numRanges = mMotionRanges.size(); for (size_t i = 0; i < numRanges; i++) { const MotionRange& range = mMotionRanges.itemAt(i); if (range.axis == axis && range.source == source) { return ⦥ } } return NULL; } void InputDeviceInfo::addSource(uint32_t source) { mSources |= source; } void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz, float resolution) { MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; mMotionRanges.add(range); } void InputDeviceInfo::addMotionRange(const MotionRange& range) { mMotionRanges.add(range); } } // namespace android libs/input/InputTransport.cpp0100644 0000000 0000000 00000102205 13077405420 015417 0ustar000000000 0000000 // // Copyright 2010 The Android Open Source Project // // Provides a shared memory transport for input events. // #define LOG_TAG "InputTransport" //#define LOG_NDEBUG 0 // Log debug messages about channel messages (send message, receive message) #define DEBUG_CHANNEL_MESSAGES 0 // Log debug messages whenever InputChannel objects are created/destroyed #define DEBUG_CHANNEL_LIFECYCLE 0 // Log debug messages about transport actions #define DEBUG_TRANSPORT_ACTIONS 0 // Log debug messages about touch event resampling #define DEBUG_RESAMPLING 0 #include #include #include #include #include #include #include #include #include #include namespace android { // Socket buffer size. The default is typically about 128KB, which is much larger than // we really need. So we make it smaller. It just needs to be big enough to hold // a few dozen large multi-finger motion events in the case where an application gets // behind processing touches. static const size_t SOCKET_BUFFER_SIZE = 32 * 1024; // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; // Latency added during resampling. A few milliseconds doesn't hurt much but // reduces the impact of mispredicted touch positions. static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; // Minimum time difference between consecutive samples before attempting to resample. static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; // Maximum time difference between consecutive samples before attempting to resample // by extrapolation. static const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS; // Maximum time to predict forward from the last known state, to avoid predicting too // far into the future. This time is further bounded by 50% of the last time delta. static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; template inline static T min(const T& a, const T& b) { return a < b ? a : b; } inline static float lerp(float a, float b, float alpha) { return a + alpha * (b - a); } // --- InputMessage --- bool InputMessage::isValid(size_t actualSize) const { if (size() == actualSize) { switch (header.type) { case TYPE_KEY: return true; case TYPE_MOTION: return body.motion.pointerCount > 0 && body.motion.pointerCount <= MAX_POINTERS; case TYPE_FINISHED: return true; } } return false; } size_t InputMessage::size() const { switch (header.type) { case TYPE_KEY: return sizeof(Header) + body.key.size(); case TYPE_MOTION: return sizeof(Header) + body.motion.size(); case TYPE_FINISHED: return sizeof(Header) + body.finished.size(); } return sizeof(Header); } // --- InputChannel --- InputChannel::InputChannel(const String8& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", mName.string(), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " "non-blocking. errno=%d", mName.string(), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel destroyed: name='%s', fd=%d", mName.string(), mFd); #endif ::close(mFd); } status_t InputChannel::openInputChannelPair(const String8& name, sp& outServerChannel, sp& outClientChannel) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", name.string(), errno); outServerChannel.clear(); outClientChannel.clear(); return result; } int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); String8 serverChannelName = name; serverChannelName.append(" (server)"); outServerChannel = new InputChannel(serverChannelName, sockets[0]); String8 clientChannelName = name; clientChannelName.append(" (client)"); outClientChannel = new InputChannel(clientChannelName, sockets[1]); return OK; } status_t InputChannel::sendMessage(const InputMessage* msg) { size_t msgLength = msg->size(); ssize_t nWrite; do { nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), msg->header.type, error); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; } if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) { return DEAD_OBJECT; } return -error; } if (size_t(nWrite) != msgLength) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", mName.string(), msg->header.type); #endif return DEAD_OBJECT; } #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); #endif return OK; } status_t InputChannel::receiveMessage(InputMessage* msg) { ssize_t nRead; do { nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); } while (nRead == -1 && errno == EINTR); if (nRead < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; } if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) { return DEAD_OBJECT; } return -error; } if (nRead == 0) { // check for EOF #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); #endif return DEAD_OBJECT; } if (!msg->isValid(nRead)) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ received invalid message", mName.string()); #endif return BAD_VALUE; } #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); #endif return OK; } sp InputChannel::dup() const { int fd = ::dup(getFd()); return fd >= 0 ? new InputChannel(getName(), fd) : NULL; } // --- InputPublisher --- InputPublisher::InputPublisher(const sp& channel) : mChannel(channel) { } InputPublisher::~InputPublisher() { } status_t InputPublisher::publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," "downTime=%lld, eventTime=%lld", mChannel->getName().string(), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); #endif if (!seq) { ALOGE("Attempted to publish a key event with sequence number 0."); return BAD_VALUE; } InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; msg.body.key.seq = seq; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; msg.body.key.scanCode = scanCode; msg.body.key.metaState = metaState; msg.body.key.repeatCount = repeatCount; msg.body.key.downTime = downTime; msg.body.key.eventTime = eventTime; return mChannel->sendMessage(&msg); } status_t InputPublisher::publishMotionEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, " "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " "pointerCount=%" PRIu32, mChannel->getName().string(), seq, deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif if (!seq) { ALOGE("Attempted to publish a motion event with sequence number 0."); return BAD_VALUE; } if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".", mChannel->getName().string(), pointerCount); return BAD_VALUE; } InputMessage msg; msg.header.type = InputMessage::TYPE_MOTION; msg.body.motion.seq = seq; msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.action = action; msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; msg.body.motion.buttonState = buttonState; msg.body.motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; for (uint32_t i = 0; i < pointerCount; i++) { msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } return mChannel->sendMessage(&msg); } status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().string()); #endif InputMessage msg; status_t result = mChannel->receiveMessage(&msg); if (result) { *outSeq = 0; *outHandled = false; return result; } if (msg.header.type != InputMessage::TYPE_FINISHED) { ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", mChannel->getName().string(), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; *outHandled = msg.body.finished.handled; return OK; } // --- InputConsumer --- InputConsumer::InputConsumer(const sp& channel) : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) { } InputConsumer::~InputConsumer() { } bool InputConsumer::isTouchResamplingEnabled() { char value[PROPERTY_VALUE_MAX]; int length = property_get("ro.input.noresample", value, NULL); if (length > 0) { if (!strcmp("1", value)) { return false; } if (strcmp("0", value)) { ALOGD("Unrecognized property value for 'ro.input.noresample'. " "Use '1' or '0'."); } } return true; } status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); #endif *outSeq = 0; *outEvent = NULL; // Fetch the next input message. // Loop until an event can be returned or no additional events are received. while (!*outEvent) { if (mMsgDeferred) { // mMsg contains a valid input message from the previous call to consume // that has not yet been processed. mMsgDeferred = false; } else { // Receive a fresh message. status_t result = mChannel->receiveMessage(&mMsg); if (result) { // Consume the next batched event unless batches are being held for later. if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent); if (*outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", mChannel->getName().string(), *outSeq); #endif break; } } return result; } } switch (mMsg.header.type) { case InputMessage::TYPE_KEY: { KeyEvent* keyEvent = factory->createKeyEvent(); if (!keyEvent) return NO_MEMORY; initializeKeyEvent(keyEvent, &mMsg); *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", mChannel->getName().string(), *outSeq); #endif break; } case AINPUT_EVENT_TYPE_MOTION: { ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source); if (batchIndex >= 0) { Batch& batch = mBatches.editItemAt(batchIndex); if (canAddSample(batch, &mMsg)) { batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ appended to batch event", mChannel->getName().string()); #endif break; } else { // We cannot append to the batch in progress, so we need to consume // the previous batch right now and defer the new message until later. mMsgDeferred = true; status_t result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent); mBatches.removeAt(batchIndex); if (result) { return result; } #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event and " "deferred current event, seq=%u", mChannel->getName().string(), *outSeq); #endif break; } } // Start a new batch if needed. if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) { mBatches.push(); Batch& batch = mBatches.editTop(); batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ started batch event", mChannel->getName().string()); #endif break; } MotionEvent* motionEvent = factory->createMotionEvent(); if (! motionEvent) return NO_MEMORY; updateTouchState(&mMsg); initializeMotionEvent(motionEvent, &mMsg); *outSeq = mMsg.body.motion.seq; *outEvent = motionEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", mChannel->getName().string(), *outSeq); #endif break; } default: ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", mChannel->getName().string(), mMsg.header.type); return UNKNOWN_ERROR; } } return OK; } status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { status_t result; for (size_t i = mBatches.size(); i > 0; ) { i--; Batch& batch = mBatches.editItemAt(i); if (frameTime < 0) { result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent); mBatches.removeAt(i); return result; } nsecs_t sampleTime = frameTime; if (mResampleTouch) { sampleTime -= RESAMPLE_LATENCY; } ssize_t split = findSampleNoLaterThan(batch, sampleTime); if (split < 0) { continue; } result = consumeSamples(factory, batch, split + 1, outSeq, outEvent); const InputMessage* next; if (batch.samples.isEmpty()) { mBatches.removeAt(i); next = NULL; } else { next = &batch.samples.itemAt(0); } if (!result && mResampleTouch) { resampleTouchState(sampleTime, static_cast(*outEvent), next); } return result; } return WOULD_BLOCK; } status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) { MotionEvent* motionEvent = factory->createMotionEvent(); if (! motionEvent) return NO_MEMORY; uint32_t chain = 0; for (size_t i = 0; i < count; i++) { InputMessage& msg = batch.samples.editItemAt(i); updateTouchState(&msg); if (i) { SeqChain seqChain; seqChain.seq = msg.body.motion.seq; seqChain.chain = chain; mSeqChains.push(seqChain); addSample(motionEvent, &msg); } else { initializeMotionEvent(motionEvent, &msg); } chain = msg.body.motion.seq; } batch.samples.removeItemsAt(0, count); *outSeq = chain; *outEvent = motionEvent; return OK; } void InputConsumer::updateTouchState(InputMessage* msg) { if (!mResampleTouch || !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) { return; } int32_t deviceId = msg->body.motion.deviceId; int32_t source = msg->body.motion.source; nsecs_t eventTime = msg->body.motion.eventTime; // Update the touch state history to incorporate the new input message. // If the message is in the past relative to the most recently produced resampled // touch, then use the resampled time and coordinates instead. switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: { ssize_t index = findTouchState(deviceId, source); if (index < 0) { mTouchStates.push(); index = mTouchStates.size() - 1; } TouchState& touchState = mTouchStates.editItemAt(index); touchState.initialize(deviceId, source); touchState.addHistory(msg); break; } case AMOTION_EVENT_ACTION_MOVE: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); touchState.addHistory(msg); if (eventTime < touchState.lastResample.eventTime) { rewriteMessage(touchState, msg); } else { touchState.lastResample.idBits.clear(); } } break; } case AMOTION_EVENT_ACTION_POINTER_DOWN: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); rewriteMessage(touchState, msg); } break; } case AMOTION_EVENT_ACTION_POINTER_UP: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); rewriteMessage(touchState, msg); touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); } break; } case AMOTION_EVENT_ACTION_SCROLL: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { const TouchState& touchState = mTouchStates.itemAt(index); rewriteMessage(touchState, msg); } break; } case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { const TouchState& touchState = mTouchStates.itemAt(index); rewriteMessage(touchState, msg); mTouchStates.removeAt(index); } break; } } } void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) { for (uint32_t i = 0; i < msg->body.motion.pointerCount; i++) { uint32_t id = msg->body.motion.pointers[i].properties.id; if (state.lastResample.idBits.hasBit(id)) { PointerCoords& msgCoords = msg->body.motion.pointers[i].coords; const PointerCoords& resampleCoords = state.lastResample.getPointerById(id); #if DEBUG_RESAMPLING ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X), resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y), msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X), msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y)); #endif msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX()); msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY()); } } } void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, const InputMessage* next) { if (!mResampleTouch || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER) || event->getAction() != AMOTION_EVENT_ACTION_MOVE) { return; } ssize_t index = findTouchState(event->getDeviceId(), event->getSource()); if (index < 0) { #if DEBUG_RESAMPLING ALOGD("Not resampled, no touch state for device."); #endif return; } TouchState& touchState = mTouchStates.editItemAt(index); if (touchState.historySize < 1) { #if DEBUG_RESAMPLING ALOGD("Not resampled, no history for device."); #endif return; } // Ensure that the current sample has all of the pointers that need to be reported. const History* current = touchState.getHistory(0); size_t pointerCount = event->getPointerCount(); for (size_t i = 0; i < pointerCount; i++) { uint32_t id = event->getPointerId(i); if (!current->idBits.hasBit(id)) { #if DEBUG_RESAMPLING ALOGD("Not resampled, missing id %d", id); #endif return; } } // Find the data to use for resampling. const History* other; History future; float alpha; if (next) { // Interpolate between current sample and future sample. // So current->eventTime <= sampleTime <= future.eventTime. future.initializeFrom(next); other = &future; nsecs_t delta = future.eventTime - current->eventTime; if (delta < RESAMPLE_MIN_DELTA) { #if DEBUG_RESAMPLING ALOGD("Not resampled, delta time is too small: %lld ns.", delta); #endif return; } alpha = float(sampleTime - current->eventTime) / delta; } else if (touchState.historySize >= 2) { // Extrapolate future sample using current sample and past sample. // So other->eventTime <= current->eventTime <= sampleTime. other = touchState.getHistory(1); nsecs_t delta = current->eventTime - other->eventTime; if (delta < RESAMPLE_MIN_DELTA) { #if DEBUG_RESAMPLING ALOGD("Not resampled, delta time is too small: %lld ns.", delta); #endif return; } else if (delta > RESAMPLE_MAX_DELTA) { #if DEBUG_RESAMPLING ALOGD("Not resampled, delta time is too large: %lld ns.", delta); #endif return; } nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION); if (sampleTime > maxPredict) { #if DEBUG_RESAMPLING ALOGD("Sample time is too far in the future, adjusting prediction " "from %lld to %lld ns.", sampleTime - current->eventTime, maxPredict - current->eventTime); #endif sampleTime = maxPredict; } alpha = float(current->eventTime - sampleTime) / delta; } else { #if DEBUG_RESAMPLING ALOGD("Not resampled, insufficient data."); #endif return; } // Resample touch coordinates. touchState.lastResample.eventTime = sampleTime; touchState.lastResample.idBits.clear(); for (size_t i = 0; i < pointerCount; i++) { uint32_t id = event->getPointerId(i); touchState.lastResample.idToIndex[id] = i; touchState.lastResample.idBits.markBit(id); PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; const PointerCoords& currentCoords = current->getPointerById(id); if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) { const PointerCoords& otherCoords = other->getPointerById(id); resampledCoords.copyFrom(currentCoords); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, lerp(currentCoords.getX(), otherCoords.getX(), alpha)); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, lerp(currentCoords.getY(), otherCoords.getY(), alpha)); #if DEBUG_RESAMPLING ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " "other (%0.3f, %0.3f), alpha %0.3f", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha); #endif } else { resampledCoords.copyFrom(currentCoords); #if DEBUG_RESAMPLING ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY()); #endif } } event->addSample(sampleTime, touchState.lastResample.pointers); } bool InputConsumer::shouldResampleTool(int32_t toolType) { return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", mChannel->getName().string(), seq, handled ? "true" : "false"); #endif if (!seq) { ALOGE("Attempted to send a finished signal with sequence number 0."); return BAD_VALUE; } // Send finished signals for the batch sequence chain first. size_t seqChainCount = mSeqChains.size(); if (seqChainCount) { uint32_t currentSeq = seq; uint32_t chainSeqs[seqChainCount]; size_t chainIndex = 0; for (size_t i = seqChainCount; i > 0; ) { i--; const SeqChain& seqChain = mSeqChains.itemAt(i); if (seqChain.seq == currentSeq) { currentSeq = seqChain.chain; chainSeqs[chainIndex++] = currentSeq; mSeqChains.removeAt(i); } } status_t status = OK; while (!status && chainIndex > 0) { chainIndex--; status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); } if (status) { // An error occurred so at least one signal was not sent, reconstruct the chain. do { SeqChain seqChain; seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq; seqChain.chain = chainSeqs[chainIndex]; mSeqChains.push(seqChain); if (chainIndex != 0) { chainIndex--; } } while (chainIndex > 0); return status; } } // Send finished signal for the last message in the batch. return sendUnchainedFinishedSignal(seq, handled); } status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) { InputMessage msg; msg.header.type = InputMessage::TYPE_FINISHED; msg.body.finished.seq = seq; msg.body.finished.handled = handled; return mChannel->sendMessage(&msg); } bool InputConsumer::hasDeferredEvent() const { return mMsgDeferred; } bool InputConsumer::hasPendingBatch() const { return !mBatches.isEmpty(); } ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { for (size_t i = 0; i < mBatches.size(); i++) { const Batch& batch = mBatches.itemAt(i); const InputMessage& head = batch.samples.itemAt(0); if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) { return i; } } return -1; } ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { for (size_t i = 0; i < mTouchStates.size(); i++) { const TouchState& touchState = mTouchStates.itemAt(i); if (touchState.deviceId == deviceId && touchState.source == source) { return i; } } return -1; } void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { event->initialize( msg->body.key.deviceId, msg->body.key.source, msg->body.key.action, msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime, msg->body.key.eventTime); } void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { uint32_t pointerCount = msg->body.motion.pointerCount; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties); pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } event->initialize( msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.action, msg->body.motion.actionButton, msg->body.motion.flags, msg->body.motion.edgeFlags, msg->body.motion.metaState, msg->body.motion.buttonState, msg->body.motion.xOffset, msg->body.motion.yOffset, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { uint32_t pointerCount = msg->body.motion.pointerCount; PointerCoords pointerCoords[pointerCount]; for (uint32_t i = 0; i < pointerCount; i++) { pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } event->setMetaState(event->getMetaState() | msg->body.motion.metaState); event->addSample(msg->body.motion.eventTime, pointerCoords); } bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) { const InputMessage& head = batch.samples.itemAt(0); uint32_t pointerCount = msg->body.motion.pointerCount; if (head.body.motion.pointerCount != pointerCount || head.body.motion.action != msg->body.motion.action) { return false; } for (size_t i = 0; i < pointerCount; i++) { if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) { return false; } } return true; } ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) { size_t numSamples = batch.samples.size(); size_t index = 0; while (index < numSamples && batch.samples.itemAt(index).body.motion.eventTime <= time) { index += 1; } return ssize_t(index) - 1; } } // namespace android libs/input/KeyCharacterMap.cpp0100644 0000000 0000000 00000127457 13077405420 015426 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ #define LOG_TAG "KeyCharacterMap" #include #include #ifdef __ANDROID__ #include #endif #include #include #include #include #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 // Enables debug output for mapping. #define DEBUG_MAPPING 0 namespace android { static const char* WHITESPACE = " \t\r"; static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; struct Modifier { const char* label; int32_t metaState; }; static const Modifier modifiers[] = { { "shift", AMETA_SHIFT_ON }, { "lshift", AMETA_SHIFT_LEFT_ON }, { "rshift", AMETA_SHIFT_RIGHT_ON }, { "alt", AMETA_ALT_ON }, { "lalt", AMETA_ALT_LEFT_ON }, { "ralt", AMETA_ALT_RIGHT_ON }, { "ctrl", AMETA_CTRL_ON }, { "lctrl", AMETA_CTRL_LEFT_ON }, { "rctrl", AMETA_CTRL_RIGHT_ON }, { "meta", AMETA_META_ON }, { "lmeta", AMETA_META_LEFT_ON }, { "rmeta", AMETA_META_RIGHT_ON }, { "sym", AMETA_SYM_ON }, { "fn", AMETA_FUNCTION_ON }, { "capslock", AMETA_CAPS_LOCK_ON }, { "numlock", AMETA_NUM_LOCK_ON }, { "scrolllock", AMETA_SCROLL_LOCK_ON }, }; #if DEBUG_MAPPING static String8 toString(const char16_t* chars, size_t numChars) { String8 result; for (size_t i = 0; i < numChars; i++) { result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); } return result; } #endif // --- KeyCharacterMap --- sp KeyCharacterMap::sEmpty = new KeyCharacterMap(); KeyCharacterMap::KeyCharacterMap() : mType(KEYBOARD_TYPE_UNKNOWN) { } KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), mKeysByUsageCode(other.mKeysByUsageCode) { for (size_t i = 0; i < other.mKeys.size(); i++) { mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); } } KeyCharacterMap::~KeyCharacterMap() { for (size_t i = 0; i < mKeys.size(); i++) { Key* key = mKeys.editValueAt(i); delete key; } } status_t KeyCharacterMap::load(const String8& filename, Format format, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening key character map file %s.", status, filename.string()); } else { status = load(tokenizer, format, outMap); delete tokenizer; } return status; } status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, Format format, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); if (status) { ALOGE("Error %d opening key character map.", status); } else { status = load(tokenizer, format, outMap); delete tokenizer; } return status; } status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format, sp* outMap) { status_t status = OK; sp map = new KeyCharacterMap(); if (!map.get()) { ALOGE("Error allocating key character map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map.get(), tokenizer, format); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { *outMap = map; } } return status; } sp KeyCharacterMap::combine(const sp& base, const sp& overlay) { if (overlay == NULL) { return base; } if (base == NULL) { return overlay; } sp map = new KeyCharacterMap(*base.get()); for (size_t i = 0; i < overlay->mKeys.size(); i++) { int32_t keyCode = overlay->mKeys.keyAt(i); Key* key = overlay->mKeys.valueAt(i); ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); if (oldIndex >= 0) { delete map->mKeys.valueAt(oldIndex); map->mKeys.editValueAt(oldIndex) = new Key(*key); } else { map->mKeys.add(keyCode, new Key(*key)); } } for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), overlay->mKeysByScanCode.valueAt(i)); } for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), overlay->mKeysByUsageCode.valueAt(i)); } return map; } sp KeyCharacterMap::empty() { return sEmpty; } int32_t KeyCharacterMap::getKeyboardType() const { return mType; } char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { result = key->label; } #if DEBUG_MAPPING ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); #endif return result; } char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { result = key->number; } #if DEBUG_MAPPING ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); #endif return result; } char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { char16_t result = 0; const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { result = behavior->character; } #if DEBUG_MAPPING ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); #endif return result; } bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, FallbackAction* outFallbackAction) const { outFallbackAction->keyCode = 0; outFallbackAction->metaState = 0; bool result = false; const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { if (behavior->fallbackKeyCode) { outFallbackAction->keyCode = behavior->fallbackKeyCode; outFallbackAction->metaState = metaState & ~behavior->metaState; result = true; } } #if DEBUG_MAPPING ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " "fallback keyCode=%d, fallback metaState=0x%08x.", keyCode, metaState, result ? "true" : "false", outFallbackAction->keyCode, outFallbackAction->metaState); #endif return result; } char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, int32_t metaState) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. // However, if we find a perfect meta state match for one behavior then use that one. for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { if (behavior->character) { for (size_t i = 0; i < numChars; i++) { if (behavior->character == chars[i]) { result = behavior->character; if ((behavior->metaState & metaState) == behavior->metaState) { goto ExactMatch; } break; } } } } ExactMatch: ; } #if DEBUG_MAPPING ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", keyCode, toString(chars, numChars).string(), metaState, result); #endif return result; } bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector& outEvents) const { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); for (size_t i = 0; i < numChars; i++) { int32_t keyCode, metaState; char16_t ch = chars[i]; if (!findKey(ch, &keyCode, &metaState)) { #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", deviceId, toString(chars, numChars).string(), ch); #endif return false; } int32_t currentMetaState = 0; addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); } #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); } #endif return true; } status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { if (usageCode) { ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); if (index >= 0) { *outKeyCode = mKeysByUsageCode.valueAt(index); #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", scanCode, usageCode, *outKeyCode); #endif return OK; } } if (scanCode) { ssize_t index = mKeysByScanCode.indexOfKey(scanCode); if (index >= 0) { *outKeyCode = mKeysByScanCode.valueAt(index); #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", scanCode, usageCode, *outKeyCode); #endif return OK; } } #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); #endif *outKeyCode = AKEYCODE_UNKNOWN; return NAME_NOT_FOUND; } void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState, int32_t *outKeyCode, int32_t *outMetaState) const { *outKeyCode = keyCode; *outMetaState = metaState; const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { if (behavior->replacementKeyCode) { *outKeyCode = behavior->replacementKeyCode; int32_t newMetaState = metaState & ~behavior->metaState; // Reset dependent meta states. if (behavior->metaState & AMETA_ALT_ON) { newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); } if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { newMetaState &= ~AMETA_ALT_ON; } if (behavior->metaState & AMETA_CTRL_ON) { newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); } if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { newMetaState &= ~AMETA_CTRL_ON; } if (behavior->metaState & AMETA_SHIFT_ON) { newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON); } if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { newMetaState &= ~AMETA_SHIFT_ON; } // ... and put universal bits back if needed *outMetaState = normalizeMetaState(newMetaState); } } #if DEBUG_MAPPING ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ " "replacement keyCode=%d, replacement metaState=0x%08x.", keyCode, metaState, *outKeyCode, *outMetaState); #endif } bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { ssize_t index = mKeys.indexOfKey(keyCode); if (index >= 0) { *outKey = mKeys.valueAt(index); return true; } return false; } bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, const Key** outKey, const Behavior** outBehavior) const { const Key* key; if (getKey(keyCode, &key)) { const Behavior* behavior = key->firstBehavior; while (behavior) { if (matchesMetaState(metaState, behavior->metaState)) { *outKey = key; *outBehavior = behavior; return true; } behavior = behavior->next; } } return false; } bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { // Behavior must have at least the set of meta states specified. // And if the key event has CTRL, ALT or META then the behavior must exactly // match those, taking into account that a behavior can specify that it handles // one, both or either of a left/right modifier pair. if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { const int32_t EXACT_META_STATES = AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; if (behaviorMetaState & AMETA_CTRL_ON) { unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_CTRL_ON; } if (behaviorMetaState & AMETA_ALT_ON) { unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_ALT_ON; } if (behaviorMetaState & AMETA_META_ON) { unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_META_ON; } return !unmatchedMetaState; } return false; } bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { if (!ch) { return false; } for (size_t i = 0; i < mKeys.size(); i++) { const Key* key = mKeys.valueAt(i); // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. const Behavior* found = NULL; for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { if (behavior->character == ch) { found = behavior; } } if (found) { *outKeyCode = mKeys.keyAt(i); *outMetaState = found->metaState; return true; } } return false; } void KeyCharacterMap::addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { outEvents.push(); KeyEvent& event = outEvents.editTop(); event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState, 0, time, time); } void KeyCharacterMap::addMetaKeys(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t* currentMetaState) { // Add and remove meta keys symmetrically. if (down) { addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, AMETA_SHIFT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, AMETA_ALT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, AMETA_CTRL_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, AMETA_META_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); } else { addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, AMETA_META_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, AMETA_CTRL_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, AMETA_ALT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, AMETA_SHIFT_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); } } bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState) { if ((metaState & keyMetaState) == keyMetaState) { *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); return true; } return false; } void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t leftKeyCode, int32_t leftKeyMetaState, int32_t rightKeyCode, int32_t rightKeyMetaState, int32_t eitherKeyMetaState, int32_t* currentMetaState) { bool specific = false; specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, leftKeyCode, leftKeyMetaState, currentMetaState); specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, rightKeyCode, rightKeyMetaState, currentMetaState); if (!specific) { addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, leftKeyCode, eitherKeyMetaState, currentMetaState); } } void KeyCharacterMap::addLockedMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState) { if ((metaState & keyMetaState) == keyMetaState) { *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); } } #ifdef __ANDROID__ sp KeyCharacterMap::readFromParcel(Parcel* parcel) { sp map = new KeyCharacterMap(); map->mType = parcel->readInt32(); size_t numKeys = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } if (numKeys > MAX_KEYS) { ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS); return NULL; } for (size_t i = 0; i < numKeys; i++) { int32_t keyCode = parcel->readInt32(); char16_t label = parcel->readInt32(); char16_t number = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } Key* key = new Key(); key->label = label; key->number = number; map->mKeys.add(keyCode, key); Behavior* lastBehavior = NULL; while (parcel->readInt32()) { int32_t metaState = parcel->readInt32(); char16_t character = parcel->readInt32(); int32_t fallbackKeyCode = parcel->readInt32(); int32_t replacementKeyCode = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } Behavior* behavior = new Behavior(); behavior->metaState = metaState; behavior->character = character; behavior->fallbackKeyCode = fallbackKeyCode; behavior->replacementKeyCode = replacementKeyCode; if (lastBehavior) { lastBehavior->next = behavior; } else { key->firstBehavior = behavior; } lastBehavior = behavior; } if (parcel->errorCheck()) { return NULL; } } return map; } void KeyCharacterMap::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mType); size_t numKeys = mKeys.size(); parcel->writeInt32(numKeys); for (size_t i = 0; i < numKeys; i++) { int32_t keyCode = mKeys.keyAt(i); const Key* key = mKeys.valueAt(i); parcel->writeInt32(keyCode); parcel->writeInt32(key->label); parcel->writeInt32(key->number); for (const Behavior* behavior = key->firstBehavior; behavior != NULL; behavior = behavior->next) { parcel->writeInt32(1); parcel->writeInt32(behavior->metaState); parcel->writeInt32(behavior->character); parcel->writeInt32(behavior->fallbackKeyCode); parcel->writeInt32(behavior->replacementKeyCode); } parcel->writeInt32(0); } } #endif // --- KeyCharacterMap::Key --- KeyCharacterMap::Key::Key() : label(0), number(0), firstBehavior(NULL) { } KeyCharacterMap::Key::Key(const Key& other) : label(other.label), number(other.number), firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { } KeyCharacterMap::Key::~Key() { Behavior* behavior = firstBehavior; while (behavior) { Behavior* next = behavior->next; delete behavior; behavior = next; } } // --- KeyCharacterMap::Behavior --- KeyCharacterMap::Behavior::Behavior() : next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) { } KeyCharacterMap::Behavior::Behavior(const Behavior& other) : next(other.next ? new Behavior(*other.next) : NULL), metaState(other.metaState), character(other.character), fallbackKeyCode(other.fallbackKeyCode), replacementKeyCode(other.replacementKeyCode) { } // --- KeyCharacterMap::Parser --- KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { } KeyCharacterMap::Parser::~Parser() { } status_t KeyCharacterMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { switch (mState) { case STATE_TOP: { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "type") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseType(); if (status) return status; } else if (keywordToken == "map") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseMap(); if (status) return status; } else if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; } else { ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); return BAD_VALUE; } break; } case STATE_KEY: { status_t status = parseKeyProperty(); if (status) return status; break; } } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); return BAD_VALUE; } } mTokenizer->nextLine(); } if (mState != STATE_TOP) { ALOGE("%s: Unterminated key description at end of file.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (mFormat == FORMAT_BASE) { if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", mTokenizer->getLocation().string()); return BAD_VALUE; } } else if (mFormat == FORMAT_OVERLAY) { if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { ALOGE("%s: Overlay keyboard layout missing required keyboard " "'type OVERLAY' declaration.", mTokenizer->getLocation().string()); return BAD_VALUE; } } return NO_ERROR; } status_t KeyCharacterMap::Parser::parseType() { if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().string()); return BAD_VALUE; } KeyboardType type; String8 typeToken = mTokenizer->nextToken(WHITESPACE); if (typeToken == "NUMERIC") { type = KEYBOARD_TYPE_NUMERIC; } else if (typeToken == "PREDICTIVE") { type = KEYBOARD_TYPE_PREDICTIVE; } else if (typeToken == "ALPHA") { type = KEYBOARD_TYPE_ALPHA; } else if (typeToken == "FULL") { type = KEYBOARD_TYPE_FULL; } else if (typeToken == "SPECIAL_FUNCTION") { type = KEYBOARD_TYPE_SPECIAL_FUNCTION; } else if (typeToken == "OVERLAY") { type = KEYBOARD_TYPE_OVERLAY; } else { ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), typeToken.string()); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed type: type=%d.", type); #endif mMap->mType = type; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseMap() { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); return parseMapKey(); } ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); return BAD_VALUE; } status_t KeyCharacterMap::Parser::parseMapKey() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); bool mapUsage = false; if (codeToken == "usage") { mapUsage = true; mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed map key %s: code=%d, keyCode=%d.", mapUsage ? "usage" : "scan code", code, keyCode); #endif map.add(code, keyCode); return NO_ERROR; } status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(keyCode) >= 0) { ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); if (openBraceToken != "{") { ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().string(), openBraceToken.string()); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); #endif mKeyCode = keyCode; mMap->mKeys.add(keyCode, new Key()); mState = STATE_KEY; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseKeyProperty() { Key* key = mMap->mKeys.valueFor(mKeyCode); String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); if (token == "}") { mState = STATE_TOP; return finishKey(key); } Vector properties; // Parse all comma-delimited property names up to the first colon. for (;;) { if (token == "label") { properties.add(Property(PROPERTY_LABEL)); } else if (token == "number") { properties.add(Property(PROPERTY_NUMBER)); } else { int32_t metaState; status_t status = parseModifier(token, &metaState); if (status) { ALOGE("%s: Expected a property name or modifier, got '%s'.", mTokenizer->getLocation().string(), token.string()); return status; } properties.add(Property(PROPERTY_META, metaState)); } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { char ch = mTokenizer->nextChar(); if (ch == ':') { break; } else if (ch == ',') { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); continue; } } ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().string()); return BAD_VALUE; } // Parse behavior after the colon. mTokenizer->skipDelimiters(WHITESPACE); Behavior behavior; bool haveCharacter = false; bool haveFallback = false; bool haveReplacement = false; do { char ch = mTokenizer->peekChar(); if (ch == '\'') { char16_t character; status_t status = parseCharacterLiteral(&character); if (status || !character) { ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine character literal with replace action.", mTokenizer->getLocation().string()); return BAD_VALUE; } behavior.character = character; haveCharacter = true; } else { token = mTokenizer->nextToken(WHITESPACE); if (token == "none") { if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine 'none' with replace action.", mTokenizer->getLocation().string()); return BAD_VALUE; } haveCharacter = true; } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(token.string()); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", mTokenizer->getLocation().string(), token.string()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", mTokenizer->getLocation().string()); return BAD_VALUE; } behavior.fallbackKeyCode = keyCode; haveFallback = true; } else if (token == "replace") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(token.string()); if (!keyCode) { ALOGE("%s: Invalid key code label for replace, got '%s'.", mTokenizer->getLocation().string(), token.string()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine character literal with replace action.", mTokenizer->getLocation().string()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", mTokenizer->getLocation().string()); return BAD_VALUE; } behavior.replacementKeyCode = keyCode; haveReplacement = true; } else { ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().string()); return BAD_VALUE; } } mTokenizer->skipDelimiters(WHITESPACE); } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); // Add the behavior. for (size_t i = 0; i < properties.size(); i++) { const Property& property = properties.itemAt(i); switch (property.property) { case PROPERTY_LABEL: if (key->label) { ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().string()); return BAD_VALUE; } key->label = behavior.character; #if DEBUG_PARSER ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); #endif break; case PROPERTY_NUMBER: if (key->number) { ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().string()); return BAD_VALUE; } key->number = behavior.character; #if DEBUG_PARSER ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); #endif break; case PROPERTY_META: { for (Behavior* b = key->firstBehavior; b; b = b->next) { if (b->metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", mTokenizer->getLocation().string()); return BAD_VALUE; } } Behavior* newBehavior = new Behavior(behavior); newBehavior->metaState = property.metaState; newBehavior->next = key->firstBehavior; key->firstBehavior = newBehavior; #if DEBUG_PARSER ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.", mKeyCode, newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode); #endif break; } } } return NO_ERROR; } status_t KeyCharacterMap::Parser::finishKey(Key* key) { // Fill in default number property. if (!key->number) { char16_t digit = 0; char16_t symbol = 0; for (Behavior* b = key->firstBehavior; b; b = b->next) { char16_t ch = b->character; if (ch) { if (ch >= '0' && ch <= '9') { digit = ch; } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' || ch == '-' || ch == '+' || ch == ',' || ch == '.' || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { symbol = ch; } } } key->number = digit ? digit : symbol; } return NO_ERROR; } status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { if (token == "base") { *outMetaState = 0; return NO_ERROR; } int32_t combinedMeta = 0; const char* str = token.string(); const char* start = str; for (const char* cur = str; ; cur++) { char ch = *cur; if (ch == '+' || ch == '\0') { size_t len = cur - start; int32_t metaState = 0; for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { if (strlen(modifiers[i].label) == len && strncmp(modifiers[i].label, start, len) == 0) { metaState = modifiers[i].metaState; break; } } if (!metaState) { return BAD_VALUE; } if (combinedMeta & metaState) { ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().string(), token.string()); return BAD_VALUE; } combinedMeta |= metaState; start = cur + 1; if (ch == '\0') { break; } } } *outMetaState = combinedMeta; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { char ch = mTokenizer->nextChar(); if (ch != '\'') { goto Error; } ch = mTokenizer->nextChar(); if (ch == '\\') { // Escape sequence. ch = mTokenizer->nextChar(); if (ch == 'n') { *outCharacter = '\n'; } else if (ch == 't') { *outCharacter = '\t'; } else if (ch == '\\') { *outCharacter = '\\'; } else if (ch == '\'') { *outCharacter = '\''; } else if (ch == '"') { *outCharacter = '"'; } else if (ch == 'u') { *outCharacter = 0; for (int i = 0; i < 4; i++) { ch = mTokenizer->nextChar(); int digit; if (ch >= '0' && ch <= '9') { digit = ch - '0'; } else if (ch >= 'A' && ch <= 'F') { digit = ch - 'A' + 10; } else if (ch >= 'a' && ch <= 'f') { digit = ch - 'a' + 10; } else { goto Error; } *outCharacter = (*outCharacter << 4) | digit; } } else { goto Error; } } else if (ch >= 32 && ch <= 126 && ch != '\'') { // ASCII literal character. *outCharacter = ch; } else { goto Error; } ch = mTokenizer->nextChar(); if (ch != '\'') { goto Error; } // Ensure that we consumed the entire token. if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { return NO_ERROR; } Error: ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); return BAD_VALUE; } } // namespace android libs/input/KeyLayoutMap.cpp0100644 0000000 0000000 00000035574 13077405420 015005 0ustar000000000 0000000 /* * Copyright (C) 2008 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. */ #define LOG_TAG "KeyLayoutMap" #include #include #include #include #include #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 // Enables debug output for mapping. #define DEBUG_MAPPING 0 namespace android { static const char* WHITESPACE = " \t\r"; // --- KeyLayoutMap --- KeyLayoutMap::KeyLayoutMap() { } KeyLayoutMap::~KeyLayoutMap() { } status_t KeyLayoutMap::load(const String8& filename, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening key layout map file %s.", status, filename.string()); } else { sp map = new KeyLayoutMap(); if (!map.get()) { ALOGE("Error allocating key layout map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map.get(), tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { *outMap = map; } } delete tokenizer; } return status; } status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode, uint32_t* outFlags) const { const Key* key = getKey(scanCode, usageCode); if (!key) { #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); #endif *outKeyCode = AKEYCODE_UNKNOWN; *outFlags = 0; return NAME_NOT_FOUND; } *outKeyCode = key->keyCode; *outFlags = key->flags; #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", scanCode, usageCode, *outKeyCode, *outFlags); #endif return NO_ERROR; } const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { if (usageCode) { ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); if (index >= 0) { return &mKeysByUsageCode.valueAt(index); } } if (scanCode) { ssize_t index = mKeysByScanCode.indexOfKey(scanCode); if (index >= 0) { return &mKeysByScanCode.valueAt(index); } } return NULL; } status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const { const size_t N = mKeysByScanCode.size(); for (size_t i=0; iadd(mKeysByScanCode.keyAt(i)); } } return NO_ERROR; } status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { ssize_t index = mAxes.indexOfKey(scanCode); if (index < 0) { #if DEBUG_MAPPING ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); #endif return NAME_NOT_FOUND; } *outAxisInfo = mAxes.valueAt(index); #if DEBUG_MAPPING ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " "splitValue=%d, flatOverride=%d.", scanCode, outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, outAxisInfo->splitValue, outAxisInfo->flatOverride); #endif return NO_ERROR; } status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const { const size_t N = mLedsByScanCode.size(); for (size_t i = 0; i < N; i++) { if (mLedsByScanCode.valueAt(i).ledCode == ledCode) { *outScanCode = mLedsByScanCode.keyAt(i); #if DEBUG_MAPPING ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode); #endif return NO_ERROR; } } #if DEBUG_MAPPING ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode); #endif return NAME_NOT_FOUND; } status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const { const size_t N = mLedsByUsageCode.size(); for (size_t i = 0; i < N; i++) { if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) { *outUsageCode = mLedsByUsageCode.keyAt(i); #if DEBUG_MAPPING ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode); #endif return NO_ERROR; } } #if DEBUG_MAPPING ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode); #endif return NAME_NOT_FOUND; } // --- KeyLayoutMap::Parser --- KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : mMap(map), mTokenizer(tokenizer) { } KeyLayoutMap::Parser::~Parser() { } status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; } else if (keywordToken == "axis") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseAxis(); if (status) return status; } else if (keywordToken == "led") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseLed(); if (status) return status; } else { ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); return BAD_VALUE; } } mTokenizer->nextLine(); } return NO_ERROR; } status_t KeyLayoutMap::Parser::parseKey() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); bool mapUsage = false; if (codeToken == "usage") { mapUsage = true; mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; } uint32_t flags = 0; for (;;) { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); uint32_t flag = getKeyFlagByLabel(flagToken.string()); if (!flag) { ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } if (flags & flag) { ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } flags |= flag; } #if DEBUG_PARSER ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", mapUsage ? "usage" : "scan code", code, keyCode, flags); #endif Key key; key.keyCode = keyCode; key.flags = flags; map.add(code, key); return NO_ERROR; } status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); char* end; int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } if (mMap->mAxes.indexOfKey(scanCode) >= 0) { ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } AxisInfo axisInfo; mTokenizer->skipDelimiters(WHITESPACE); String8 token = mTokenizer->nextToken(WHITESPACE); if (token == "invert") { axisInfo.mode = AxisInfo::MODE_INVERT; mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.axis = getAxisByLabel(axisToken.string()); if (axisInfo.axis < 0) { ALOGE("%s: Expected inverted axis label, got '%s'.", mTokenizer->getLocation().string(), axisToken.string()); return BAD_VALUE; } } else if (token == "split") { axisInfo.mode = AxisInfo::MODE_SPLIT; mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected split value, got '%s'.", mTokenizer->getLocation().string(), splitToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.axis = getAxisByLabel(lowAxisToken.string()); if (axisInfo.axis < 0) { ALOGE("%s: Expected low axis label, got '%s'.", mTokenizer->getLocation().string(), lowAxisToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); if (axisInfo.highAxis < 0) { ALOGE("%s: Expected high axis label, got '%s'.", mTokenizer->getLocation().string(), highAxisToken.string()); return BAD_VALUE; } } else { axisInfo.axis = getAxisByLabel(token.string()); if (axisInfo.axis < 0) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", mTokenizer->getLocation().string(), token.string()); return BAD_VALUE; } } for (;;) { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { break; } String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected flat value, got '%s'.", mTokenizer->getLocation().string(), flatToken.string()); return BAD_VALUE; } } else { ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); return BAD_VALUE; } } #if DEBUG_PARSER ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " "splitValue=%d, flatOverride=%d.", scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue, axisInfo.flatOverride); #endif mMap->mAxes.add(scanCode, axisInfo); return NO_ERROR; } status_t KeyLayoutMap::Parser::parseLed() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); bool mapUsage = false; if (codeToken == "usage") { mapUsage = true; mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); if (*end) { ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; if (map.indexOfKey(code) >= 0) { ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t ledCode = getLedByLabel(ledCodeToken.string()); if (ledCode < 0) { ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), ledCodeToken.string()); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code", code, ledCode); #endif Led led; led.ledCode = ledCode; map.add(code, led); return NO_ERROR; } }; libs/input/Keyboard.cpp0100644 0000000 0000000 00000020564 13077405420 014152 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "Keyboard" #include #include #include #include #include #include #include #include #include #include namespace android { // --- KeyMap --- KeyMap::KeyMap() { } KeyMap::~KeyMap() { } status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", deviceIdenfifier.name.string(), keyLayoutName.string()); } } if (isComplete()) { return OK; } } // Try searching by device identifier. if (probeKeyMap(deviceIdenfifier, String8::empty())) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { return OK; } // Try the Virtual key map as a last resort. if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", deviceIdenfifier.name.string()); return NAME_NOT_FOUND; } bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& keyMapName) { if (!haveKeyLayout()) { loadKeyLayout(deviceIdentifier, keyMapName); } if (!haveKeyCharacterMap()) { loadKeyCharacterMap(deviceIdentifier, keyMapName); } return isComplete(); } status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name) { String8 path(getPath(deviceIdentifier, name, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); if (path.isEmpty()) { return NAME_NOT_FOUND; } status_t status = KeyLayoutMap::load(path, &keyLayoutMap); if (status) { return status; } keyLayoutFile.setTo(path); return OK; } status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name) { String8 path(getPath(deviceIdentifier, name, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); if (path.isEmpty()) { return NAME_NOT_FOUND; } status_t status = KeyCharacterMap::load(path, KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); if (status) { return status; } keyCharacterMapFile.setTo(path); return OK; } String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, const String8& name, InputDeviceConfigurationFileType type) { return name.isEmpty() ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) : getInputDeviceConfigurationFilePathByName(name, type); } // --- Global functions --- bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { if (!keyMap->haveKeyCharacterMap() || keyMap->keyCharacterMap->getKeyboardType() == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { return false; } if (deviceConfiguration) { bool builtIn = false; if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) && builtIn) { return true; } } return strstr(deviceIdentifier.name.string(), "-keypad"); } static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { int32_t newMetaState; if (down) { newMetaState = oldMetaState | mask; } else { newMetaState = oldMetaState & ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON); } return normalizeMetaState(newMetaState); } int32_t normalizeMetaState(int32_t oldMetaState) { int32_t newMetaState = oldMetaState; if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { newMetaState |= AMETA_ALT_ON; } if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { newMetaState |= AMETA_SHIFT_ON; } if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { newMetaState |= AMETA_CTRL_ON; } if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { newMetaState |= AMETA_META_ON; } return newMetaState; } static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) { if (down) { return oldMetaState; } else { return oldMetaState ^ mask; } } int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; switch (keyCode) { case AKEYCODE_ALT_LEFT: return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); case AKEYCODE_ALT_RIGHT: return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState); case AKEYCODE_SHIFT_LEFT: return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState); case AKEYCODE_SHIFT_RIGHT: return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState); case AKEYCODE_SYM: return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState); case AKEYCODE_FUNCTION: return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState); case AKEYCODE_CTRL_LEFT: return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState); case AKEYCODE_CTRL_RIGHT: return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState); case AKEYCODE_META_LEFT: return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState); case AKEYCODE_META_RIGHT: return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState); case AKEYCODE_CAPS_LOCK: return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState); case AKEYCODE_NUM_LOCK: return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState); case AKEYCODE_SCROLL_LOCK: return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState); default: return oldMetaState; } } bool isMetaKey(int32_t keyCode) { switch (keyCode) { case AKEYCODE_ALT_LEFT: case AKEYCODE_ALT_RIGHT: case AKEYCODE_SHIFT_LEFT: case AKEYCODE_SHIFT_RIGHT: case AKEYCODE_SYM: case AKEYCODE_FUNCTION: case AKEYCODE_CTRL_LEFT: case AKEYCODE_CTRL_RIGHT: case AKEYCODE_META_LEFT: case AKEYCODE_META_RIGHT: case AKEYCODE_CAPS_LOCK: case AKEYCODE_NUM_LOCK: case AKEYCODE_SCROLL_LOCK: return true; default: return false; } } } // namespace android libs/input/VelocityControl.cpp0100644 0000000 0000000 00000006715 13077405420 015553 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "VelocityControl" //#define LOG_NDEBUG 0 // Log debug messages about acceleration. #define DEBUG_ACCELERATION 0 #include #include #include #include #include namespace android { // --- VelocityControl --- const nsecs_t VelocityControl::STOP_TIME; VelocityControl::VelocityControl() { reset(); } void VelocityControl::setParameters(const VelocityControlParameters& parameters) { mParameters = parameters; reset(); } void VelocityControl::reset() { mLastMovementTime = LLONG_MIN; mRawPosition.x = 0; mRawPosition.y = 0; mVelocityTracker.clear(); } void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { if ((deltaX && *deltaX) || (deltaY && *deltaY)) { if (eventTime >= mLastMovementTime + STOP_TIME) { #if DEBUG_ACCELERATION ALOGD("VelocityControl: stopped, last movement was %0.3fms ago", (eventTime - mLastMovementTime) * 0.000001f); #endif reset(); } mLastMovementTime = eventTime; if (deltaX) { mRawPosition.x += *deltaX; } if (deltaY) { mRawPosition.y += *deltaY; } mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); float vx, vy; float scale = mParameters.scale; if (mVelocityTracker.getVelocity(0, &vx, &vy)) { float speed = hypotf(vx, vy) * scale; if (speed >= mParameters.highThreshold) { // Apply full acceleration above the high speed threshold. scale *= mParameters.acceleration; } else if (speed > mParameters.lowThreshold) { // Linearly interpolate the acceleration to apply between the low and high // speed thresholds. scale *= 1 + (speed - mParameters.lowThreshold) / (mParameters.highThreshold - mParameters.lowThreshold) * (mParameters.acceleration - 1); } #if DEBUG_ACCELERATION ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration, vx, vy, speed, scale / mParameters.scale); #endif } else { #if DEBUG_ACCELERATION ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration); #endif } if (deltaX) { *deltaX *= scale; } if (deltaY) { *deltaY *= scale; } } } } // namespace android libs/input/VelocityTracker.cpp0100644 0000000 0000000 00000100402 13077405420 015512 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "VelocityTracker" //#define LOG_NDEBUG 0 // Log debug messages about velocity tracking. #define DEBUG_VELOCITY 0 // Log debug messages about the progress of the algorithm itself. #define DEBUG_STRATEGY 0 #include #include #include #include #include #include #include namespace android { // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; // Threshold for determining that a pointer has stopped moving. // Some input devices do not send ACTION_MOVE events in the case where a pointer has // stopped. We need to detect this case so that we can accurately predict the // velocity after the pointer starts moving again. static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; static float vectorDot(const float* a, const float* b, uint32_t m) { float r = 0; while (m) { m--; r += *(a++) * *(b++); } return r; } static float vectorNorm(const float* a, uint32_t m) { float r = 0; while (m) { m--; float t = *(a++); r += t * t; } return sqrtf(r); } #if DEBUG_STRATEGY || DEBUG_VELOCITY static String8 vectorToString(const float* a, uint32_t m) { String8 str; str.append("["); while (m--) { str.appendFormat(" %f", *(a++)); if (m) { str.append(","); } } str.append(" ]"); return str; } static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { String8 str; str.append("["); for (size_t i = 0; i < m; i++) { if (i) { str.append(","); } str.append(" ["); for (size_t j = 0; j < n; j++) { if (j) { str.append(","); } str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); } str.append(" ]"); } str.append(" ]"); return str; } #endif // --- VelocityTracker --- // The default velocity tracker strategy. // Although other strategies are available for testing and comparison purposes, // this is the strategy that applications will actually use. Be very careful // when adjusting the default strategy because it can dramatically affect // (often in a bad way) the user experience. const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2"; VelocityTracker::VelocityTracker(const char* strategy) : mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) { char value[PROPERTY_VALUE_MAX]; // Allow the default strategy to be overridden using a system property for debugging. if (!strategy) { int length = property_get("debug.velocitytracker.strategy", value, NULL); if (length > 0) { strategy = value; } else { strategy = DEFAULT_STRATEGY; } } // Configure the strategy. if (!configureStrategy(strategy)) { ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy); if (!configureStrategy(DEFAULT_STRATEGY)) { LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!", strategy); } } } VelocityTracker::~VelocityTracker() { delete mStrategy; } bool VelocityTracker::configureStrategy(const char* strategy) { mStrategy = createStrategy(strategy); return mStrategy != NULL; } VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { if (!strcmp("lsq1", strategy)) { // 1st order least squares. Quality: POOR. // Frequently underfits the touch data especially when the finger accelerates // or changes direction. Often underestimates velocity. The direction // is overly influenced by historical touch points. return new LeastSquaresVelocityTrackerStrategy(1); } if (!strcmp("lsq2", strategy)) { // 2nd order least squares. Quality: VERY GOOD. // Pretty much ideal, but can be confused by certain kinds of touch data, // particularly if the panel has a tendency to generate delayed, // duplicate or jittery touch coordinates when the finger is released. return new LeastSquaresVelocityTrackerStrategy(2); } if (!strcmp("lsq3", strategy)) { // 3rd order least squares. Quality: UNUSABLE. // Frequently overfits the touch data yielding wildly divergent estimates // of the velocity when the finger is released. return new LeastSquaresVelocityTrackerStrategy(3); } if (!strcmp("wlsq2-delta", strategy)) { // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA); } if (!strcmp("wlsq2-central", strategy)) { // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL); } if (!strcmp("wlsq2-recent", strategy)) { // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT); } if (!strcmp("int1", strategy)) { // 1st order integrating filter. Quality: GOOD. // Not as good as 'lsq2' because it cannot estimate acceleration but it is // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate // the velocity of a fling but this strategy tends to respond to changes in // direction more quickly and accurately. return new IntegratingVelocityTrackerStrategy(1); } if (!strcmp("int2", strategy)) { // 2nd order integrating filter. Quality: EXPERIMENTAL. // For comparison purposes only. Unlike 'int1' this strategy can compensate // for acceleration but it typically overestimates the effect. return new IntegratingVelocityTrackerStrategy(2); } if (!strcmp("legacy", strategy)) { // Legacy velocity tracker algorithm. Quality: POOR. // For comparison purposes only. This algorithm is strongly influenced by // old data points, consistently underestimates velocity and takes a very long // time to adjust to changes in direction. return new LegacyVelocityTrackerStrategy(); } return NULL; } void VelocityTracker::clear() { mCurrentPointerIdBits.clear(); mActivePointerId = -1; mStrategy->clear(); } void VelocityTracker::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value); mCurrentPointerIdBits = remainingIdBits; if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; } mStrategy->clearPointers(idBits); } void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { while (idBits.count() > MAX_POINTERS) { idBits.clearLastMarkedBit(); } if ((mCurrentPointerIdBits.value & idBits.value) && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { #if DEBUG_VELOCITY ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", (eventTime - mLastEventTime) * 0.000001f); #endif // We have not received any movements for too long. Assume that all pointers // have stopped. mStrategy->clear(); } mLastEventTime = eventTime; mCurrentPointerIdBits = idBits; if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit(); } mStrategy->addMovement(eventTime, idBits, positions); #if DEBUG_VELOCITY ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", eventTime, idBits.value, mActivePointerId); for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { uint32_t id = iterBits.firstMarkedBit(); uint32_t index = idBits.getIndexOfBit(id); iterBits.clearBit(id); Estimator estimator; getEstimator(id, &estimator); ALOGD(" %d: position (%0.3f, %0.3f), " "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", id, positions[index].x, positions[index].y, int(estimator.degree), vectorToString(estimator.xCoeff, estimator.degree + 1).string(), vectorToString(estimator.yCoeff, estimator.degree + 1).string(), estimator.confidence); } #endif } void VelocityTracker::addMovement(const MotionEvent* event) { int32_t actionMasked = event->getActionMasked(); switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_HOVER_ENTER: // Clear all pointers on down before adding the new movement. clear(); break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { // Start a new movement trace for a pointer that just went down. // We do this on down instead of on up because the client may want to query the // final velocity for a pointer that just went up. BitSet32 downIdBits; downIdBits.markBit(event->getPointerId(event->getActionIndex())); clearPointers(downIdBits); break; } case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_HOVER_MOVE: break; default: // Ignore all other actions because they do not convey any new information about // pointer movement. We also want to preserve the last known velocity of the pointers. // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position // of the pointers that went up. ACTION_POINTER_UP does include the new position of // pointers that remained down but we will also receive an ACTION_MOVE with this // information if any of them actually moved. Since we don't know how many pointers // will be going up at once it makes sense to just wait for the following ACTION_MOVE // before adding the movement. return; } size_t pointerCount = event->getPointerCount(); if (pointerCount > MAX_POINTERS) { pointerCount = MAX_POINTERS; } BitSet32 idBits; for (size_t i = 0; i < pointerCount; i++) { idBits.markBit(event->getPointerId(i)); } uint32_t pointerIndex[MAX_POINTERS]; for (size_t i = 0; i < pointerCount; i++) { pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i)); } nsecs_t eventTime; Position positions[pointerCount]; size_t historySize = event->getHistorySize(); for (size_t h = 0; h < historySize; h++) { eventTime = event->getHistoricalEventTime(h); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; positions[index].x = event->getHistoricalX(i, h); positions[index].y = event->getHistoricalY(i, h); } addMovement(eventTime, idBits, positions); } eventTime = event->getEventTime(); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; positions[index].x = event->getX(i); positions[index].y = event->getY(i); } addMovement(eventTime, idBits, positions); } bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { Estimator estimator; if (getEstimator(id, &estimator) && estimator.degree >= 1) { *outVx = estimator.xCoeff[1]; *outVy = estimator.yCoeff[1]; return true; } *outVx = 0; *outVy = 0; return false; } bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { return mStrategy->getEstimator(id, outEstimator); } // --- LeastSquaresVelocityTrackerStrategy --- const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( uint32_t degree, Weighting weighting) : mDegree(degree), mWeighting(weighting) { clear(); } LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { } void LeastSquaresVelocityTrackerStrategy::clear() { mIndex = 0; mMovements[0].idBits.clear(); } void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); mMovements[mIndex].idBits = remainingIdBits; } void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions) { if (++mIndex == HISTORY_SIZE) { mIndex = 0; } Movement& movement = mMovements[mIndex]; movement.eventTime = eventTime; movement.idBits = idBits; uint32_t count = idBits.count(); for (uint32_t i = 0; i < count; i++) { movement.positions[i] = positions[i]; } } /** * Solves a linear least squares problem to obtain a N degree polynomial that fits * the specified input data as nearly as possible. * * Returns true if a solution is found, false otherwise. * * The input consists of two vectors of data points X and Y with indices 0..m-1 * along with a weight vector W of the same size. * * The output is a vector B with indices 0..n that describes a polynomial * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. * * Accordingly, the weight vector W should be initialized by the caller with the * reciprocal square root of the variance of the error in each input data point. * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). * The weights express the relative importance of each data point. If the weights are * all 1, then the data points are considered to be of equal importance when fitting * the polynomial. It is a good idea to choose weights that diminish the importance * of data points that may have higher than usual error margins. * * Errors among data points are assumed to be independent. W is represented here * as a vector although in the literature it is typically taken to be a diagonal matrix. * * That is to say, the function that generated the input data can be approximated * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. * * The coefficient of determination (R^2) is also returned to describe the goodness * of fit of the model for the given data. It is a value between 0 and 1, where 1 * indicates perfect correspondence. * * This function first expands the X vector to a m by n matrix A such that * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then * multiplies it by w[i]./ * * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q * and an m by n upper triangular matrix R. Because R is upper triangular (lower * part is all zeroes), we can simplify the decomposition into an m by n matrix * Q1 and a n by n matrix R1 such that A = Q1 R1. * * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) * to find B. * * For efficiency, we lay out A and Q column-wise in memory because we frequently * operate on the column vectors. Conversely, we lay out R row-wise. * * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares * http://en.wikipedia.org/wiki/Gram-Schmidt */ static bool solveLeastSquares(const float* x, const float* y, const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { #if DEBUG_STRATEGY ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), vectorToString(x, m).string(), vectorToString(y, m).string(), vectorToString(w, m).string()); #endif // Expand the X vector to a matrix A, pre-multiplied by the weights. float a[n][m]; // column-major order for (uint32_t h = 0; h < m; h++) { a[0][h] = w[h]; for (uint32_t i = 1; i < n; i++) { a[i][h] = a[i - 1][h] * x[h]; } } #if DEBUG_STRATEGY ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); #endif // Apply the Gram-Schmidt process to A to obtain its QR decomposition. float q[n][m]; // orthonormal basis, column-major order float r[n][n]; // upper triangular matrix, row-major order for (uint32_t j = 0; j < n; j++) { for (uint32_t h = 0; h < m; h++) { q[j][h] = a[j][h]; } for (uint32_t i = 0; i < j; i++) { float dot = vectorDot(&q[j][0], &q[i][0], m); for (uint32_t h = 0; h < m; h++) { q[j][h] -= dot * q[i][h]; } } float norm = vectorNorm(&q[j][0], m); if (norm < 0.000001f) { // vectors are linearly dependent or zero so no solution #if DEBUG_STRATEGY ALOGD(" - no solution, norm=%f", norm); #endif return false; } float invNorm = 1.0f / norm; for (uint32_t h = 0; h < m; h++) { q[j][h] *= invNorm; } for (uint32_t i = 0; i < n; i++) { r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); } } #if DEBUG_STRATEGY ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); // calculate QR, if we factored A correctly then QR should equal A float qr[n][m]; for (uint32_t h = 0; h < m; h++) { for (uint32_t i = 0; i < n; i++) { qr[i][h] = 0; for (uint32_t j = 0; j < n; j++) { qr[i][h] += q[j][h] * r[j][i]; } } } ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); #endif // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. // We just work from bottom-right to top-left calculating B's coefficients. float wy[m]; for (uint32_t h = 0; h < m; h++) { wy[h] = y[h] * w[h]; } for (uint32_t i = n; i != 0; ) { i--; outB[i] = vectorDot(&q[i][0], wy, m); for (uint32_t j = n - 1; j > i; j--) { outB[i] -= r[i][j] * outB[j]; } outB[i] /= r[i][i]; } #if DEBUG_STRATEGY ALOGD(" - b=%s", vectorToString(outB, n).string()); #endif // Calculate the coefficient of determination as 1 - (SSerr / SStot) where // SSerr is the residual sum of squares (variance of the error), // and SStot is the total sum of squares (variance of the data) where each // has been weighted. float ymean = 0; for (uint32_t h = 0; h < m; h++) { ymean += y[h]; } ymean /= m; float sserr = 0; float sstot = 0; for (uint32_t h = 0; h < m; h++) { float err = y[h] - outB[0]; float term = 1; for (uint32_t i = 1; i < n; i++) { term *= x[h]; err -= term * outB[i]; } sserr += w[h] * w[h] * err * err; float var = y[h] - ymean; sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; #if DEBUG_STRATEGY ALOGD(" - sserr=%f", sserr); ALOGD(" - sstot=%f", sstot); ALOGD(" - det=%f", *outDet); #endif return true; } bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); // Iterate over movement samples in reverse time order and collect samples. float x[HISTORY_SIZE]; float y[HISTORY_SIZE]; float w[HISTORY_SIZE]; float time[HISTORY_SIZE]; uint32_t m = 0; uint32_t index = mIndex; const Movement& newestMovement = mMovements[mIndex]; do { const Movement& movement = mMovements[index]; if (!movement.idBits.hasBit(id)) { break; } nsecs_t age = newestMovement.eventTime - movement.eventTime; if (age > HORIZON) { break; } const VelocityTracker::Position& position = movement.getPosition(id); x[m] = position.x; y[m] = position.y; w[m] = chooseWeight(index); time[m] = -age * 0.000000001f; index = (index == 0 ? HISTORY_SIZE : index) - 1; } while (++m < HISTORY_SIZE); if (m == 0) { return false; // no data } // Calculate a least squares polynomial fit. uint32_t degree = mDegree; if (degree > m - 1) { degree = m - 1; } if (degree >= 1) { float xdet, ydet; uint32_t n = degree + 1; if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) { outEstimator->time = newestMovement.eventTime; outEstimator->degree = degree; outEstimator->confidence = xdet * ydet; #if DEBUG_STRATEGY ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).string(), vectorToString(outEstimator->yCoeff, n).string(), outEstimator->confidence); #endif return true; } } // No velocity data available for this pointer, but we do have its current position. outEstimator->xCoeff[0] = x[0]; outEstimator->yCoeff[0] = y[0]; outEstimator->time = newestMovement.eventTime; outEstimator->degree = 0; outEstimator->confidence = 1; return true; } float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const { switch (mWeighting) { case WEIGHTING_DELTA: { // Weight points based on how much time elapsed between them and the next // point so that points that "cover" a shorter time span are weighed less. // delta 0ms: 0.5 // delta 10ms: 1.0 if (index == mIndex) { return 1.0f; } uint32_t nextIndex = (index + 1) % HISTORY_SIZE; float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime) * 0.000001f; if (deltaMillis < 0) { return 0.5f; } if (deltaMillis < 10) { return 0.5f + deltaMillis * 0.05; } return 1.0f; } case WEIGHTING_CENTRAL: { // Weight points based on their age, weighing very recent and very old points less. // age 0ms: 0.5 // age 10ms: 1.0 // age 50ms: 1.0 // age 60ms: 0.5 float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) * 0.000001f; if (ageMillis < 0) { return 0.5f; } if (ageMillis < 10) { return 0.5f + ageMillis * 0.05; } if (ageMillis < 50) { return 1.0f; } if (ageMillis < 60) { return 0.5f + (60 - ageMillis) * 0.05; } return 0.5f; } case WEIGHTING_RECENT: { // Weight points based on their age, weighing older points less. // age 0ms: 1.0 // age 50ms: 1.0 // age 100ms: 0.5 float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) * 0.000001f; if (ageMillis < 50) { return 1.0f; } if (ageMillis < 100) { return 0.5f + (100 - ageMillis) * 0.01f; } return 0.5f; } case WEIGHTING_NONE: default: return 1.0f; } } // --- IntegratingVelocityTrackerStrategy --- IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) : mDegree(degree) { } IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { } void IntegratingVelocityTrackerStrategy::clear() { mPointerIdBits.clear(); } void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { mPointerIdBits.value &= ~idBits.value; } void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions) { uint32_t index = 0; for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) { uint32_t id = iterIdBits.clearFirstMarkedBit(); State& state = mPointerState[id]; const VelocityTracker::Position& position = positions[index++]; if (mPointerIdBits.hasBit(id)) { updateState(state, eventTime, position.x, position.y); } else { initState(state, eventTime, position.x, position.y); } } mPointerIdBits = idBits; } bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); if (mPointerIdBits.hasBit(id)) { const State& state = mPointerState[id]; populateEstimator(state, outEstimator); return true; } return false; } void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime, float xpos, float ypos) const { state.updateTime = eventTime; state.degree = 0; state.xpos = xpos; state.xvel = 0; state.xaccel = 0; state.ypos = ypos; state.yvel = 0; state.yaccel = 0; } void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const { const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds if (eventTime <= state.updateTime + MIN_TIME_DELTA) { return; } float dt = (eventTime - state.updateTime) * 0.000000001f; state.updateTime = eventTime; float xvel = (xpos - state.xpos) / dt; float yvel = (ypos - state.ypos) / dt; if (state.degree == 0) { state.xvel = xvel; state.yvel = yvel; state.degree = 1; } else { float alpha = dt / (FILTER_TIME_CONSTANT + dt); if (mDegree == 1) { state.xvel += (xvel - state.xvel) * alpha; state.yvel += (yvel - state.yvel) * alpha; } else { float xaccel = (xvel - state.xvel) / dt; float yaccel = (yvel - state.yvel) / dt; if (state.degree == 1) { state.xaccel = xaccel; state.yaccel = yaccel; state.degree = 2; } else { state.xaccel += (xaccel - state.xaccel) * alpha; state.yaccel += (yaccel - state.yaccel) * alpha; } state.xvel += (state.xaccel * dt) * alpha; state.yvel += (state.yaccel * dt) * alpha; } } state.xpos = xpos; state.ypos = ypos; } void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const { outEstimator->time = state.updateTime; outEstimator->confidence = 1.0f; outEstimator->degree = state.degree; outEstimator->xCoeff[0] = state.xpos; outEstimator->xCoeff[1] = state.xvel; outEstimator->xCoeff[2] = state.xaccel / 2; outEstimator->yCoeff[0] = state.ypos; outEstimator->yCoeff[1] = state.yvel; outEstimator->yCoeff[2] = state.yaccel / 2; } // --- LegacyVelocityTrackerStrategy --- const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { clear(); } LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } void LegacyVelocityTrackerStrategy::clear() { mIndex = 0; mMovements[0].idBits.clear(); } void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); mMovements[mIndex].idBits = remainingIdBits; } void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, const VelocityTracker::Position* positions) { if (++mIndex == HISTORY_SIZE) { mIndex = 0; } Movement& movement = mMovements[mIndex]; movement.eventTime = eventTime; movement.idBits = idBits; uint32_t count = idBits.count(); for (uint32_t i = 0; i < count; i++) { movement.positions[i] = positions[i]; } } bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); const Movement& newestMovement = mMovements[mIndex]; if (!newestMovement.idBits.hasBit(id)) { return false; // no data } // Find the oldest sample that contains the pointer and that is not older than HORIZON. nsecs_t minTime = newestMovement.eventTime - HORIZON; uint32_t oldestIndex = mIndex; uint32_t numTouches = 1; do { uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; const Movement& nextOldestMovement = mMovements[nextOldestIndex]; if (!nextOldestMovement.idBits.hasBit(id) || nextOldestMovement.eventTime < minTime) { break; } oldestIndex = nextOldestIndex; } while (++numTouches < HISTORY_SIZE); // Calculate an exponentially weighted moving average of the velocity estimate // at different points in time measured relative to the oldest sample. // This is essentially an IIR filter. Newer samples are weighted more heavily // than older samples. Samples at equal time points are weighted more or less // equally. // // One tricky problem is that the sample data may be poorly conditioned. // Sometimes samples arrive very close together in time which can cause us to // overestimate the velocity at that time point. Most samples might be measured // 16ms apart but some consecutive samples could be only 0.5sm apart because // the hardware or driver reports them irregularly or in bursts. float accumVx = 0; float accumVy = 0; uint32_t index = oldestIndex; uint32_t samplesUsed = 0; const Movement& oldestMovement = mMovements[oldestIndex]; const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); nsecs_t lastDuration = 0; while (numTouches-- > 1) { if (++index == HISTORY_SIZE) { index = 0; } const Movement& movement = mMovements[index]; nsecs_t duration = movement.eventTime - oldestMovement.eventTime; // If the duration between samples is small, we may significantly overestimate // the velocity. Consequently, we impose a minimum duration constraint on the // samples that we include in the calculation. if (duration >= MIN_DURATION) { const VelocityTracker::Position& position = movement.getPosition(id); float scale = 1000000000.0f / duration; // one over time delta in seconds float vx = (position.x - oldestPosition.x) * scale; float vy = (position.y - oldestPosition.y) * scale; accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); lastDuration = duration; samplesUsed += 1; } } // Report velocity. const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); outEstimator->time = newestMovement.eventTime; outEstimator->confidence = 1; outEstimator->xCoeff[0] = newestPosition.x; outEstimator->yCoeff[0] = newestPosition.y; if (samplesUsed) { outEstimator->xCoeff[1] = accumVx; outEstimator->yCoeff[1] = accumVy; outEstimator->degree = 1; } else { outEstimator->degree = 0; } return true; } } // namespace android libs/input/VirtualKeyMap.cpp0100644 0000000 0000000 00000012444 13077405420 015145 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "VirtualKeyMap" #include #include #include #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 namespace android { static const char* WHITESPACE = " \t\r"; static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; // --- VirtualKeyMap --- VirtualKeyMap::VirtualKeyMap() { } VirtualKeyMap::~VirtualKeyMap() { } status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) { *outMap = NULL; Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening virtual key map file %s.", status, filename.string()); } else { VirtualKeyMap* map = new VirtualKeyMap(); if (!map) { ALOGE("Error allocating virtual key map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map, tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status) { delete map; } else { *outMap = map; } } delete tokenizer; } return status; } // --- VirtualKeyMap::Parser --- VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : mMap(map), mTokenizer(tokenizer) { } VirtualKeyMap::Parser::~Parser() { } status_t VirtualKeyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { // Multiple keys can appear on one line or they can be broken up across multiple lines. do { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); if (token != "0x01") { ALOGE("%s: Unknown virtual key type, expected 0x01.", mTokenizer->getLocation().string()); return BAD_VALUE; } VirtualKeyDefinition defn; bool success = parseNextIntField(&defn.scanCode) && parseNextIntField(&defn.centerX) && parseNextIntField(&defn.centerY) && parseNextIntField(&defn.width) && parseNextIntField(&defn.height); if (!success) { ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", mTokenizer->getLocation().string()); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, " "width=%d, height=%d", defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height); #endif mMap->mVirtualKeys.push(defn); } while (consumeFieldDelimiterAndSkipWhitespace()); if (!mTokenizer->isEol()) { ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); return BAD_VALUE; } } mTokenizer->nextLine(); } return NO_ERROR; } bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->peekChar() == ':') { mTokenizer->nextChar(); mTokenizer->skipDelimiters(WHITESPACE); return true; } return false; } bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { if (!consumeFieldDelimiterAndSkipWhitespace()) { return false; } String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); char* end; *outValue = strtol(token.string(), &end, 0); if (token.isEmpty() || *end != '\0') { ALOGE("Expected an integer, got '%s'.", token.string()); return false; } return true; } } // namespace android libs/input/tests/0040755 0000000 0000000 00000000000 13077405420 013044 5ustar000000000 0000000 libs/input/tests/Android.mk0100644 0000000 0000000 00000002234 13077405420 014753 0ustar000000000 0000000 # Build the unit tests. LOCAL_PATH:= $(call my-dir) # Build the unit tests. test_src_files := \ InputChannel_test.cpp \ InputEvent_test.cpp \ InputPublisherAndConsumer_test.cpp shared_libraries := \ libinput \ libcutils \ libutils \ libbinder \ libui \ $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ $(eval include $(BUILD_NATIVE_TEST)) \ ) # NOTE: This is a compile time test, and does not need to be # run. All assertions are static_asserts and will fail during # buildtime if something's wrong. include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := StructLayout_test.cpp LOCAL_MODULE := StructLayout_test LOCAL_CFLAGS := -std=c++11 -O0 LOCAL_MULTILIB := both include $(BUILD_STATIC_LIBRARY) # Build the manual test programs. include $(call all-makefiles-under, $(LOCAL_PATH)) libs/input/tests/InputChannel_test.cpp0100644 0000000 0000000 00000014025 13077405420 017176 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "TestHelpers.h" #include #include #include #include #include #include #include #include namespace android { class InputChannelTest : public testing::Test { protected: virtual void SetUp() { } virtual void TearDown() { } }; TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) { // Our purpose here is to verify that the input channel destructor closes the // file descriptor provided to it. One easy way is to provide it with one end // of a pipe and to check for EPIPE on the other end after the channel is destroyed. Pipe pipe; sp inputChannel = new InputChannel(String8("channel name"), pipe.sendFd); EXPECT_STREQ("channel name", inputChannel->getName().string()) << "channel should have provided name"; EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) << "channel should have provided fd"; inputChannel.clear(); // destroys input channel EXPECT_EQ(-EPIPE, pipe.readSignal()) << "channel should have closed fd when destroyed"; // clean up fds of Pipe endpoints that were closed so we don't try to close them again pipe.sendFd = -1; } TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { sp serverChannel, clientChannel; status_t result = InputChannel::openInputChannelPair(String8("channel name"), serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; // Name EXPECT_STREQ("channel name (server)", serverChannel->getName().string()) << "server channel should have suffixed name"; EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) << "client channel should have suffixed name"; // Server->Client communication InputMessage serverMsg; memset(&serverMsg, 0, sizeof(InputMessage)); serverMsg.header.type = InputMessage::TYPE_KEY; serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN; EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg)) << "server channel should be able to send message to client channel"; InputMessage clientMsg; EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg)) << "client channel should be able to receive message from server channel"; EXPECT_EQ(serverMsg.header.type, clientMsg.header.type) << "client channel should receive the correct message from server channel"; EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action) << "client channel should receive the correct message from server channel"; // Client->Server communication InputMessage clientReply; memset(&clientReply, 0, sizeof(InputMessage)); clientReply.header.type = InputMessage::TYPE_FINISHED; clientReply.body.finished.seq = 0x11223344; clientReply.body.finished.handled = true; EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply)) << "client channel should be able to send message to server channel"; InputMessage serverReply; EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply)) << "server channel should be able to receive message from client channel"; EXPECT_EQ(clientReply.header.type, serverReply.header.type) << "server channel should receive the correct message from client channel"; EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq) << "server channel should receive the correct message from client channel"; EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled) << "server channel should receive the correct message from client channel"; } TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { sp serverChannel, clientChannel; status_t result = InputChannel::openInputChannelPair(String8("channel name"), serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; InputMessage msg; EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg)) << "receiveMessage should have returned WOULD_BLOCK"; } TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { sp serverChannel, clientChannel; status_t result = InputChannel::openInputChannelPair(String8("channel name"), serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; serverChannel.clear(); // close server channel InputMessage msg; EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg)) << "receiveMessage should have returned DEAD_OBJECT"; } TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { sp serverChannel, clientChannel; status_t result = InputChannel::openInputChannelPair(String8("channel name"), serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; serverChannel.clear(); // close server channel InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg)) << "sendMessage should have returned DEAD_OBJECT"; } } // namespace android libs/input/tests/InputEvent_test.cpp0100644 0000000 0000000 00000056417 13077405420 016722 0ustar000000000 0000000 /* * 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 #include #include #include namespace android { class BaseTest : public testing::Test { protected: virtual void SetUp() { } virtual void TearDown() { } }; // --- PointerCoordsTest --- class PointerCoordsTest : public BaseTest { }; TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { PointerCoords coords; coords.clear(); ASSERT_EQ(0ULL, coords.bits); } TEST_F(PointerCoordsTest, AxisValues) { float* valuePtr; PointerCoords coords; coords.clear(); // Check invariants when no axes are present. ASSERT_EQ(0, coords.getAxisValue(0)) << "getAxisValue should return zero because axis is not present"; ASSERT_EQ(0, coords.getAxisValue(1)) << "getAxisValue should return zero because axis is not present"; // Set first axis. ASSERT_EQ(OK, coords.setAxisValue(1, 5)); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(0x4000000000000000ULL, coords.bits); ASSERT_EQ(0, coords.getAxisValue(0)) << "getAxisValue should return zero because axis is not present"; ASSERT_EQ(5, coords.getAxisValue(1)) << "getAxisValue should return value of axis"; // Set an axis with a higher id than all others. (appending value at the end) ASSERT_EQ(OK, coords.setAxisValue(3, 2)); ASSERT_EQ(0x5000000000000000ULL, coords.bits); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(2, coords.values[1]); ASSERT_EQ(0, coords.getAxisValue(0)) << "getAxisValue should return zero because axis is not present"; ASSERT_EQ(5, coords.getAxisValue(1)) << "getAxisValue should return value of axis"; ASSERT_EQ(0, coords.getAxisValue(2)) << "getAxisValue should return zero because axis is not present"; ASSERT_EQ(2, coords.getAxisValue(3)) << "getAxisValue should return value of axis"; // Set an axis with an id lower than all others. (prepending value at beginning) ASSERT_EQ(OK, coords.setAxisValue(0, 4)); ASSERT_EQ(0xd000000000000000ULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(5, coords.values[1]); ASSERT_EQ(2, coords.values[2]); ASSERT_EQ(4, coords.getAxisValue(0)) << "getAxisValue should return value of axis"; ASSERT_EQ(5, coords.getAxisValue(1)) << "getAxisValue should return value of axis"; ASSERT_EQ(0, coords.getAxisValue(2)) << "getAxisValue should return zero because axis is not present"; ASSERT_EQ(2, coords.getAxisValue(3)) << "getAxisValue should return value of axis"; // Set an axis with an id between the others. (inserting value in the middle) ASSERT_EQ(OK, coords.setAxisValue(2, 1)); ASSERT_EQ(0xf000000000000000ULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(5, coords.values[1]); ASSERT_EQ(1, coords.values[2]); ASSERT_EQ(2, coords.values[3]); ASSERT_EQ(4, coords.getAxisValue(0)) << "getAxisValue should return value of axis"; ASSERT_EQ(5, coords.getAxisValue(1)) << "getAxisValue should return value of axis"; ASSERT_EQ(1, coords.getAxisValue(2)) << "getAxisValue should return value of axis"; ASSERT_EQ(2, coords.getAxisValue(3)) << "getAxisValue should return value of axis"; // Set an existing axis value in place. ASSERT_EQ(OK, coords.setAxisValue(1, 6)); ASSERT_EQ(0xf000000000000000ULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(6, coords.values[1]); ASSERT_EQ(1, coords.values[2]); ASSERT_EQ(2, coords.values[3]); ASSERT_EQ(4, coords.getAxisValue(0)) << "getAxisValue should return value of axis"; ASSERT_EQ(6, coords.getAxisValue(1)) << "getAxisValue should return value of axis"; ASSERT_EQ(1, coords.getAxisValue(2)) << "getAxisValue should return value of axis"; ASSERT_EQ(2, coords.getAxisValue(3)) << "getAxisValue should return value of axis"; // Set maximum number of axes. for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) { ASSERT_EQ(OK, coords.setAxisValue(axis, axis)); } ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); // Try to set one more axis beyond maximum number. // Ensure bits are unchanged. ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100)); ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); } TEST_F(PointerCoordsTest, Parcel) { Parcel parcel; PointerCoords inCoords; inCoords.clear(); PointerCoords outCoords; // Round trip with empty coords. inCoords.writeToParcel(&parcel); parcel.setDataPosition(0); outCoords.readFromParcel(&parcel); ASSERT_EQ(0ULL, outCoords.bits); // Round trip with some values. parcel.freeData(); inCoords.setAxisValue(2, 5); inCoords.setAxisValue(5, 8); inCoords.writeToParcel(&parcel); parcel.setDataPosition(0); outCoords.readFromParcel(&parcel); ASSERT_EQ(outCoords.bits, inCoords.bits); ASSERT_EQ(outCoords.values[0], inCoords.values[0]); ASSERT_EQ(outCoords.values[1], inCoords.values[1]); } // --- KeyEventTest --- class KeyEventTest : public BaseTest { }; TEST_F(KeyEventTest, Properties) { KeyEvent event; // Initialize and get properties. const nsecs_t ARBITRARY_DOWN_TIME = 1; const nsecs_t ARBITRARY_EVENT_TIME = 2; event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121, AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType()); ASSERT_EQ(2, event.getDeviceId()); ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource()); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction()); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags()); ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode()); ASSERT_EQ(121, event.getScanCode()); ASSERT_EQ(AMETA_ALT_ON, event.getMetaState()); ASSERT_EQ(1, event.getRepeatCount()); ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime()); ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getEventTime()); // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); } // --- MotionEventTest --- class MotionEventTest : public BaseTest { protected: static const nsecs_t ARBITRARY_DOWN_TIME; static const nsecs_t ARBITRARY_EVENT_TIME; static const float X_OFFSET; static const float Y_OFFSET; void initializeEventWithHistory(MotionEvent* event); void assertEqualsEventWithHistory(const MotionEvent* event); }; const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1; const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2; const float MotionEventTest::X_OFFSET = 1.0f; const float MotionEventTest::Y_OFFSET = 1.1f; void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { PointerProperties pointerProperties[2]; pointerProperties[0].clear(); pointerProperties[0].id = 1; pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerProperties[1].clear(); pointerProperties[1].id = 2; pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; PointerCoords pointerCoords[2]; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18); pointerCoords[1].clear(); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128); event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228); event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); } void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { // Check properties. ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); ASSERT_EQ(2, event->getDeviceId()); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction()); ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState()); ASSERT_EQ(X_OFFSET, event->getXOffset()); ASSERT_EQ(Y_OFFSET, event->getYOffset()); ASSERT_EQ(2.0f, event->getXPrecision()); ASSERT_EQ(2.1f, event->getYPrecision()); ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime()); ASSERT_EQ(2U, event->getPointerCount()); ASSERT_EQ(1, event->getPointerId(0)); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0)); ASSERT_EQ(2, event->getPointerId(1)); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1)); ASSERT_EQ(2U, event->getHistorySize()); // Check data. ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0)); ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(211, event->getRawPointerCoords(0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(221, event->getRawPointerCoords(1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); ASSERT_EQ(10, event->getHistoricalRawX(0, 0)); ASSERT_EQ(20, event->getHistoricalRawX(1, 0)); ASSERT_EQ(110, event->getHistoricalRawX(0, 1)); ASSERT_EQ(120, event->getHistoricalRawX(1, 1)); ASSERT_EQ(210, event->getRawX(0)); ASSERT_EQ(220, event->getRawX(1)); ASSERT_EQ(11, event->getHistoricalRawY(0, 0)); ASSERT_EQ(21, event->getHistoricalRawY(1, 0)); ASSERT_EQ(111, event->getHistoricalRawY(0, 1)); ASSERT_EQ(121, event->getHistoricalRawY(1, 1)); ASSERT_EQ(211, event->getRawY(0)); ASSERT_EQ(221, event->getRawY(1)); ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0)); ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0)); ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1)); ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1)); ASSERT_EQ(X_OFFSET + 210, event->getX(0)); ASSERT_EQ(X_OFFSET + 220, event->getX(1)); ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0)); ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0)); ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1)); ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1)); ASSERT_EQ(Y_OFFSET + 211, event->getY(0)); ASSERT_EQ(Y_OFFSET + 221, event->getY(1)); ASSERT_EQ(12, event->getHistoricalPressure(0, 0)); ASSERT_EQ(22, event->getHistoricalPressure(1, 0)); ASSERT_EQ(112, event->getHistoricalPressure(0, 1)); ASSERT_EQ(122, event->getHistoricalPressure(1, 1)); ASSERT_EQ(212, event->getPressure(0)); ASSERT_EQ(222, event->getPressure(1)); ASSERT_EQ(13, event->getHistoricalSize(0, 0)); ASSERT_EQ(23, event->getHistoricalSize(1, 0)); ASSERT_EQ(113, event->getHistoricalSize(0, 1)); ASSERT_EQ(123, event->getHistoricalSize(1, 1)); ASSERT_EQ(213, event->getSize(0)); ASSERT_EQ(223, event->getSize(1)); ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0)); ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0)); ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1)); ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1)); ASSERT_EQ(214, event->getTouchMajor(0)); ASSERT_EQ(224, event->getTouchMajor(1)); ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0)); ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0)); ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1)); ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1)); ASSERT_EQ(215, event->getTouchMinor(0)); ASSERT_EQ(225, event->getTouchMinor(1)); ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0)); ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0)); ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1)); ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1)); ASSERT_EQ(216, event->getToolMajor(0)); ASSERT_EQ(226, event->getToolMajor(1)); ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0)); ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0)); ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1)); ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1)); ASSERT_EQ(217, event->getToolMinor(0)); ASSERT_EQ(227, event->getToolMinor(1)); ASSERT_EQ(18, event->getHistoricalOrientation(0, 0)); ASSERT_EQ(28, event->getHistoricalOrientation(1, 0)); ASSERT_EQ(118, event->getHistoricalOrientation(0, 1)); ASSERT_EQ(128, event->getHistoricalOrientation(1, 1)); ASSERT_EQ(218, event->getOrientation(0)); ASSERT_EQ(228, event->getOrientation(1)); } TEST_F(MotionEventTest, Properties) { MotionEvent event; // Initialize, add samples and check properties. initializeEventWithHistory(&event); ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); // Set source. event.setSource(AINPUT_SOURCE_JOYSTICK); ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); // Set action. event.setAction(AMOTION_EVENT_ACTION_CANCEL); ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction()); // Set meta state. event.setMetaState(AMETA_CTRL_ON); ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState()); } TEST_F(MotionEventTest, CopyFrom_KeepHistory) { MotionEvent event; initializeEventWithHistory(&event); MotionEvent copy; copy.copyFrom(&event, true /*keepHistory*/); ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); } TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) { MotionEvent event; initializeEventWithHistory(&event); MotionEvent copy; copy.copyFrom(&event, false /*keepHistory*/); ASSERT_EQ(event.getPointerCount(), copy.getPointerCount()); ASSERT_EQ(0U, copy.getHistorySize()); ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0)); ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1)); ASSERT_EQ(event.getEventTime(), copy.getEventTime()); ASSERT_EQ(event.getX(0), copy.getX(0)); } TEST_F(MotionEventTest, OffsetLocation) { MotionEvent event; initializeEventWithHistory(&event); event.offsetLocation(5.0f, -2.0f); ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset()); ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset()); } TEST_F(MotionEventTest, Scale) { MotionEvent event; initializeEventWithHistory(&event); event.scale(2.0f); ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); ASSERT_EQ(210 * 2, event.getRawX(0)); ASSERT_EQ(211 * 2, event.getRawY(0)); ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0)); ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0)); ASSERT_EQ(212, event.getPressure(0)); ASSERT_EQ(213, event.getSize(0)); ASSERT_EQ(214 * 2, event.getTouchMajor(0)); ASSERT_EQ(215 * 2, event.getTouchMinor(0)); ASSERT_EQ(216 * 2, event.getToolMajor(0)); ASSERT_EQ(217 * 2, event.getToolMinor(0)); ASSERT_EQ(218, event.getOrientation(0)); } TEST_F(MotionEventTest, Parcel) { Parcel parcel; MotionEvent inEvent; initializeEventWithHistory(&inEvent); MotionEvent outEvent; // Round trip. inEvent.writeToParcel(&parcel); parcel.setDataPosition(0); outEvent.readFromParcel(&parcel); ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent)); } static void setRotationMatrix(float matrix[9], float angle) { float sin = sinf(angle); float cos = cosf(angle); matrix[0] = cos; matrix[1] = -sin; matrix[2] = 0; matrix[3] = sin; matrix[4] = cos; matrix[5] = 0; matrix[6] = 0; matrix[7] = 0; matrix[8] = 1.0f; } TEST_F(MotionEventTest, Transform) { // Generate some points on a circle. // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle // of ARC * i degrees clockwise relative to the Y axis. // The geometrical representation is irrelevant to the test, it's just easy to generate // and check rotation. We set the orientation to the same angle. // Coordinate system: down is increasing Y, right is increasing X. const float PI_180 = float(M_PI / 180); const float RADIUS = 10; const float ARC = 36; const float ROTATION = ARC * 2; const size_t pointerCount = 11; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { float angle = float(i * ARC * PI_180); pointerProperties[i].clear(); pointerProperties[i].id = i; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; // Check original raw X and Y assumption. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); // Now translate the motion event so the circle's origin is at (0,0). event.offsetLocation(-3, -2); // Offsetting the location should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); // Apply a rotation about the origin by ROTATION degrees clockwise. float matrix[9]; setRotationMatrix(matrix, ROTATION * PI_180); event.transform(matrix); // Check the points. for (size_t i = 0; i < pointerCount; i++) { float angle = float((i * ARC + ROTATION) * PI_180); ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001); ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001); ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); } // Applying the transformation should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } } // namespace android libs/input/tests/InputPublisherAndConsumer_test.cpp0100644 0000000 0000000 00000027137 13077405420 021732 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "TestHelpers.h" #include #include #include #include #include #include #include #include namespace android { class InputPublisherAndConsumerTest : public testing::Test { protected: sp serverChannel, clientChannel; InputPublisher* mPublisher; InputConsumer* mConsumer; PreallocatedInputEventFactory mEventFactory; virtual void SetUp() { status_t result = InputChannel::openInputChannelPair(String8("channel name"), serverChannel, clientChannel); mPublisher = new InputPublisher(serverChannel); mConsumer = new InputConsumer(clientChannel); } virtual void TearDown() { if (mPublisher) { delete mPublisher; mPublisher = NULL; } if (mConsumer) { delete mConsumer; mConsumer = NULL; } serverChannel.clear(); clientChannel.clear(); } void PublishAndConsumeKeyEvent(); void PublishAndConsumeMotionEvent(); }; TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get()); EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get()); } void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { status_t status; const uint32_t seq = 15; const int32_t deviceId = 1; const int32_t source = AINPUT_SOURCE_KEYBOARD; const int32_t action = AKEY_EVENT_ACTION_DOWN; const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM; const int32_t keyCode = AKEYCODE_ENTER; const int32_t scanCode = 13; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; const int32_t repeatCount = 1; const nsecs_t downTime = 3; const nsecs_t eventTime = 4; status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK"; uint32_t consumeSeq; InputEvent* event; status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event); ASSERT_EQ(OK, status) << "consumer consume should return OK"; ASSERT_TRUE(event != NULL) << "consumer should have returned non-NULL event"; ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType()) << "consumer should have returned a key event"; KeyEvent* keyEvent = static_cast(event); EXPECT_EQ(seq, consumeSeq); EXPECT_EQ(deviceId, keyEvent->getDeviceId()); EXPECT_EQ(source, keyEvent->getSource()); EXPECT_EQ(action, keyEvent->getAction()); EXPECT_EQ(flags, keyEvent->getFlags()); EXPECT_EQ(keyCode, keyEvent->getKeyCode()); EXPECT_EQ(scanCode, keyEvent->getScanCode()); EXPECT_EQ(metaState, keyEvent->getMetaState()); EXPECT_EQ(repeatCount, keyEvent->getRepeatCount()); EXPECT_EQ(downTime, keyEvent->getDownTime()); EXPECT_EQ(eventTime, keyEvent->getEventTime()); status = mConsumer->sendFinishedSignal(seq, true); ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK"; uint32_t finishedSeq = 0; bool handled = false; status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled); ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK"; ASSERT_EQ(seq, finishedSeq) << "publisher receiveFinishedSignal should have returned the original sequence number"; ASSERT_TRUE(handled) << "publisher receiveFinishedSignal should have set handled to consumer's reply"; } void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { status_t status; const uint32_t seq = 15; const int32_t deviceId = 1; const int32_t source = AINPUT_SOURCE_TOUCHSCREEN; const int32_t action = AMOTION_EVENT_ACTION_MOVE; const int32_t actionButton = 0; const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY; const float xOffset = -10; const float yOffset = -20; const float xPrecision = 0.25; const float yPrecision = 0.5; const nsecs_t downTime = 3; const size_t pointerCount = 3; const nsecs_t eventTime = 4; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = (i + 2) % pointerCount; pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; uint32_t consumeSeq; InputEvent* event; status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event); ASSERT_EQ(OK, status) << "consumer consume should return OK"; ASSERT_TRUE(event != NULL) << "consumer should have returned non-NULL event"; ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()) << "consumer should have returned a motion event"; MotionEvent* motionEvent = static_cast(event); EXPECT_EQ(seq, consumeSeq); EXPECT_EQ(deviceId, motionEvent->getDeviceId()); EXPECT_EQ(source, motionEvent->getSource()); EXPECT_EQ(action, motionEvent->getAction()); EXPECT_EQ(flags, motionEvent->getFlags()); EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags()); EXPECT_EQ(metaState, motionEvent->getMetaState()); EXPECT_EQ(buttonState, motionEvent->getButtonState()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); EXPECT_EQ(0U, motionEvent->getHistorySize()); for (size_t i = 0; i < pointerCount; i++) { SCOPED_TRACE(i); EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), motionEvent->getRawX(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), motionEvent->getRawY(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset, motionEvent->getX(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset, motionEvent->getY(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); } status = mConsumer->sendFinishedSignal(seq, false); ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK"; uint32_t finishedSeq = 0; bool handled = true; status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled); ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK"; ASSERT_EQ(seq, finishedSeq) << "publisher receiveFinishedSignal should have returned the original sequence number"; ASSERT_FALSE(handled) << "publisher receiveFinishedSignal should have set handled to consumer's reply"; } TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) { status_t status; const size_t pointerCount = 0; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { status_t status; const size_t pointerCount = MAX_POINTERS + 1; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerCoords[i].clear(); } status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); } } // namespace android libs/input/tests/StructLayout_test.cpp0100644 0000000 0000000 00000005115 13077405420 017270 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include namespace android { #define CHECK_OFFSET(type, member, expected_offset) \ static_assert((offsetof(type, member) == expected_offset), "") struct Foo { uint32_t dummy; PointerCoords coords; }; void TestPointerCoordsAlignment() { CHECK_OFFSET(Foo, coords, 8); } void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage, body, 8); CHECK_OFFSET(InputMessage::Body::Key, seq, 0); CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Key, source, 20); CHECK_OFFSET(InputMessage::Body::Key, action, 24); CHECK_OFFSET(InputMessage::Body::Key, flags, 28); CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32); CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36); CHECK_OFFSET(InputMessage::Body::Key, metaState, 40); CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44); CHECK_OFFSET(InputMessage::Body::Key, downTime, 48); CHECK_OFFSET(InputMessage::Body::Motion, seq, 0); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); CHECK_OFFSET(InputMessage::Body::Motion, action, 24); CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28); CHECK_OFFSET(InputMessage::Body::Motion, flags, 32); CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36); CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40); CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44); CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48); CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56); CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60); CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 64); CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68); CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72); CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80); } } // namespace android libs/input/tests/TestHelpers.h0100644 0000000 0000000 00000003324 13077405420 015456 0ustar000000000 0000000 /* * Copyright (C) 2010 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 TESTHELPERS_H #define TESTHELPERS_H #include #include namespace android { class Pipe { public: int sendFd; int receiveFd; Pipe() { int fds[2]; ::pipe(fds); receiveFd = fds[0]; sendFd = fds[1]; } ~Pipe() { if (sendFd != -1) { ::close(sendFd); } if (receiveFd != -1) { ::close(receiveFd); } } status_t writeSignal() { ssize_t nWritten = ::write(sendFd, "*", 1); return nWritten == 1 ? 0 : -errno; } status_t readSignal() { char buf[1]; ssize_t nRead = ::read(receiveFd, buf, 1); return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno; } }; class DelayedTask : public Thread { int mDelayMillis; public: DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { } protected: virtual ~DelayedTask() { } virtual void doTask() = 0; virtual bool threadLoop() { usleep(mDelayMillis * 1000); doTask(); return false; } }; } // namespace android #endif // TESTHELPERS_H libs/ui/0040755 0000000 0000000 00000000000 13077405420 011160 5ustar000000000 0000000 libs/ui/Android.mk0100644 0000000 0000000 00000004127 13077405420 013072 0ustar000000000 0000000 # Copyright (C) 2010 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. LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror LOCAL_SANITIZE := integer # The static constructors and destructors in this library have not been noted to # introduce significant overheads LOCAL_CPPFLAGS += -Wno-exit-time-destructors LOCAL_CPPFLAGS += -Wno-global-constructors # We only care about compiling as C++14 LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic # We use four-character constants for the GraphicBuffer header, and don't care # that they're non-portable as long as they're consistent within one execution LOCAL_CPPFLAGS += -Wno-four-char-constants # Don't warn about struct padding LOCAL_CPPFLAGS += -Wno-padded LOCAL_SRC_FILES := \ Fence.cpp \ FrameStats.cpp \ GraphicBuffer.cpp \ GraphicBufferAllocator.cpp \ GraphicBufferMapper.cpp \ HdrCapabilities.cpp \ PixelFormat.cpp \ Rect.cpp \ Region.cpp \ UiConfig.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libhardware \ libsync \ libutils \ liblog ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),) LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT) endif LOCAL_MODULE := libui include $(BUILD_SHARED_LIBRARY) # Include subdirectory makefiles # ============================================================ # If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework # team really wants is to build the stuff defined by this makefile. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif libs/ui/Fence.cpp0100644 0000000 0000000 00000011434 13077405420 012704 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define LOG_TAG "Fence" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 // We would eliminate the non-conforming zero-length array, but we can't since // this is effectively included from the Linux kernel #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-length-array" #include #pragma clang diagnostic pop #include #include #include #include namespace android { const sp Fence::NO_FENCE = sp(new Fence); Fence::Fence() : mFenceFd(-1) { } Fence::Fence(int fenceFd) : mFenceFd(fenceFd) { } Fence::~Fence() { if (mFenceFd != -1) { close(mFenceFd); } } status_t Fence::wait(int timeout) { ATRACE_CALL(); if (mFenceFd == -1) { return NO_ERROR; } int err = sync_wait(mFenceFd, timeout); return err < 0 ? -errno : status_t(NO_ERROR); } status_t Fence::waitForever(const char* logname) { ATRACE_CALL(); if (mFenceFd == -1) { return NO_ERROR; } int warningTimeout = 3000; int err = sync_wait(mFenceFd, warningTimeout); if (err < 0 && errno == ETIME) { ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd, warningTimeout); err = sync_wait(mFenceFd, TIMEOUT_NEVER); } return err < 0 ? -errno : status_t(NO_ERROR); } sp Fence::merge(const String8& name, const sp& f1, const sp& f2) { ATRACE_CALL(); int result; // Merge the two fences. In the case where one of the fences is not a // valid fence (e.g. NO_FENCE) we merge the one valid fence with itself so // that a new fence with the given name is created. if (f1->isValid() && f2->isValid()) { result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd); } else if (f1->isValid()) { result = sync_merge(name.string(), f1->mFenceFd, f1->mFenceFd); } else if (f2->isValid()) { result = sync_merge(name.string(), f2->mFenceFd, f2->mFenceFd); } else { return NO_FENCE; } if (result == -1) { status_t err = -errno; ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", name.string(), f1->mFenceFd, f2->mFenceFd, strerror(-err), err); return NO_FENCE; } return sp(new Fence(result)); } int Fence::dup() const { return ::dup(mFenceFd); } nsecs_t Fence::getSignalTime() const { if (mFenceFd == -1) { return -1; } struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd); if (finfo == NULL) { ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd); return -1; } if (finfo->status != 1) { sync_fence_info_free(finfo); return INT64_MAX; } struct sync_pt_info* pinfo = NULL; uint64_t timestamp = 0; while ((pinfo = sync_pt_info(finfo, pinfo)) != NULL) { if (pinfo->timestamp_ns > timestamp) { timestamp = pinfo->timestamp_ns; } } sync_fence_info_free(finfo); return nsecs_t(timestamp); } size_t Fence::getFlattenedSize() const { return 4; } size_t Fence::getFdCount() const { return isValid() ? 1 : 0; } status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { if (size < getFlattenedSize() || count < getFdCount()) { return NO_MEMORY; } // Cast to uint32_t since the size of a size_t can vary between 32- and // 64-bit processes FlattenableUtils::write(buffer, size, static_cast(getFdCount())); if (isValid()) { *fds++ = mFenceFd; count--; } return NO_ERROR; } status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (mFenceFd != -1) { // Don't unflatten if we already have a valid fd. return INVALID_OPERATION; } if (size < 1) { return NO_MEMORY; } uint32_t numFds; FlattenableUtils::read(buffer, size, numFds); if (numFds > 1) { return BAD_VALUE; } if (count < numFds) { return NO_MEMORY; } if (numFds) { mFenceFd = *fds++; count--; } return NO_ERROR; } } // namespace android libs/ui/FrameStats.cpp0100644 0000000 0000000 00000005031 13077405420 013731 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace android { bool FrameStats::isFixedSize() const { return false; } size_t FrameStats::getFlattenedSize() const { const size_t timestampSize = sizeof(nsecs_t); size_t size = timestampSize; size += 3 * desiredPresentTimesNano.size() * timestampSize; return size; } status_t FrameStats::flatten(void* buffer, size_t size) const { if (size < getFlattenedSize()) { return NO_MEMORY; } nsecs_t* timestamps = reinterpret_cast(buffer); const size_t timestampSize = sizeof(nsecs_t); size_t frameCount = desiredPresentTimesNano.size(); memcpy(timestamps, &refreshPeriodNano, timestampSize); timestamps += 1; memcpy(timestamps, desiredPresentTimesNano.array(), frameCount * timestampSize); timestamps += frameCount; memcpy(timestamps, actualPresentTimesNano.array(), frameCount * timestampSize); timestamps += frameCount; memcpy(timestamps, frameReadyTimesNano.array(), frameCount * timestampSize); return NO_ERROR; } status_t FrameStats::unflatten(void const* buffer, size_t size) { const size_t timestampSize = sizeof(nsecs_t); if (size < timestampSize) { return NO_MEMORY; } nsecs_t const* timestamps = reinterpret_cast(buffer); size_t frameCount = (size - timestampSize) / (3 * timestampSize); memcpy(&refreshPeriodNano, timestamps, timestampSize); timestamps += 1; desiredPresentTimesNano.resize(frameCount); memcpy(desiredPresentTimesNano.editArray(), timestamps, frameCount * timestampSize); timestamps += frameCount; actualPresentTimesNano.resize(frameCount); memcpy(actualPresentTimesNano.editArray(), timestamps, frameCount * timestampSize); timestamps += frameCount; frameReadyTimesNano.resize(frameCount); memcpy(frameReadyTimesNano.editArray(), timestamps, frameCount * timestampSize); return NO_ERROR; } } // namespace android libs/ui/GraphicBuffer.cpp0100644 0000000 0000000 00000031126 13077405420 014373 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "GraphicBuffer" #include #include #include #include #include #include #include #include #include namespace android { // =========================================================================== // Buffer and implementation of ANativeWindowBuffer // =========================================================================== static uint64_t getUniqueId() { static volatile int32_t nextId = 0; uint64_t id = static_cast(getpid()) << 32; id |= static_cast(android_atomic_inc(&nextId)); return id; } GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = height = stride = format = usage = 0; handle = NULL; } GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = height = stride = format = usage = 0; handle = NULL; mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage); } GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) { width = static_cast(inWidth); height = static_cast(inHeight); stride = static_cast(inStride); format = inFormat; usage = static_cast(inUsage); handle = inHandle; } GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()), mGenerationNumber(0) { width = buffer->width; height = buffer->height; stride = buffer->stride; format = buffer->format; usage = buffer->usage; handle = buffer->handle; } GraphicBuffer::~GraphicBuffer() { if (handle) { free_handle(); } } void GraphicBuffer::free_handle() { if (mOwner == ownHandle) { mBufferMapper.unregisterBuffer(handle); native_handle_close(handle); native_handle_delete(const_cast(handle)); } else if (mOwner == ownData) { GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); } handle = NULL; mWrappedBuffer = 0; } status_t GraphicBuffer::initCheck() const { return static_cast(mInitCheck); } void GraphicBuffer::dumpAllocationsToSystemLog() { GraphicBufferAllocator::dumpToSystemLog(); } ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const { LOG_ALWAYS_FATAL_IF(this == NULL, "getNativeBuffer() called on NULL GraphicBuffer"); return static_cast( const_cast(this)); } status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) { if (mOwner != ownData) return INVALID_OPERATION; if (handle && static_cast(inWidth) == width && static_cast(inHeight) == height && inFormat == format && static_cast(inUsage) == usage) return NO_ERROR; if (handle) { GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); handle = 0; } return initSize(inWidth, inHeight, inFormat, inUsage); } bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) { if (static_cast(inWidth) != width) return true; if (static_cast(inHeight) != height) return true; if (inFormat != format) return true; if ((static_cast(usage) & inUsage) != inUsage) return true; return false; } status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage) { GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); uint32_t outStride = 0; status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage, &handle, &outStride); if (err == NO_ERROR) { width = static_cast(inWidth); height = static_cast(inHeight); format = inFormat; usage = static_cast(inUsage); stride = static_cast(outStride); } return err; } status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr) { const Rect lockBounds(width, height); status_t res = lock(inUsage, lockBounds, vaddr); return res; } status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr) { if (rect.left < 0 || rect.right > width || rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, width, height); return BAD_VALUE; } status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr); return res; } status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, android_ycbcr* ycbcr) { const Rect lockBounds(width, height); status_t res = lockYCbCr(inUsage, lockBounds, ycbcr); return res; } status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, const Rect& rect, android_ycbcr* ycbcr) { if (rect.left < 0 || rect.right > width || rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, width, height); return BAD_VALUE; } status_t res = getBufferMapper().lockYCbCr(handle, inUsage, rect, ycbcr); return res; } status_t GraphicBuffer::unlock() { status_t res = getBufferMapper().unlock(handle); return res; } status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd) { const Rect lockBounds(width, height); status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd); return res; } status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd) { if (rect.left < 0 || rect.right > width || rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, width, height); return BAD_VALUE; } status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr, fenceFd); return res; } status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, android_ycbcr* ycbcr, int fenceFd) { const Rect lockBounds(width, height); status_t res = lockAsyncYCbCr(inUsage, lockBounds, ycbcr, fenceFd); return res; } status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, android_ycbcr* ycbcr, int fenceFd) { if (rect.left < 0 || rect.right > width || rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, width, height); return BAD_VALUE; } status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, ycbcr, fenceFd); return res; } status_t GraphicBuffer::unlockAsync(int *fenceFd) { status_t res = getBufferMapper().unlockAsync(handle, fenceFd); return res; } size_t GraphicBuffer::getFlattenedSize() const { return static_cast(11 + (handle ? handle->numInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { return static_cast(handle ? handle->numFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { size_t sizeNeeded = GraphicBuffer::getFlattenedSize(); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = GraphicBuffer::getFdCount(); if (count < fdCountNeeded) return NO_MEMORY; int32_t* buf = static_cast(buffer); buf[0] = 'GBFR'; buf[1] = width; buf[2] = height; buf[3] = stride; buf[4] = format; buf[5] = usage; buf[6] = static_cast(mId >> 32); buf[7] = static_cast(mId & 0xFFFFFFFFull); buf[8] = static_cast(mGenerationNumber); buf[9] = 0; buf[10] = 0; if (handle) { buf[9] = handle->numFds; buf[10] = handle->numInts; memcpy(fds, handle->data, static_cast(handle->numFds) * sizeof(int)); memcpy(&buf[11], handle->data + handle->numFds, static_cast(handle->numInts) * sizeof(int)); } buffer = static_cast(static_cast(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { fds += handle->numFds; count -= static_cast(handle->numFds); } return NO_ERROR; } status_t GraphicBuffer::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (size < 11 * sizeof(int)) return NO_MEMORY; int const* buf = static_cast(buffer); if (buf[0] != 'GBFR') return BAD_TYPE; const size_t numFds = static_cast(buf[9]); const size_t numInts = static_cast(buf[10]); // Limit the maxNumber to be relatively small. The number of fds or ints // should not come close to this number, and the number itself was simply // chosen to be high enough to not cause issues and low enough to prevent // overflow problems. const size_t maxNumber = 4096; if (numFds >= maxNumber || numInts >= (maxNumber - 11)) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts); return BAD_VALUE; } const size_t sizeNeeded = (11 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = numFds; if (count < fdCountNeeded) return NO_MEMORY; if (handle) { // free previous handle if any free_handle(); } if (numFds || numInts) { width = buf[1]; height = buf[2]; stride = buf[3]; format = buf[4]; usage = buf[5]; native_handle* h = native_handle_create( static_cast(numFds), static_cast(numInts)); if (!h) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: native_handle_create failed"); return NO_MEMORY; } memcpy(h->data, fds, numFds * sizeof(int)); memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; handle = NULL; } mId = static_cast(buf[6]) << 32; mId |= static_cast(buf[7]); mGenerationNumber = static_cast(buf[8]); mOwner = ownHandle; if (handle != 0) { status_t err = mBufferMapper.registerBuffer(handle); if (err != NO_ERROR) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err); return err; } } buffer = static_cast(static_cast(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; count -= numFds; return NO_ERROR; } // --------------------------------------------------------------------------- }; // namespace android libs/ui/GraphicBufferAllocator.cpp0100644 0000000 0000000 00000011403 13077405420 016230 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ #define LOG_TAG "GraphicBufferAllocator" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator ) Mutex GraphicBufferAllocator::sLock; KeyedVector GraphicBufferAllocator::sAllocList; GraphicBufferAllocator::GraphicBufferAllocator() : mAllocDev(0) { hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { gralloc_open(module, &mAllocDev); } } GraphicBufferAllocator::~GraphicBufferAllocator() { gralloc_close(mAllocDev); } void GraphicBufferAllocator::dump(String8& result) const { Mutex::Autolock _l(sLock); KeyedVector& list(sAllocList); size_t total = 0; const size_t SIZE = 4096; char buffer[SIZE]; snprintf(buffer, SIZE, "Allocated buffers:\n"); result.append(buffer); const size_t c = list.size(); for (size_t i=0 ; icommon.version >= 1 && mAllocDev->dump) { mAllocDev->dump(mAllocDev, buffer, SIZE); result.append(buffer); } } void GraphicBufferAllocator::dumpToSystemLog() { String8 s; GraphicBufferAllocator::getInstance().dump(s); ALOGD("%s", s.string()); } status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, buffer_handle_t* handle, uint32_t* stride) { ATRACE_CALL(); // make sure to not allocate a N x 0 or 0 x N buffer, since this is // allowed from an API stand-point allocate a 1x1 buffer instead. if (!width || !height) width = height = 1; // we have a h/w allocator and h/w buffer is requested status_t err; // Filter out any usage bits that should not be passed to the gralloc module usage &= GRALLOC_USAGE_ALLOC_MASK; int outStride = 0; err = mAllocDev->alloc(mAllocDev, static_cast(width), static_cast(height), format, static_cast(usage), handle, &outStride); *stride = static_cast(outStride); ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", width, height, format, usage, err, strerror(-err)); if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector& list(sAllocList); uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; rec.width = width; rec.height = height; rec.stride = *stride; rec.format = format; rec.usage = usage; rec.size = static_cast(height * (*stride) * bpp); list.add(*handle, rec); } return err; } status_t GraphicBufferAllocator::free(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocDev->free(mAllocDev, handle); ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err)); if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector& list(sAllocList); list.removeItem(handle); } return err; } // --------------------------------------------------------------------------- }; // namespace android libs/ui/GraphicBufferMapper.cpp0100644 0000000 0000000 00000013341 13077405420 015537 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "GraphicBufferMapper" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include // We would eliminate the non-conforming zero-length array, but we can't since // this is effectively included from the Linux kernel #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-length-array" #include #pragma clang diagnostic pop #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper ) GraphicBufferMapper::GraphicBufferMapper() : mAllocMod(0) { hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { mAllocMod = reinterpret_cast(module); } } status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocMod->registerBuffer(mAllocMod, handle); ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)", handle, err, strerror(-err)); return err; } status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocMod->unregisterBuffer(mAllocMod, handle); ALOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)", handle, err, strerror(-err)); return err; } status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr) { ATRACE_CALL(); status_t err; err = mAllocMod->lock(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err)); return err; } status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr) { ATRACE_CALL(); status_t err; if (mAllocMod->lock_ycbcr == NULL) { return -EINVAL; // do not log failure } err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err)); return err; } status_t GraphicBufferMapper::unlock(buffer_handle_t handle) { ATRACE_CALL(); status_t err; err = mAllocMod->unlock(mAllocMod, handle); ALOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err)); return err; } status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) { err = mAllocMod->lockAsync(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else { if (fenceFd >= 0) { sync_wait(fenceFd, -1); close(fenceFd); } err = mAllocMod->lock(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); } ALOGW_IF(err, "lockAsync(...) failed %d (%s)", err, strerror(-err)); return err; } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3 && mAllocMod->lockAsync_ycbcr != NULL) { err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr, fenceFd); } else if (mAllocMod->lock_ycbcr != NULL) { if (fenceFd >= 0) { sync_wait(fenceFd, -1); close(fenceFd); } err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); } else { if (fenceFd >= 0) { close(fenceFd); } return -EINVAL; // do not log failure } ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err)); return err; } status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) { err = mAllocMod->unlockAsync(mAllocMod, handle, fenceFd); } else { *fenceFd = -1; err = mAllocMod->unlock(mAllocMod, handle); } ALOGW_IF(err, "unlockAsync(...) failed %d (%s)", err, strerror(-err)); return err; } // --------------------------------------------------------------------------- }; // namespace android libs/ui/HdrCapabilities.cpp0100644 0000000 0000000 00000003163 13077405420 014713 0ustar000000000 0000000 /* * Copyright 2016 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 #include namespace android { status_t HdrCapabilities::writeToParcel(Parcel* parcel) const { status_t result = parcel->writeInt32Vector(mSupportedHdrTypes); if (result != OK) { return result; } result = parcel->writeFloat(mMaxLuminance); if (result != OK) { return result; } result = parcel->writeFloat(mMaxAverageLuminance); if (result != OK) { return result; } result = parcel->writeFloat(mMinLuminance); return result; } status_t HdrCapabilities::readFromParcel(const Parcel* parcel) { status_t result = parcel->readInt32Vector(&mSupportedHdrTypes); if (result != OK) { return result; } result = parcel->readFloat(&mMaxLuminance); if (result != OK) { return result; } result = parcel->readFloat(&mMaxAverageLuminance); if (result != OK) { return result; } result = parcel->readFloat(&mMinLuminance); return result; } } // namespace android libs/ui/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 014300 0ustar000000000 0000000 libs/ui/NOTICE0100644 0000000 0000000 00000024707 13077405420 012073 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS libs/ui/PixelFormat.cpp0100644 0000000 0000000 00000003457 13077405420 014124 0ustar000000000 0000000 /* * Copyright (C) 2007 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 // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- uint32_t bytesPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_BGRA_8888: return 4; case PIXEL_FORMAT_RGB_888: return 3; case PIXEL_FORMAT_RGB_565: case PIXEL_FORMAT_RGBA_5551: case PIXEL_FORMAT_RGBA_4444: return 2; } return 0; } uint32_t bitsPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_BGRA_8888: return 32; case PIXEL_FORMAT_RGB_888: return 24; case PIXEL_FORMAT_RGB_565: case PIXEL_FORMAT_RGBA_5551: case PIXEL_FORMAT_RGBA_4444: return 16; } return 0; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- libs/ui/Rect.cpp0100644 0000000 0000000 00000007643 13077405420 012570 0ustar000000000 0000000 /* * Copyright (C) 2009 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 #include namespace android { const Rect Rect::INVALID_RECT{0, 0, -1, -1}; const Rect Rect::EMPTY_RECT{0, 0, 0, 0}; static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; } static inline int32_t max(int32_t a, int32_t b) { return (a > b) ? a : b; } void Rect::makeInvalid() { left = 0; top = 0; right = -1; bottom = -1; } bool Rect::operator <(const Rect& rhs) const { if (top < rhs.top) { return true; } else if (top == rhs.top) { if (left < rhs.left) { return true; } else if (left == rhs.left) { if (bottom < rhs.bottom) { return true; } else if (bottom == rhs.bottom) { if (right < rhs.right) { return true; } } } } return false; } Rect& Rect::offsetTo(int32_t x, int32_t y) { right -= left - x; bottom -= top - y; left = x; top = y; return *this; } Rect& Rect::offsetBy(int32_t x, int32_t y) { left += x; top += y; right += x; bottom += y; return *this; } const Rect Rect::operator +(const Point& rhs) const { const Rect result(left + rhs.x, top + rhs.y, right + rhs.x, bottom + rhs.y); return result; } const Rect Rect::operator -(const Point& rhs) const { const Rect result(left - rhs.x, top - rhs.y, right - rhs.x, bottom - rhs.y); return result; } bool Rect::intersect(const Rect& with, Rect* result) const { result->left = max(left, with.left); result->top = max(top, with.top); result->right = min(right, with.right); result->bottom = min(bottom, with.bottom); return !(result->isEmpty()); } Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) const { Rect result(*this); if (xform & HAL_TRANSFORM_FLIP_H) { result = Rect(width - result.right, result.top, width - result.left, result.bottom); } if (xform & HAL_TRANSFORM_FLIP_V) { result = Rect(result.left, height - result.bottom, result.right, height - result.top); } if (xform & HAL_TRANSFORM_ROT_90) { int left = height - result.bottom; int top = result.left; int right = height - result.top; int bottom = result.right; result = Rect(left, top, right, bottom); } return result; } Rect Rect::reduce(const Rect& exclude) const { Rect result(Rect::EMPTY_RECT); uint32_t mask = 0; mask |= (exclude.left > left) ? 1 : 0; mask |= (exclude.top > top) ? 2 : 0; mask |= (exclude.right < right) ? 4 : 0; mask |= (exclude.bottom < bottom) ? 8 : 0; if (mask == 0) { // crop entirely covers us result.clear(); } else { result = *this; if (!(mask & (mask - 1))) { // power-of-2, i.e.: just one bit is set if (mask & 1) { result.right = min(result.right, exclude.left); } else if (mask & 2) { result.bottom = min(result.bottom, exclude.top); } else if (mask & 4) { result.left = max(result.left, exclude.right); } else if (mask & 8) { result.top = max(result.top, exclude.bottom); } } } return result; } }; // namespace android libs/ui/Region.cpp0100644 0000000 0000000 00000063300 13077405420 013106 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define LOG_TAG "Region" #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- #define VALIDATE_REGIONS (false) #define VALIDATE_WITH_CORECG (false) // ---------------------------------------------------------------------------- #if VALIDATE_WITH_CORECG #include #endif namespace android { // ---------------------------------------------------------------------------- enum { op_nand = region_operator::op_nand, op_and = region_operator::op_and, op_or = region_operator::op_or, op_xor = region_operator::op_xor }; enum { direction_LTR, direction_RTL }; const Region Region::INVALID_REGION(Rect::INVALID_RECT); // ---------------------------------------------------------------------------- Region::Region() { mStorage.add(Rect(0,0)); } Region::Region(const Region& rhs) : mStorage(rhs.mStorage) { #if VALIDATE_REGIONS validate(rhs, "rhs copy-ctor"); #endif } Region::Region(const Rect& rhs) { mStorage.add(rhs); } Region::~Region() { } /** * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way * * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be * compared with the span directly below, and subdivided as needed to resolve T-junctions. * * The resulting temporary vector will be a completely reversed copy of the original, without any * bottom-up T-junctions. * * Second pass through, divideSpanRTL will be false since the previous span will index into the * final, correctly ordered region buffer. Each rectangle will be compared with the span directly * above it, and subdivided to resolve any remaining T-junctions. */ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, Vector& dst, int spanDirection) { dst.clear(); const Rect* current = end - 1; int lastTop = current->top; // add first span immediately do { dst.add(*current); current--; } while (current->top == lastTop && current >= begin); int beginLastSpan = -1; int endLastSpan = -1; int top = -1; int bottom = -1; // for all other spans, split if a t-junction exists in the span directly above while (current >= begin) { if (current->top != (current + 1)->top) { // new span if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) || (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) { // previous span not directly adjacent, don't check for T junctions beginLastSpan = INT_MAX; } else { beginLastSpan = endLastSpan + 1; } endLastSpan = static_cast(dst.size()) - 1; top = current->top; bottom = current->bottom; } int left = current->left; int right = current->right; for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { // prevIndex can't be -1 here because if endLastSpan is set to a // value greater than -1 (allowing the loop to execute), // beginLastSpan (and therefore prevIndex) will also be increased const Rect prev = dst[static_cast(prevIndex)]; if (spanDirection == direction_RTL) { // iterating over previous span RTL, quit if it's too far left if (prev.right <= left) break; if (prev.right > left && prev.right < right) { dst.add(Rect(prev.right, top, right, bottom)); right = prev.right; } if (prev.left > left && prev.left < right) { dst.add(Rect(prev.left, top, right, bottom)); right = prev.left; } // if an entry in the previous span is too far right, nothing further left in the // current span will need it if (prev.left >= right) { beginLastSpan = prevIndex; } } else { // iterating over previous span LTR, quit if it's too far right if (prev.left >= right) break; if (prev.left > left && prev.left < right) { dst.add(Rect(left, top, prev.left, bottom)); left = prev.left; } if (prev.right > left && prev.right < right) { dst.add(Rect(left, top, prev.right, bottom)); left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the // current span will need it if (prev.right <= left) { beginLastSpan = prevIndex; } } } if (left < right) { dst.add(Rect(left, top, right, bottom)); } current--; } } /** * Creates a new region with the same data as the argument, but divides rectangles as necessary to * remove T-Junctions * * Note: the output will not necessarily be a very efficient representation of the region, since it * may be that a triangle-based approach would generate significantly simpler geometry */ Region Region::createTJunctionFreeRegion(const Region& r) { if (r.isEmpty()) return r; if (r.isRect()) return r; Vector reversed; reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); Region outputRegion; reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), outputRegion.mStorage, direction_LTR); outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds #if VALIDATE_REGIONS validate(outputRegion, "T-Junction free region"); #endif return outputRegion; } Region& Region::operator = (const Region& rhs) { #if VALIDATE_REGIONS validate(*this, "this->operator="); validate(rhs, "rhs.operator="); #endif mStorage = rhs.mStorage; return *this; } Region& Region::makeBoundsSelf() { if (mStorage.size() >= 2) { const Rect bounds(getBounds()); mStorage.clear(); mStorage.add(bounds); } return *this; } bool Region::contains(const Point& point) const { return contains(point.x, point.y); } bool Region::contains(int x, int y) const { const_iterator cur = begin(); const_iterator const tail = end(); while (cur != tail) { if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) { return true; } cur++; } return false; } void Region::clear() { mStorage.clear(); mStorage.add(Rect(0,0)); } void Region::set(const Rect& r) { mStorage.clear(); mStorage.add(r); } void Region::set(int32_t w, int32_t h) { mStorage.clear(); mStorage.add(Rect(w, h)); } void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); mStorage.add(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { return begin() == region.begin(); } // ---------------------------------------------------------------------------- void Region::addRectUnchecked(int l, int t, int r, int b) { Rect rect(l,t,r,b); size_t where = mStorage.size() - 1; mStorage.insertAt(rect, where, 1); } // ---------------------------------------------------------------------------- Region& Region::orSelf(const Rect& r) { return operationSelf(r, op_or); } Region& Region::xorSelf(const Rect& r) { return operationSelf(r, op_xor); } Region& Region::andSelf(const Rect& r) { return operationSelf(r, op_and); } Region& Region::subtractSelf(const Rect& r) { return operationSelf(r, op_nand); } Region& Region::operationSelf(const Rect& r, int op) { Region lhs(*this); boolean_operation(op, *this, lhs, r); return *this; } // ---------------------------------------------------------------------------- Region& Region::orSelf(const Region& rhs) { return operationSelf(rhs, op_or); } Region& Region::xorSelf(const Region& rhs) { return operationSelf(rhs, op_xor); } Region& Region::andSelf(const Region& rhs) { return operationSelf(rhs, op_and); } Region& Region::subtractSelf(const Region& rhs) { return operationSelf(rhs, op_nand); } Region& Region::operationSelf(const Region& rhs, int op) { Region lhs(*this); boolean_operation(op, *this, lhs, rhs); return *this; } Region& Region::translateSelf(int x, int y) { if (x|y) translate(*this, x, y); return *this; } // ---------------------------------------------------------------------------- const Region Region::merge(const Rect& rhs) const { return operation(rhs, op_or); } const Region Region::mergeExclusive(const Rect& rhs) const { return operation(rhs, op_xor); } const Region Region::intersect(const Rect& rhs) const { return operation(rhs, op_and); } const Region Region::subtract(const Rect& rhs) const { return operation(rhs, op_nand); } const Region Region::operation(const Rect& rhs, int op) const { Region result; boolean_operation(op, result, *this, rhs); return result; } // ---------------------------------------------------------------------------- const Region Region::merge(const Region& rhs) const { return operation(rhs, op_or); } const Region Region::mergeExclusive(const Region& rhs) const { return operation(rhs, op_xor); } const Region Region::intersect(const Region& rhs) const { return operation(rhs, op_and); } const Region Region::subtract(const Region& rhs) const { return operation(rhs, op_nand); } const Region Region::operation(const Region& rhs, int op) const { Region result; boolean_operation(op, result, *this, rhs); return result; } const Region Region::translate(int x, int y) const { Region result; translate(result, *this, x, y); return result; } // ---------------------------------------------------------------------------- Region& Region::orSelf(const Region& rhs, int dx, int dy) { return operationSelf(rhs, dx, dy, op_or); } Region& Region::xorSelf(const Region& rhs, int dx, int dy) { return operationSelf(rhs, dx, dy, op_xor); } Region& Region::andSelf(const Region& rhs, int dx, int dy) { return operationSelf(rhs, dx, dy, op_and); } Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { return operationSelf(rhs, dx, dy, op_nand); } Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) { Region lhs(*this); boolean_operation(op, *this, lhs, rhs, dx, dy); return *this; } // ---------------------------------------------------------------------------- const Region Region::merge(const Region& rhs, int dx, int dy) const { return operation(rhs, dx, dy, op_or); } const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { return operation(rhs, dx, dy, op_xor); } const Region Region::intersect(const Region& rhs, int dx, int dy) const { return operation(rhs, dx, dy, op_and); } const Region Region::subtract(const Region& rhs, int dx, int dy) const { return operation(rhs, dx, dy, op_nand); } const Region Region::operation(const Region& rhs, int dx, int dy, int op) const { Region result; boolean_operation(op, result, *this, rhs, dx, dy); return result; } // ---------------------------------------------------------------------------- // This is our region rasterizer, which merges rects and spans together // to obtain an optimal region. class Region::rasterizer : public region_operator::region_rasterizer { Rect bounds; Vector& storage; Rect* head; Rect* tail; Vector span; Rect* cur; public: rasterizer(Region& reg) : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { storage.clear(); } virtual ~rasterizer(); virtual void operator()(const Rect& rect); private: template static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } template static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } void flushSpan(); }; Region::rasterizer::~rasterizer() { if (span.size()) { flushSpan(); } if (storage.size()) { bounds.top = storage.itemAt(0).top; bounds.bottom = storage.top().bottom; if (storage.size() == 1) { storage.clear(); } } else { bounds.left = 0; bounds.right = 0; } storage.add(bounds); } void Region::rasterizer::operator()(const Rect& rect) { //ALOGD(">>> %3d, %3d, %3d, %3d", // rect.left, rect.top, rect.right, rect.bottom); if (span.size()) { if (cur->top != rect.top) { flushSpan(); } else if (cur->right == rect.left) { cur->right = rect.right; return; } } span.add(rect); cur = span.editArray() + (span.size() - 1); } void Region::rasterizer::flushSpan() { bool merge = false; if (tail-head == ssize_t(span.size())) { Rect const* p = span.editArray(); Rect const* q = head; if (p->top == q->bottom) { merge = true; while (q != tail) { if ((p->left != q->left) || (p->right != q->right)) { merge = false; break; } p++, q++; } } } if (merge) { const int bottom = span[0].bottom; Rect* r = head; while (r != tail) { r->bottom = bottom; r++; } } else { bounds.left = min(span.itemAt(0).left, bounds.left); bounds.right = max(span.top().right, bounds.right); storage.appendVector(span); tail = storage.editArray() + storage.size(); head = tail - span.size(); } span.clear(); } bool Region::validate(const Region& reg, const char* name, bool silent) { bool result = true; const_iterator cur = reg.begin(); const_iterator const tail = reg.end(); const_iterator prev = cur; Rect b(*prev); while (cur != tail) { if (cur->isValid() == false) { // We allow this particular flavor of invalid Rect, since it is used // as a signal value in various parts of the system if (*cur != Rect::INVALID_RECT) { ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); result = false; } } if (cur->right > region_operator::max_value) { ALOGE_IF(!silent, "%s: rect->right > max_value", name); result = false; } if (cur->bottom > region_operator::max_value) { ALOGE_IF(!silent, "%s: rect->right > max_value", name); result = false; } if (prev != cur) { b.left = b.left < cur->left ? b.left : cur->left; b.top = b.top < cur->top ? b.top : cur->top; b.right = b.right > cur->right ? b.right : cur->right; b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; if ((*prev < *cur) == false) { ALOGE_IF(!silent, "%s: region's Rects not sorted", name); result = false; } if (cur->top == prev->top) { if (cur->bottom != prev->bottom) { ALOGE_IF(!silent, "%s: invalid span %p", name, cur); result = false; } else if (cur->left < prev->right) { ALOGE_IF(!silent, "%s: spans overlap horizontally prev=%p, cur=%p", name, prev, cur); result = false; } } else if (cur->top < prev->bottom) { ALOGE_IF(!silent, "%s: spans overlap vertically prev=%p, cur=%p", name, prev, cur); result = false; } prev = cur; } cur++; } if (b != reg.getBounds()) { result = false; ALOGE_IF(!silent, "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, b.left, b.top, b.right, b.bottom, reg.getBounds().left, reg.getBounds().top, reg.getBounds().right, reg.getBounds().bottom); } if (reg.mStorage.size() == 2) { result = false; ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name); } if (result == false && !silent) { reg.dump(name); CallStack stack(LOG_TAG); } return result; } void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Region& rhs, int dx, int dy) { #if VALIDATE_REGIONS validate(lhs, "boolean_operation (before): lhs"); validate(rhs, "boolean_operation (before): rhs"); validate(dst, "boolean_operation (before): dst"); #endif size_t lhs_count; Rect const * const lhs_rects = lhs.getArray(&lhs_count); size_t rhs_count; Rect const * const rhs_rects = rhs.getArray(&rhs_count); region_operator::region lhs_region(lhs_rects, lhs_count); region_operator::region rhs_region(rhs_rects, rhs_count, dx, dy); region_operator operation(op, lhs_region, rhs_region); { // scope for rasterizer (dtor has side effects) rasterizer r(dst); operation(r); } #if VALIDATE_REGIONS validate(lhs, "boolean_operation: lhs"); validate(rhs, "boolean_operation: rhs"); validate(dst, "boolean_operation: dst"); #endif #if VALIDATE_WITH_CORECG SkRegion sk_lhs; SkRegion sk_rhs; SkRegion sk_dst; for (size_t i=0 ; ileft != it.rect().fLeft || head->top != it.rect().fTop || head->right != it.rect().fRight || head->bottom != it.rect().fBottom ) { same = false; break; } } else { same = false; break; } head++; it.next(); } if (head != tail) { same = false; } if(!same) { ALOGD("---\nregion boolean %s failed", name); lhs.dump("lhs"); rhs.dump("rhs"); dst.dump("dst"); ALOGD("should be"); SkRegion::Iterator it(sk_dst); while (!it.done()) { ALOGD(" [%3d, %3d, %3d, %3d]", it.rect().fLeft, it.rect().fTop, it.rect().fRight, it.rect().fBottom); it.next(); } } #endif } void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs, int dx, int dy) { // We allow this particular flavor of invalid Rect, since it is used as a // signal value in various parts of the system if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", op, rhs.left, rhs.top, rhs.right, rhs.bottom); return; } #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS boolean_operation(op, dst, lhs, Region(rhs), dx, dy); #else size_t lhs_count; Rect const * const lhs_rects = lhs.getArray(&lhs_count); region_operator::region lhs_region(lhs_rects, lhs_count); region_operator::region rhs_region(&rhs, 1, dx, dy); region_operator operation(op, lhs_region, rhs_region); { // scope for rasterizer (dtor has side effects) rasterizer r(dst); operation(r); } #endif } void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Region& rhs) { boolean_operation(op, dst, lhs, rhs, 0, 0); } void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs) { boolean_operation(op, dst, lhs, rhs, 0, 0); } void Region::translate(Region& reg, int dx, int dy) { if ((dx || dy) && !reg.isEmpty()) { #if VALIDATE_REGIONS validate(reg, "translate (before)"); #endif size_t count = reg.mStorage.size(); Rect* rects = reg.mStorage.editArray(); while (count) { rects->offsetBy(dx, dy); rects++; count--; } #if VALIDATE_REGIONS validate(reg, "translate (after)"); #endif } } void Region::translate(Region& dst, const Region& reg, int dx, int dy) { dst = reg; translate(dst, dx, dy); } // ---------------------------------------------------------------------------- size_t Region::getFlattenedSize() const { return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); } status_t Region::flatten(void* buffer, size_t size) const { #if VALIDATE_REGIONS validate(*this, "Region::flatten"); #endif if (size < getFlattenedSize()) { return NO_MEMORY; } // Cast to uint32_t since the size of a size_t can vary between 32- and // 64-bit processes FlattenableUtils::write(buffer, size, static_cast(mStorage.size())); for (auto rect : mStorage) { status_t result = rect.flatten(buffer, size); if (result != NO_ERROR) { return result; } FlattenableUtils::advance(buffer, size, sizeof(rect)); } return NO_ERROR; } status_t Region::unflatten(void const* buffer, size_t size) { if (size < sizeof(uint32_t)) { return NO_MEMORY; } uint32_t numRects = 0; FlattenableUtils::read(buffer, size, numRects); if (size < numRects * sizeof(Rect)) { return NO_MEMORY; } if (numRects > (UINT32_MAX / sizeof(Rect))) { android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); return NO_MEMORY; } Region result; result.mStorage.clear(); for (size_t r = 0; r < numRects; ++r) { Rect rect(Rect::EMPTY_RECT); status_t status = rect.unflatten(buffer, size); if (status != NO_ERROR) { return status; } FlattenableUtils::advance(buffer, size, sizeof(rect)); result.mStorage.push_back(rect); } #if VALIDATE_REGIONS validate(result, "Region::unflatten"); #endif if (!result.validate(result, "Region::unflatten", true)) { ALOGE("Region::unflatten() failed, invalid region"); return BAD_VALUE; } mStorage = result.mStorage; return NO_ERROR; } // ---------------------------------------------------------------------------- Region::const_iterator Region::begin() const { return mStorage.array(); } Region::const_iterator Region::end() const { size_t numRects = isRect() ? 1 : mStorage.size() - 1; return mStorage.array() + numRects; } Rect const* Region::getArray(size_t* count) const { if (count) *count = static_cast(end() - begin()); return begin(); } // ---------------------------------------------------------------------------- void Region::dump(String8& out, const char* what, uint32_t /* flags */) const { const_iterator head = begin(); const_iterator const tail = end(); out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head); while (head != tail) { out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right, head->bottom); ++head; } } void Region::dump(const char* what, uint32_t /* flags */) const { const_iterator head = begin(); const_iterator const tail = end(); ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); while (head != tail) { ALOGD(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right, head->bottom); head++; } } // ---------------------------------------------------------------------------- }; // namespace android libs/ui/UiConfig.cpp0100644 0000000 0000000 00000002156 13077405420 013370 0ustar000000000 0000000 /* * Copyright (C) 2012 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 namespace android { #ifdef FRAMEBUFFER_FORCE_FORMAT // We need the two-level macro to stringify the contents of a macro argument #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #endif void appendUiConfigString(String8& configStr) { static const char* config = " [libui" #ifdef FRAMEBUFFER_FORCE_FORMAT " FRAMEBUFFER_FORCE_FORMAT=" TOSTRING(FRAMEBUFFER_FORCE_FORMAT) #endif "]"; configStr.append(config); } }; // namespace android libs/ui/tests/0040755 0000000 0000000 00000000000 13077405420 012322 5ustar000000000 0000000 libs/ui/tests/Android.mk0100644 0000000 0000000 00000002225 13077405420 014231 0ustar000000000 0000000 # # Copyright (C) 2014 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SHARED_LIBRARIES := libui LOCAL_SRC_FILES := Region_test.cpp LOCAL_MODULE := Region_test include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := vec_test.cpp LOCAL_MODULE := vec_test include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := mat_test.cpp LOCAL_MODULE := mat_test include $(BUILD_NATIVE_TEST) libs/ui/tests/Region_test.cpp0100644 0000000 0000000 00000010022 13077405420 015300 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "RegionTest" #include #include #include #include namespace android { class RegionTest : public testing::Test { protected: void checkVertTJunction(const Rect* lhs, const Rect* rhs) { EXPECT_FALSE((rhs->right > lhs->left && rhs->right < lhs->right) || (rhs->left > lhs->left && rhs->left < lhs->right)); } void verifyNoTJunctions(const Region& r) { for (const Rect* current = r.begin(); current < r.end(); current++) { for (const Rect* other = current - 1; other >= r.begin(); other--) { if (other->bottom < current->top) break; if (other->bottom != current->top) continue; checkVertTJunction(current, other); } for (const Rect* other = current + 1; other < r.end(); other++) { if (other->top > current->bottom) break; if (other->top != current->bottom) continue; checkVertTJunction(current, other); } } } void checkTJunctionFreeFromRegion(const Region& original, int expectedCount = -1) { Region modified = Region::createTJunctionFreeRegion(original); verifyNoTJunctions(modified); if (expectedCount != -1) { EXPECT_EQ(modified.end() - modified.begin(), expectedCount); } EXPECT_TRUE((original ^ modified).isEmpty()); } }; TEST_F(RegionTest, MinimalDivision_TJunction) { Region r; // | x | // |xxx| r.clear(); r.orSelf(Rect(1, 0, 2, 1)); r.orSelf(Rect(0, 1, 3, 2)); checkTJunctionFreeFromRegion(r, 4); // | x | // | | // |xxx| r.clear(); r.orSelf(Rect(1, 0, 2, 1)); r.orSelf(Rect(0, 2, 3, 3)); checkTJunctionFreeFromRegion(r, 2); } TEST_F(RegionTest, Trivial_TJunction) { Region r; checkTJunctionFreeFromRegion(r); r.orSelf(Rect(100, 100, 500, 500)); checkTJunctionFreeFromRegion(r); } TEST_F(RegionTest, Simple_TJunction) { Region r; // | x | // |xxxx| // |xxxx| // |xxxx| r.clear(); r.orSelf(Rect(1, 0, 2, 1)); r.orSelf(Rect(0, 1, 3, 3)); checkTJunctionFreeFromRegion(r); // | x | // |xx | // |xxx| r.clear(); r.orSelf(Rect(2,0,4,2)); r.orSelf(Rect(0,2,4,4)); r.orSelf(Rect(0,4,6,6)); checkTJunctionFreeFromRegion(r); // |x x| // |xxx| // |x x| r.clear(); r.orSelf(Rect(0,0,2,6)); r.orSelf(Rect(4,0,6,6)); r.orSelf(Rect(0,2,6,4)); checkTJunctionFreeFromRegion(r); // |xxx| // | x | // | x | r.clear(); r.orSelf(Rect(0,0,6,2)); r.orSelf(Rect(2,2,4,6)); checkTJunctionFreeFromRegion(r); } TEST_F(RegionTest, Bigger_TJunction) { Region r; // |xxxx | // | xxxx | // | xxxx | // | xxxx| for (int i = 0; i < 4; i++) { r.orSelf(Rect(i,i,i+4,i+1)); } checkTJunctionFreeFromRegion(r, 16); } #define ITER_MAX 1000 #define X_MAX 8 #define Y_MAX 8 TEST_F(RegionTest, Random_TJunction) { Region r; srandom(12345); for (int iter = 0; iter < ITER_MAX; iter++) { r.clear(); for (int i = 0; i < X_MAX; i++) { for (int j = 0; j < Y_MAX; j++) { if (random() % 2) { r.orSelf(Rect(i, j, i + 1, j + 1)); } } } checkTJunctionFreeFromRegion(r); } } }; // namespace android libs/ui/tests/mat_test.cpp0100644 0000000 0000000 00000006311 13077405420 014644 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "RegionTest" #include #include #include #include #include namespace android { class MatTest : public testing::Test { protected: }; TEST_F(MatTest, Basics) { mat4 m0; EXPECT_EQ(sizeof(mat4), sizeof(float)*16); } TEST_F(MatTest, ComparisonOps) { mat4 m0; mat4 m1(2); EXPECT_TRUE(m0 == m0); EXPECT_TRUE(m0 != m1); EXPECT_FALSE(m0 != m0); EXPECT_FALSE(m0 == m1); } TEST_F(MatTest, Constructors) { mat4 m0; ASSERT_EQ(m0[0].x, 1); ASSERT_EQ(m0[0].y, 0); ASSERT_EQ(m0[0].z, 0); ASSERT_EQ(m0[0].w, 0); ASSERT_EQ(m0[1].x, 0); ASSERT_EQ(m0[1].y, 1); ASSERT_EQ(m0[1].z, 0); ASSERT_EQ(m0[1].w, 0); ASSERT_EQ(m0[2].x, 0); ASSERT_EQ(m0[2].y, 0); ASSERT_EQ(m0[2].z, 1); ASSERT_EQ(m0[2].w, 0); ASSERT_EQ(m0[3].x, 0); ASSERT_EQ(m0[3].y, 0); ASSERT_EQ(m0[3].z, 0); ASSERT_EQ(m0[3].w, 1); mat4 m1(2); mat4 m2(vec4(2)); mat4 m3(m2); EXPECT_EQ(m1, m2); EXPECT_EQ(m2, m3); EXPECT_EQ(m3, m1); mat4 m4(vec4(1), vec4(2), vec4(3), vec4(4)); } TEST_F(MatTest, ArithmeticOps) { mat4 m0; mat4 m1(2); mat4 m2(vec4(2)); m1 += m2; EXPECT_EQ(mat4(4), m1); m2 -= m1; EXPECT_EQ(mat4(-2), m2); m1 *= 2; EXPECT_EQ(mat4(8), m1); m1 /= 2; EXPECT_EQ(mat4(4), m1); m0 = -m0; EXPECT_EQ(mat4(-1), m0); } TEST_F(MatTest, UnaryOps) { const mat4 identity; mat4 m0; ++m0; EXPECT_EQ(mat4( vec4(2,1,1,1), vec4(1,2,1,1), vec4(1,1,2,1), vec4(1,1,1,2) ), m0); EXPECT_EQ(mat4( -vec4(2,1,1,1), -vec4(1,2,1,1), -vec4(1,1,2,1), -vec4(1,1,1,2) ), -m0); --m0; EXPECT_EQ(identity, m0); } TEST_F(MatTest, MiscOps) { const mat4 identity; mat4 m0; EXPECT_EQ(4, trace(m0)); mat4 m1(vec4(1,2,3,4), vec4(5,6,7,8), vec4(9,10,11,12), vec4(13,14,15,16)); mat4 m2(vec4(1,5,9,13), vec4(2,6,10,14), vec4(3,7,11,15), vec4(4,8,12,16)); EXPECT_EQ(m1, transpose(m2)); EXPECT_EQ(m2, transpose(m1)); EXPECT_EQ(vec4(1,6,11,16), diag(m1)); EXPECT_EQ(identity, inverse(identity)); mat4 m3(vec4(4,3,0,0), vec4(3,2,0,0), vec4(0,0,1,0), vec4(0,0,0,1)); mat4 m3i(inverse(m3)); EXPECT_FLOAT_EQ(-2, m3i[0][0]); EXPECT_FLOAT_EQ( 3, m3i[0][1]); EXPECT_FLOAT_EQ( 3, m3i[1][0]); EXPECT_FLOAT_EQ(-4, m3i[1][1]); mat4 m3ii(inverse(m3i)); EXPECT_FLOAT_EQ(m3[0][0], m3ii[0][0]); EXPECT_FLOAT_EQ(m3[0][1], m3ii[0][1]); EXPECT_FLOAT_EQ(m3[1][0], m3ii[1][0]); EXPECT_FLOAT_EQ(m3[1][1], m3ii[1][1]); EXPECT_EQ(m1, m1*identity); } }; // namespace android libs/ui/tests/vec_test.cpp0100644 0000000 0000000 00000012262 13077405420 014642 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define LOG_TAG "RegionTest" #include #include #include #include #include #include namespace android { class VecTest : public testing::Test { }; TEST_F(VecTest, Basics) { vec4 v4; vec3& v3(v4.xyz); EXPECT_EQ(sizeof(vec4), sizeof(float)*4); EXPECT_EQ(sizeof(vec3), sizeof(float)*3); EXPECT_EQ(sizeof(vec2), sizeof(float)*2); EXPECT_EQ((void*)&v3, (void*)&v4); } TEST_F(VecTest, Constructors) { vec4 v0; EXPECT_EQ(v0.x, 0); EXPECT_EQ(v0.y, 0); EXPECT_EQ(v0.z, 0); EXPECT_EQ(v0.w, 0); vec4 v1(1); EXPECT_EQ(v1.x, 1); EXPECT_EQ(v1.y, 1); EXPECT_EQ(v1.z, 1); EXPECT_EQ(v1.w, 1); vec4 v2(1,2,3,4); EXPECT_EQ(v2.x, 1); EXPECT_EQ(v2.y, 2); EXPECT_EQ(v2.z, 3); EXPECT_EQ(v2.w, 4); vec4 v3(v2); EXPECT_EQ(v3.x, 1); EXPECT_EQ(v3.y, 2); EXPECT_EQ(v3.z, 3); EXPECT_EQ(v3.w, 4); vec4 v4(v3.xyz, 42); EXPECT_EQ(v4.x, 1); EXPECT_EQ(v4.y, 2); EXPECT_EQ(v4.z, 3); EXPECT_EQ(v4.w, 42); vec4 v5(vec3(v2.xy, 42), 24); EXPECT_EQ(v5.x, 1); EXPECT_EQ(v5.y, 2); EXPECT_EQ(v5.z, 42); EXPECT_EQ(v5.w, 24); tvec4 vd(2); EXPECT_EQ(vd.x, 2); EXPECT_EQ(vd.y, 2); EXPECT_EQ(vd.z, 2); EXPECT_EQ(vd.w, 2); } TEST_F(VecTest, Access) { vec4 v0(1,2,3,4); v0.x = 10; v0.y = 20; v0.z = 30; v0.w = 40; EXPECT_EQ(v0.x, 10); EXPECT_EQ(v0.y, 20); EXPECT_EQ(v0.z, 30); EXPECT_EQ(v0.w, 40); v0[0] = 100; v0[1] = 200; v0[2] = 300; v0[3] = 400; EXPECT_EQ(v0.x, 100); EXPECT_EQ(v0.y, 200); EXPECT_EQ(v0.z, 300); EXPECT_EQ(v0.w, 400); v0.xyz = vec3(1,2,3); EXPECT_EQ(v0.x, 1); EXPECT_EQ(v0.y, 2); EXPECT_EQ(v0.z, 3); EXPECT_EQ(v0.w, 400); } TEST_F(VecTest, UnaryOps) { vec4 v0(1,2,3,4); v0 += 1; EXPECT_EQ(v0.x, 2); EXPECT_EQ(v0.y, 3); EXPECT_EQ(v0.z, 4); EXPECT_EQ(v0.w, 5); v0 -= 1; EXPECT_EQ(v0.x, 1); EXPECT_EQ(v0.y, 2); EXPECT_EQ(v0.z, 3); EXPECT_EQ(v0.w, 4); v0 *= 2; EXPECT_EQ(v0.x, 2); EXPECT_EQ(v0.y, 4); EXPECT_EQ(v0.z, 6); EXPECT_EQ(v0.w, 8); v0 /= 2; EXPECT_EQ(v0.x, 1); EXPECT_EQ(v0.y, 2); EXPECT_EQ(v0.z, 3); EXPECT_EQ(v0.w, 4); vec4 v1(10, 20, 30, 40); v0 += v1; EXPECT_EQ(v0.x, 11); EXPECT_EQ(v0.y, 22); EXPECT_EQ(v0.z, 33); EXPECT_EQ(v0.w, 44); v0 -= v1; EXPECT_EQ(v0.x, 1); EXPECT_EQ(v0.y, 2); EXPECT_EQ(v0.z, 3); EXPECT_EQ(v0.w, 4); v0 *= v1; EXPECT_EQ(v0.x, 10); EXPECT_EQ(v0.y, 40); EXPECT_EQ(v0.z, 90); EXPECT_EQ(v0.w, 160); v0 /= v1; EXPECT_EQ(v0.x, 1); EXPECT_EQ(v0.y, 2); EXPECT_EQ(v0.z, 3); EXPECT_EQ(v0.w, 4); ++v0; EXPECT_EQ(v0.x, 2); EXPECT_EQ(v0.y, 3); EXPECT_EQ(v0.z, 4); EXPECT_EQ(v0.w, 5); ++++v0; EXPECT_EQ(v0.x, 4); EXPECT_EQ(v0.y, 5); EXPECT_EQ(v0.z, 6); EXPECT_EQ(v0.w, 7); --v1; EXPECT_EQ(v1.x, 9); EXPECT_EQ(v1.y, 19); EXPECT_EQ(v1.z, 29); EXPECT_EQ(v1.w, 39); v1 = -v1; EXPECT_EQ(v1.x, -9); EXPECT_EQ(v1.y, -19); EXPECT_EQ(v1.z, -29); EXPECT_EQ(v1.w, -39); tvec4 dv(1,2,3,4); v1 += dv; EXPECT_EQ(v1.x, -8); EXPECT_EQ(v1.y, -17); EXPECT_EQ(v1.z, -26); EXPECT_EQ(v1.w, -35); } TEST_F(VecTest, ComparisonOps) { vec4 v0(1,2,3,4); vec4 v1(10,20,30,40); EXPECT_TRUE(v0 == v0); EXPECT_TRUE(v0 != v1); EXPECT_FALSE(v0 != v0); EXPECT_FALSE(v0 == v1); } TEST_F(VecTest, ArithmeticOps) { vec4 v0(1,2,3,4); vec4 v1(10,20,30,40); vec4 v2(v0 + v1); EXPECT_EQ(v2.x, 11); EXPECT_EQ(v2.y, 22); EXPECT_EQ(v2.z, 33); EXPECT_EQ(v2.w, 44); v0 = v1 * 2; EXPECT_EQ(v0.x, 20); EXPECT_EQ(v0.y, 40); EXPECT_EQ(v0.z, 60); EXPECT_EQ(v0.w, 80); v0 = 2 * v1; EXPECT_EQ(v0.x, 20); EXPECT_EQ(v0.y, 40); EXPECT_EQ(v0.z, 60); EXPECT_EQ(v0.w, 80); tvec4 vd(2); v0 = v1 * vd; EXPECT_EQ(v0.x, 20); EXPECT_EQ(v0.y, 40); EXPECT_EQ(v0.z, 60); EXPECT_EQ(v0.w, 80); } TEST_F(VecTest, ArithmeticFunc) { vec3 east(1, 0, 0); vec3 north(0, 1, 0); vec3 up( cross(east, north) ); EXPECT_EQ(up, vec3(0,0,1)); EXPECT_EQ(dot(east, north), 0); EXPECT_EQ(length(east), 1); EXPECT_EQ(distance(east, north), sqrtf(2)); vec3 v0(1,2,3); vec3 vn(normalize(v0)); EXPECT_FLOAT_EQ(1, length(vn)); EXPECT_FLOAT_EQ(length(v0), dot(v0, vn)); tvec3 vd(east); EXPECT_EQ(length(vd), 1); } }; // namespace android opengl/0040755 0000000 0000000 00000000000 13077405420 011076 5ustar000000000 0000000 opengl/include/0040755 0000000 0000000 00000000000 13077405420 012521 5ustar000000000 0000000 opengl/include/EGL/0040755 0000000 0000000 00000000000 13077405420 013130 5ustar000000000 0000000 opengl/include/EGL/egl.h0100644 0000000 0000000 00000030101 13077405420 014040 0ustar000000000 0000000 /* -*- mode: c; tab-width: 8; -*- */ /* vi: set sw=4 ts=8: */ /* Reference version of egl.h for EGL 1.4. * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $ */ /* ** Copyright (c) 2007-2009 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ #ifndef __egl_h_ #define __egl_h_ /* All platform-dependent types and macro boilerplate (such as EGLAPI * and EGLAPIENTRY) should go in eglplatform.h. */ #include #ifdef __cplusplus extern "C" { #endif /* EGL Types */ /* EGLint is defined in eglplatform.h */ typedef unsigned int EGLBoolean; typedef unsigned int EGLenum; typedef void *EGLConfig; typedef void *EGLContext; typedef void *EGLDisplay; typedef void *EGLSurface; typedef void *EGLClientBuffer; /* EGL Versioning */ #define EGL_VERSION_1_0 1 #define EGL_VERSION_1_1 1 #define EGL_VERSION_1_2 1 #define EGL_VERSION_1_3 1 #define EGL_VERSION_1_4 1 /* EGL Enumerants. Bitmasks and other exceptional cases aside, most * enums are assigned unique values starting at 0x3000. */ /* EGL aliases */ #define EGL_FALSE 0 #define EGL_TRUE 1 /* Out-of-band handle values */ #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) #define EGL_NO_CONTEXT ((EGLContext)0) #define EGL_NO_DISPLAY ((EGLDisplay)0) #define EGL_NO_SURFACE ((EGLSurface)0) /* Out-of-band attribute value */ #define EGL_DONT_CARE ((EGLint)-1) /* Errors / GetError return values */ #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300A #define EGL_BAD_NATIVE_WINDOW 0x300B #define EGL_BAD_PARAMETER 0x300C #define EGL_BAD_SURFACE 0x300D #define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */ /* Reserved 0x300F-0x301F for additional errors */ /* Config attributes */ #define EGL_BUFFER_SIZE 0x3020 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_CONFIG_CAVEAT 0x3027 #define EGL_CONFIG_ID 0x3028 #define EGL_LEVEL 0x3029 #define EGL_MAX_PBUFFER_HEIGHT 0x302A #define EGL_MAX_PBUFFER_PIXELS 0x302B #define EGL_MAX_PBUFFER_WIDTH 0x302C #define EGL_NATIVE_RENDERABLE 0x302D #define EGL_NATIVE_VISUAL_ID 0x302E #define EGL_NATIVE_VISUAL_TYPE 0x302F #define EGL_SAMPLES 0x3031 #define EGL_SAMPLE_BUFFERS 0x3032 #define EGL_SURFACE_TYPE 0x3033 #define EGL_TRANSPARENT_TYPE 0x3034 #define EGL_TRANSPARENT_BLUE_VALUE 0x3035 #define EGL_TRANSPARENT_GREEN_VALUE 0x3036 #define EGL_TRANSPARENT_RED_VALUE 0x3037 #define EGL_NONE 0x3038 /* Attrib list terminator */ #define EGL_BIND_TO_TEXTURE_RGB 0x3039 #define EGL_BIND_TO_TEXTURE_RGBA 0x303A #define EGL_MIN_SWAP_INTERVAL 0x303B #define EGL_MAX_SWAP_INTERVAL 0x303C #define EGL_LUMINANCE_SIZE 0x303D #define EGL_ALPHA_MASK_SIZE 0x303E #define EGL_COLOR_BUFFER_TYPE 0x303F #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */ #define EGL_CONFORMANT 0x3042 /* Reserved 0x3041-0x304F for additional config attributes */ /* Config attribute values */ #define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */ #define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */ #define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */ #define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */ #define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */ /* More config attribute values, for EGL_TEXTURE_FORMAT */ #define EGL_NO_TEXTURE 0x305C #define EGL_TEXTURE_RGB 0x305D #define EGL_TEXTURE_RGBA 0x305E #define EGL_TEXTURE_2D 0x305F /* Config attribute mask bits */ #define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */ #define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */ #define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */ #define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */ #define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */ #define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */ #define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */ #define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */ #define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */ #define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */ #define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */ /* QueryString targets */ #define EGL_VENDOR 0x3053 #define EGL_VERSION 0x3054 #define EGL_EXTENSIONS 0x3055 #define EGL_CLIENT_APIS 0x308D /* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ #define EGL_HEIGHT 0x3056 #define EGL_WIDTH 0x3057 #define EGL_LARGEST_PBUFFER 0x3058 #define EGL_TEXTURE_FORMAT 0x3080 #define EGL_TEXTURE_TARGET 0x3081 #define EGL_MIPMAP_TEXTURE 0x3082 #define EGL_MIPMAP_LEVEL 0x3083 #define EGL_RENDER_BUFFER 0x3086 #define EGL_VG_COLORSPACE 0x3087 #define EGL_VG_ALPHA_FORMAT 0x3088 #define EGL_HORIZONTAL_RESOLUTION 0x3090 #define EGL_VERTICAL_RESOLUTION 0x3091 #define EGL_PIXEL_ASPECT_RATIO 0x3092 #define EGL_SWAP_BEHAVIOR 0x3093 #define EGL_MULTISAMPLE_RESOLVE 0x3099 /* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */ #define EGL_BACK_BUFFER 0x3084 #define EGL_SINGLE_BUFFER 0x3085 /* OpenVG color spaces */ #define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */ #define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */ /* OpenVG alpha formats */ #define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */ #define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */ /* Constant scale factor by which fractional display resolutions & * aspect ratio are scaled when queried as integer values. */ #define EGL_DISPLAY_SCALING 10000 /* Unknown display resolution/aspect ratio */ #define EGL_UNKNOWN ((EGLint)-1) /* Back buffer swap behaviors */ #define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ #define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */ /* CreatePbufferFromClientBuffer buffer types */ #define EGL_OPENVG_IMAGE 0x3096 /* QueryContext targets */ #define EGL_CONTEXT_CLIENT_TYPE 0x3097 /* CreateContext attributes */ #define EGL_CONTEXT_CLIENT_VERSION 0x3098 /* Multisample resolution behaviors */ #define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */ #define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */ /* BindAPI/QueryAPI targets */ #define EGL_OPENGL_ES_API 0x30A0 #define EGL_OPENVG_API 0x30A1 #define EGL_OPENGL_API 0x30A2 /* GetCurrentSurface targets */ #define EGL_DRAW 0x3059 #define EGL_READ 0x305A /* WaitNative engines */ #define EGL_CORE_NATIVE_ENGINE 0x305B /* EGL 1.2 tokens renamed for consistency in EGL 1.3 */ #define EGL_COLORSPACE EGL_VG_COLORSPACE #define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT #define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB #define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR #define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE #define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE /* EGL extensions must request enum blocks from the Khronos * API Registrar, who maintains the enumerant registry. Submit * a bug in Khronos Bugzilla against task "Registry". */ /* EGL Functions */ EGLAPI EGLint EGLAPIENTRY eglGetError(void); EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface); EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void); EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); /* This is a generic function pointer type, whose name indicates it must * be cast to the proper type *and calling convention* before use. */ typedef void (*__eglMustCastToProperFunctionPointerType)(void); /* Now, define eglGetProcAddress using the generic function ptr. type */ EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname); #ifdef __cplusplus } #endif #endif /* __egl_h_ */ opengl/include/EGL/eglext.h0100644 0000000 0000000 00000067740 13077405420 014604 0ustar000000000 0000000 #ifndef __eglext_h_ #define __eglext_h_ #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2007-2013 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ #include /*************************************************************/ /* Header file version number */ /* Current version at http://www.khronos.org/registry/egl/ */ /* $Revision: 20690 $ on $Date: 2013-02-22 17:15:05 -0800 (Fri, 22 Feb 2013) $ */ #define EGL_EGLEXT_VERSION 15 #ifndef EGL_KHR_config_attribs #define EGL_KHR_config_attribs 1 #define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ #define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ #define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ #endif #ifndef EGL_KHR_lock_surface #define EGL_KHR_lock_surface 1 #define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ #define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ #define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ #define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ #define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ #define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ #define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ #define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ #define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ #define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ #define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ #define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ #define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ #define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ #define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ #define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ #define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ #define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ #define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ #define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ #define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); #endif #ifndef EGL_KHR_image #define EGL_KHR_image 1 #define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ typedef void *EGLImageKHR; #define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); #endif #ifndef EGL_KHR_vg_parent_image #define EGL_KHR_vg_parent_image 1 #define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ #endif #ifndef EGL_KHR_gl_texture_2D_image #define EGL_KHR_gl_texture_2D_image 1 #define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ #endif #ifndef EGL_KHR_gl_texture_cubemap_image #define EGL_KHR_gl_texture_cubemap_image 1 #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ #endif #ifndef EGL_KHR_gl_texture_3D_image #define EGL_KHR_gl_texture_3D_image 1 #define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ #define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ #endif #ifndef EGL_KHR_gl_renderbuffer_image #define EGL_KHR_gl_renderbuffer_image 1 #define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ #endif #if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ #ifndef EGL_KHR_reusable_sync #define EGL_KHR_reusable_sync 1 typedef void* EGLSyncKHR; typedef khronos_utime_nanoseconds_t EGLTimeKHR; #define EGL_SYNC_STATUS_KHR 0x30F1 #define EGL_SIGNALED_KHR 0x30F2 #define EGL_UNSIGNALED_KHR 0x30F3 #define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 #define EGL_CONDITION_SATISFIED_KHR 0x30F6 #define EGL_SYNC_TYPE_KHR 0x30F7 #define EGL_SYNC_REUSABLE_KHR 0x30FA #define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR bitfield */ #define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull #define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync); typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); #endif #endif #ifndef EGL_KHR_image_base #define EGL_KHR_image_base 1 /* Most interfaces defined by EGL_KHR_image_pixmap above */ #define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ #endif #ifndef EGL_KHR_image_pixmap #define EGL_KHR_image_pixmap 1 /* Interfaces defined by EGL_KHR_image above */ #endif #ifndef EGL_IMG_context_priority #define EGL_IMG_context_priority 1 #define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 #define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 #define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 #define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 #endif #ifndef EGL_KHR_lock_surface2 #define EGL_KHR_lock_surface2 1 #define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 #endif #ifndef EGL_KHR_partial_update #define EGL_KHR_partial_update 1 #define EGL_BUFFER_AGE_KHR 0x313D typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); #endif #endif /* EGL_KHR_partial_update */ #ifndef EGL_NV_coverage_sample #define EGL_NV_coverage_sample 1 #define EGL_COVERAGE_BUFFERS_NV 0x30E0 #define EGL_COVERAGE_SAMPLES_NV 0x30E1 #endif #ifndef EGL_NV_depth_nonlinear #define EGL_NV_depth_nonlinear 1 #define EGL_DEPTH_ENCODING_NV 0x30E2 #define EGL_DEPTH_ENCODING_NONE_NV 0 #define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 #endif #if KHRONOS_SUPPORT_INT64 /* EGLTimeNV requires 64-bit uint support */ #ifndef EGL_NV_sync #define EGL_NV_sync 1 #define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 #define EGL_SYNC_STATUS_NV 0x30E7 #define EGL_SIGNALED_NV 0x30E8 #define EGL_UNSIGNALED_NV 0x30E9 #define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 #define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull #define EGL_ALREADY_SIGNALED_NV 0x30EA #define EGL_TIMEOUT_EXPIRED_NV 0x30EB #define EGL_CONDITION_SATISFIED_NV 0x30EC #define EGL_SYNC_TYPE_NV 0x30ED #define EGL_SYNC_CONDITION_NV 0x30EE #define EGL_SYNC_FENCE_NV 0x30EF #define EGL_NO_SYNC_NV ((EGLSyncNV)0) typedef void* EGLSyncNV; typedef khronos_utime_nanoseconds_t EGLTimeNV; #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync); EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync); EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode); EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync); typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode); typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value); #endif #endif #if KHRONOS_SUPPORT_INT64 /* Dependent on EGL_KHR_reusable_sync which requires 64-bit uint support */ #ifndef EGL_KHR_fence_sync #define EGL_KHR_fence_sync 1 /* Reuses most tokens and entry points from EGL_KHR_reusable_sync */ #define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 #define EGL_SYNC_CONDITION_KHR 0x30F8 #define EGL_SYNC_FENCE_KHR 0x30F9 #endif #endif #ifndef EGL_HI_clientpixmap #define EGL_HI_clientpixmap 1 /* Surface Attribute */ #define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74 /* * Structure representing a client pixmap * (pixmap's data is in client-space memory). */ struct EGLClientPixmapHI { void* pData; EGLint iWidth; EGLint iHeight; EGLint iStride; }; #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); #endif /* EGL_HI_clientpixmap */ #ifndef EGL_HI_colorformats #define EGL_HI_colorformats 1 /* Config Attribute */ #define EGL_COLOR_FORMAT_HI 0x8F70 /* Color Formats */ #define EGL_COLOR_RGB_HI 0x8F71 #define EGL_COLOR_RGBA_HI 0x8F72 #define EGL_COLOR_ARGB_HI 0x8F73 #endif /* EGL_HI_colorformats */ #ifndef EGL_MESA_drm_image #define EGL_MESA_drm_image 1 #define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 /* CreateDRMImageMESA attribute */ #define EGL_DRM_BUFFER_USE_MESA 0x31D1 /* CreateDRMImageMESA attribute */ #define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 /* EGL_IMAGE_FORMAT_MESA attribute value */ #define EGL_DRM_BUFFER_MESA 0x31D3 /* eglCreateImageKHR target */ #define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4 #define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 /* EGL_DRM_BUFFER_USE_MESA bits */ #define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 /* EGL_DRM_BUFFER_USE_MESA bits */ #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); #endif #ifndef EGL_NV_post_sub_buffer #define EGL_NV_post_sub_buffer 1 #define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); #endif #ifndef EGL_ANGLE_query_surface_pointer #define EGL_ANGLE_query_surface_pointer 1 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); #endif typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); #endif #ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle #define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1 #define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 #endif #ifndef EGL_NV_coverage_sample_resolve #define EGL_NV_coverage_sample_resolve 1 #define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 #define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 #define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 #endif #if KHRONOS_SUPPORT_INT64 /* EGLuint64NV requires 64-bit uint support */ #ifndef EGL_NV_system_time #define EGL_NV_system_time 1 typedef khronos_utime_nanoseconds_t EGLuint64NV; #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void); EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void); typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void); #endif #endif #if KHRONOS_SUPPORT_INT64 /* EGLuint64KHR requires 64-bit uint support */ #ifndef EGL_KHR_stream #define EGL_KHR_stream 1 typedef void* EGLStreamKHR; typedef khronos_uint64_t EGLuint64KHR; #define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) #define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 #define EGL_PRODUCER_FRAME_KHR 0x3212 #define EGL_CONSUMER_FRAME_KHR 0x3213 #define EGL_STREAM_STATE_KHR 0x3214 #define EGL_STREAM_STATE_CREATED_KHR 0x3215 #define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 #define EGL_STREAM_STATE_EMPTY_KHR 0x3217 #define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 #define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 #define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A #define EGL_BAD_STREAM_KHR 0x321B #define EGL_BAD_STATE_KHR 0x321C #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream); EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value); EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC)(EGLDisplay dpy, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value); #endif #endif #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_consumer_gltexture #define EGL_KHR_stream_consumer_gltexture 1 #define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream); EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream); EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); #endif #endif #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_producer_eglsurface #define EGL_KHR_stream_producer_eglsurface 1 #define EGL_STREAM_BIT_KHR 0x0800 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list); #endif #endif #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_producer_aldatalocator #define EGL_KHR_stream_producer_aldatalocator 1 #endif #endif #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_fifo #define EGL_KHR_stream_fifo 1 /* reuse EGLTimeKHR */ #define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC #define EGL_STREAM_TIME_NOW_KHR 0x31FD #define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE #define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value); #endif #endif #ifndef EGL_EXT_create_context_robustness #define EGL_EXT_create_context_robustness 1 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 #define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE #define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF #endif #ifndef EGL_ANGLE_d3d_share_handle_client_buffer #define EGL_ANGLE_d3d_share_handle_client_buffer 1 /* reuse EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE */ #endif #ifndef EGL_KHR_create_context #define EGL_KHR_create_context 1 #define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB #define EGL_CONTEXT_FLAGS_KHR 0x30FC #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 #endif #ifndef EGL_KHR_create_context_no_error #define EGL_KHR_create_context_no_error 1 #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 #endif /* EGL_KHR_create_context_no_error */ #ifndef EGL_KHR_surfaceless_context #define EGL_KHR_surfaceless_context 1 /* No tokens/entry points, just relaxes an error condition */ #endif #ifndef EGL_KHR_swap_buffers_with_damage #define EGL_KHR_swap_buffers_with_damage 1 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); #endif #endif /* EGL_KHR_swap_buffers_with_damage */ #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_cross_process_fd #define EGL_KHR_stream_cross_process_fd 1 typedef int EGLNativeFileDescriptorKHR; #define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1)) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream); EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); #endif #endif #ifndef EGL_EXT_multiview_window #define EGL_EXT_multiview_window 1 #define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134 #endif #ifndef EGL_KHR_wait_sync #define EGL_KHR_wait_sync 1 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); #endif #ifndef EGL_NV_post_convert_rounding #define EGL_NV_post_convert_rounding 1 /* No tokens or entry points, just relaxes behavior of SwapBuffers */ #endif #ifndef EGL_NV_native_query #define EGL_NV_native_query 1 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV( EGLDisplay dpy, EGLNativeDisplayType* display_id); EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV( EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType* window); EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV( EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType* pixmap); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC)(EGLDisplay dpy, EGLNativeDisplayType *display_id); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap); #endif #ifndef EGL_NV_3dvision_surface #define EGL_NV_3dvision_surface 1 #define EGL_AUTO_STEREO_NV 0x3136 #endif #ifndef EGL_ANDROID_framebuffer_target #define EGL_ANDROID_framebuffer_target 1 #define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 #endif #ifndef EGL_ANDROID_image_crop #define EGL_ANDROID_image_crop 1 #define EGL_IMAGE_CROP_LEFT_ANDROID 0x3148 #define EGL_IMAGE_CROP_TOP_ANDROID 0x3149 #define EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A #define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B #endif #ifndef EGL_ANDROID_blob_cache #define EGL_ANDROID_blob_cache 1 typedef khronos_ssize_t EGLsizeiANDROID; typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); #endif #ifndef EGL_ANDROID_image_native_buffer #define EGL_ANDROID_image_native_buffer 1 #define EGL_NATIVE_BUFFER_ANDROID 0x3140 #endif #ifndef EGL_ANDROID_native_fence_sync #define EGL_ANDROID_native_fence_sync 1 #define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 #define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 #define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 #define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR); #endif /* EGL_EGLEXT_PROTOTYPES */ typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR); #endif #ifndef EGL_ANDROID_recordable #define EGL_ANDROID_recordable 1 #define EGL_RECORDABLE_ANDROID 0x3142 #endif #ifndef EGL_EXT_buffer_age #define EGL_EXT_buffer_age 1 #define EGL_BUFFER_AGE_EXT 0x313D #endif #ifndef EGL_EXT_image_dma_buf_import #define EGL_EXT_image_dma_buf_import 1 #define EGL_LINUX_DMA_BUF_EXT 0x3270 #define EGL_LINUX_DRM_FOURCC_EXT 0x3271 #define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 #define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 #define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 #define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 #define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 #define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 #define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 #define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 #define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A #define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B #define EGL_SAMPLE_RANGE_HINT_EXT 0x327C #define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D #define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E #define EGL_ITU_REC601_EXT 0x327F #define EGL_ITU_REC709_EXT 0x3280 #define EGL_ITU_REC2020_EXT 0x3281 #define EGL_YUV_FULL_RANGE_EXT 0x3282 #define EGL_YUV_NARROW_RANGE_EXT 0x3283 #define EGL_YUV_CHROMA_SITING_0_EXT 0x3284 #define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285 #endif #ifndef EGL_ANDROID_presentation_time #define EGL_ANDROID_presentation_time 1 typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time); #else typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROID) (EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time); #endif #endif #ifndef EGL_ANDROID_create_native_client_buffer #define EGL_ANDROID_create_native_client_buffer 1 #define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 #define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 #define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 #define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list); #else typedef EGLAPI EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list); #endif #endif #ifndef EGL_ANDROID_front_buffer_auto_refresh #define EGL_ANDROID_front_buffer_auto_refresh 1 #define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C #endif #ifndef EGL_KHR_mutable_render_buffer #define EGL_KHR_mutable_render_buffer 1 #define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000 #endif #ifdef __cplusplus } #endif #endif /* __eglext_h_ */ opengl/include/EGL/eglplatform.h0100644 0000000 0000000 00000010613 13077405420 015613 0ustar000000000 0000000 #ifndef __eglplatform_h_ #define __eglplatform_h_ /* ** Copyright (c) 2007-2009 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Platform-specific types and definitions for egl.h * $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $ * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) * by filing a bug against product "EGL" component "Registry". */ #include /* Macros used in EGL function prototype declarations. * * EGL functions should be prototyped as: * * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); * * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h */ #ifndef EGLAPI #define EGLAPI KHRONOS_APICALL #endif #ifndef EGLAPIENTRY #define EGLAPIENTRY KHRONOS_APIENTRY #endif #define EGLAPIENTRYP EGLAPIENTRY* /* The types NativeDisplayType, NativeWindowType, and NativePixmapType * are aliases of window-system-dependent types, such as X Display * or * Windows Device Context. They must be defined in platform-specific * code below. The EGL-prefixed versions of Native*Type are the same * types, renamed in EGL 1.3 so all types in the API start with "EGL". * * Khronos STRONGLY RECOMMENDS that you use the default definitions * provided below, since these changes affect both binary and source * portability of applications using EGL running on different EGL * implementations. */ #if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; typedef HWND EGLNativeWindowType; #elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ typedef int EGLNativeDisplayType; typedef void *EGLNativeWindowType; typedef void *EGLNativePixmapType; #elif defined(__ANDROID__) || defined(ANDROID) struct ANativeWindow; struct egl_native_pixmap_t; typedef struct ANativeWindow* EGLNativeWindowType; typedef struct egl_native_pixmap_t* EGLNativePixmapType; typedef void* EGLNativeDisplayType; #elif defined(__unix__) /* X11 (tentative) */ #include #include typedef Display *EGLNativeDisplayType; typedef Pixmap EGLNativePixmapType; typedef Window EGLNativeWindowType; #else #error "Platform not recognized" #endif /* EGL 1.2 types, renamed for consistency in EGL 1.3 */ typedef EGLNativeDisplayType NativeDisplayType; typedef EGLNativePixmapType NativePixmapType; typedef EGLNativeWindowType NativeWindowType; /* Define EGLint. This must be a signed integral type large enough to contain * all legal attribute names and values passed into and out of EGL, whether * their type is boolean, bitmask, enumerant (symbolic constant), integer, * handle, or other. While in general a 32-bit integer will suffice, if * handles are 64 bit types, then EGLint should be defined as a signed 64-bit * integer type. */ typedef khronos_int32_t EGLint; #endif /* __eglplatform_h */ opengl/include/ETC1/0040755 0000000 0000000 00000000000 13077405420 013215 5ustar000000000 0000000 opengl/include/ETC1/etc1.h0100644 0000000 0000000 00000006710 13077405420 014223 0ustar000000000 0000000 // Copyright 2009 Google Inc. // // 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 __etc1_h__ #define __etc1_h__ #define ETC1_ENCODED_BLOCK_SIZE 8 #define ETC1_DECODED_BLOCK_SIZE 48 #ifndef ETC1_RGB8_OES #define ETC1_RGB8_OES 0x8D64 #endif typedef unsigned char etc1_byte; typedef int etc1_bool; typedef unsigned int etc1_uint32; #ifdef __cplusplus extern "C" { #endif // Encode a block of pixels. // // pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a // 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R // value of pixel (x, y). // // validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether // the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing. // // pOut is an ETC1 compressed version of the data. void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut); // Decode a block of pixels. // // pIn is an ETC1 compressed version of the data. // // pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a // 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R // value of pixel (x, y). void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut); // Return the size of the encoded image data (does not include size of PKM header). etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height); // Encode an entire image. // pIn - pointer to the image data. Formatted such that // pixel (x,y) is at pIn + pixelSize * x + stride * y; // pOut - pointer to encoded data. Must be large enough to store entire encoded image. // pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. // returns non-zero if there is an error. int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut); // Decode an entire image. // pIn - pointer to encoded data. // pOut - pointer to the image data. Will be written such that // pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be // large enough to store entire image. // pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. // returns non-zero if there is an error. int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, etc1_uint32 width, etc1_uint32 height, etc1_uint32 pixelSize, etc1_uint32 stride); // Size of a PKM header, in bytes. #define ETC_PKM_HEADER_SIZE 16 // Format a PKM header void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height); // Check if a PKM header is correctly formatted. etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader); // Read the image width from a PKM header etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader); // Read the image height from a PKM header etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader); #ifdef __cplusplus } #endif #endif opengl/include/GLES/0040755 0000000 0000000 00000000000 13077405420 013253 5ustar000000000 0000000 opengl/include/GLES/egl.h0100644 0000000 0000000 00000000563 13077405420 014174 0ustar000000000 0000000 /* * Skeleton egl.h to provide compatibility for early GLES 1.0 * applications. Several early implementations included gl.h * in egl.h leading applications to include only egl.h * * $Revision: 6252 $ on $Date:: 2008-08-06 16:35:08 -0700 #$ */ #ifndef __legacy_egl_h_ #define __legacy_egl_h_ #include #include #endif /* __legacy_egl_h_ */ opengl/include/GLES/gl.h0100644 0000000 0000000 00000103034 13077405420 014024 0ustar000000000 0000000 #ifndef __gl_h_ #define __gl_h_ /* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */ #include #ifdef __cplusplus extern "C" { #endif /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ typedef void GLvoid; typedef char GLchar; typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef khronos_int8_t GLbyte; typedef short GLshort; typedef int GLint; typedef int GLsizei; typedef khronos_uint8_t GLubyte; typedef unsigned short GLushort; typedef unsigned int GLuint; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef khronos_int32_t GLclampx; typedef khronos_intptr_t GLintptr; typedef khronos_ssize_t GLsizeiptr; /*************************************************************/ /* OpenGL ES core versions */ #define GL_VERSION_ES_CM_1_0 1 #define GL_VERSION_ES_CL_1_0 1 #define GL_VERSION_ES_CM_1_1 1 #define GL_VERSION_ES_CL_1_1 1 /* ClearBufferMask */ #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 /* Boolean */ #define GL_FALSE 0 #define GL_TRUE 1 /* BeginMode */ #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 /* AlphaFunction */ #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 /* BlendingFactorDest */ #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 /* BlendingFactorSrc */ /* GL_ZERO */ /* GL_ONE */ #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 /* GL_SRC_ALPHA */ /* GL_ONE_MINUS_SRC_ALPHA */ /* GL_DST_ALPHA */ /* GL_ONE_MINUS_DST_ALPHA */ /* ClipPlaneName */ #define GL_CLIP_PLANE0 0x3000 #define GL_CLIP_PLANE1 0x3001 #define GL_CLIP_PLANE2 0x3002 #define GL_CLIP_PLANE3 0x3003 #define GL_CLIP_PLANE4 0x3004 #define GL_CLIP_PLANE5 0x3005 /* ColorMaterialFace */ /* GL_FRONT_AND_BACK */ /* ColorMaterialParameter */ /* GL_AMBIENT_AND_DIFFUSE */ /* ColorPointerType */ /* GL_UNSIGNED_BYTE */ /* GL_FLOAT */ /* GL_FIXED */ /* CullFaceMode */ #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 /* DepthFunction */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* EnableCap */ #define GL_FOG 0x0B60 #define GL_LIGHTING 0x0B50 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_ALPHA_TEST 0x0BC0 #define GL_BLEND 0x0BE2 #define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 /* GL_LIGHT0 */ /* GL_LIGHT1 */ /* GL_LIGHT2 */ /* GL_LIGHT3 */ /* GL_LIGHT4 */ /* GL_LIGHT5 */ /* GL_LIGHT6 */ /* GL_LIGHT7 */ #define GL_POINT_SMOOTH 0x0B10 #define GL_LINE_SMOOTH 0x0B20 #define GL_SCISSOR_TEST 0x0C11 #define GL_COLOR_MATERIAL 0x0B57 #define GL_NORMALIZE 0x0BA1 #define GL_RESCALE_NORMAL 0x803A #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 #define GL_COLOR_ARRAY 0x8076 #define GL_TEXTURE_COORD_ARRAY 0x8078 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 /* ErrorCode */ #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_OUT_OF_MEMORY 0x0505 /* FogMode */ /* GL_LINEAR */ #define GL_EXP 0x0800 #define GL_EXP2 0x0801 /* FogParameter */ #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_START 0x0B63 #define GL_FOG_END 0x0B64 #define GL_FOG_MODE 0x0B65 #define GL_FOG_COLOR 0x0B66 /* FrontFaceDirection */ #define GL_CW 0x0900 #define GL_CCW 0x0901 /* GetPName */ #define GL_CURRENT_COLOR 0x0B00 #define GL_CURRENT_NORMAL 0x0B02 #define GL_CURRENT_TEXTURE_COORDS 0x0B03 #define GL_POINT_SIZE 0x0B11 #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_LINE_WIDTH 0x0B21 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_SHADE_MODEL 0x0B54 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_MATRIX_MODE 0x0BA0 #define GL_VIEWPORT 0x0BA2 #define GL_MODELVIEW_STACK_DEPTH 0x0BA3 #define GL_PROJECTION_STACK_DEPTH 0x0BA4 #define GL_TEXTURE_STACK_DEPTH 0x0BA5 #define GL_MODELVIEW_MATRIX 0x0BA6 #define GL_PROJECTION_MATRIX 0x0BA7 #define GL_TEXTURE_MATRIX 0x0BA8 #define GL_ALPHA_TEST_FUNC 0x0BC1 #define GL_ALPHA_TEST_REF 0x0BC2 #define GL_BLEND_DST 0x0BE0 #define GL_BLEND_SRC 0x0BE1 #define GL_LOGIC_OP_MODE 0x0BF0 #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_LIGHTS 0x0D31 #define GL_MAX_CLIP_PLANES 0x0D32 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 #define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_VERTEX_ARRAY_SIZE 0x807A #define GL_VERTEX_ARRAY_TYPE 0x807B #define GL_VERTEX_ARRAY_STRIDE 0x807C #define GL_NORMAL_ARRAY_TYPE 0x807E #define GL_NORMAL_ARRAY_STRIDE 0x807F #define GL_COLOR_ARRAY_SIZE 0x8081 #define GL_COLOR_ARRAY_TYPE 0x8082 #define GL_COLOR_ARRAY_STRIDE 0x8083 #define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A #define GL_VERTEX_ARRAY_POINTER 0x808E #define GL_NORMAL_ARRAY_POINTER 0x808F #define GL_COLOR_ARRAY_POINTER 0x8090 #define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB /* GetTextureParameter */ /* GL_TEXTURE_MAG_FILTER */ /* GL_TEXTURE_MIN_FILTER */ /* GL_TEXTURE_WRAP_S */ /* GL_TEXTURE_WRAP_T */ #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 /* HintMode */ #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 /* HintTarget */ #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #define GL_POINT_SMOOTH_HINT 0x0C51 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_FOG_HINT 0x0C54 #define GL_GENERATE_MIPMAP_HINT 0x8192 /* LightModelParameter */ #define GL_LIGHT_MODEL_AMBIENT 0x0B53 #define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 /* LightParameter */ #define GL_AMBIENT 0x1200 #define GL_DIFFUSE 0x1201 #define GL_SPECULAR 0x1202 #define GL_POSITION 0x1203 #define GL_SPOT_DIRECTION 0x1204 #define GL_SPOT_EXPONENT 0x1205 #define GL_SPOT_CUTOFF 0x1206 #define GL_CONSTANT_ATTENUATION 0x1207 #define GL_LINEAR_ATTENUATION 0x1208 #define GL_QUADRATIC_ATTENUATION 0x1209 /* DataType */ #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C /* LogicOp */ #define GL_CLEAR 0x1500 #define GL_AND 0x1501 #define GL_AND_REVERSE 0x1502 #define GL_COPY 0x1503 #define GL_AND_INVERTED 0x1504 #define GL_NOOP 0x1505 #define GL_XOR 0x1506 #define GL_OR 0x1507 #define GL_NOR 0x1508 #define GL_EQUIV 0x1509 #define GL_INVERT 0x150A #define GL_OR_REVERSE 0x150B #define GL_COPY_INVERTED 0x150C #define GL_OR_INVERTED 0x150D #define GL_NAND 0x150E #define GL_SET 0x150F /* MaterialFace */ /* GL_FRONT_AND_BACK */ /* MaterialParameter */ #define GL_EMISSION 0x1600 #define GL_SHININESS 0x1601 #define GL_AMBIENT_AND_DIFFUSE 0x1602 /* GL_AMBIENT */ /* GL_DIFFUSE */ /* GL_SPECULAR */ /* MatrixMode */ #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 #define GL_TEXTURE 0x1702 /* NormalPointerType */ /* GL_BYTE */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* PixelFormat */ #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A /* PixelStoreParameter */ #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 /* PixelType */ /* GL_UNSIGNED_BYTE */ #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 /* ShadingModel */ #define GL_FLAT 0x1D00 #define GL_SMOOTH 0x1D01 /* StencilFunction */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* StencilOp */ /* GL_ZERO */ #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 /* GL_INVERT */ /* StringName */ #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 /* TexCoordPointerType */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* GL_BYTE */ /* TextureEnvMode */ #define GL_MODULATE 0x2100 #define GL_DECAL 0x2101 /* GL_BLEND */ #define GL_ADD 0x0104 /* GL_REPLACE */ /* TextureEnvParameter */ #define GL_TEXTURE_ENV_MODE 0x2200 #define GL_TEXTURE_ENV_COLOR 0x2201 /* TextureEnvTarget */ #define GL_TEXTURE_ENV 0x2300 /* TextureMagFilter */ #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 /* TextureMinFilter */ /* GL_NEAREST */ /* GL_LINEAR */ #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 /* TextureParameterName */ #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_GENERATE_MIPMAP 0x8191 /* TextureTarget */ /* GL_TEXTURE_2D */ /* TextureUnit */ #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 /* TextureWrapMode */ #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F /* VertexPointerType */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* GL_BYTE */ /* LightName */ #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 #define GL_LIGHT2 0x4002 #define GL_LIGHT3 0x4003 #define GL_LIGHT4 0x4004 #define GL_LIGHT5 0x4005 #define GL_LIGHT6 0x4006 #define GL_LIGHT7 0x4007 /* Buffer Objects */ #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 /* Texture combine + dot3 */ #define GL_SUBTRACT 0x84E7 #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_ALPHA_SCALE 0x0D1C #define GL_SRC0_RGB 0x8580 #define GL_SRC1_RGB 0x8581 #define GL_SRC2_RGB 0x8582 #define GL_SRC0_ALPHA 0x8588 #define GL_SRC1_ALPHA 0x8589 #define GL_SRC2_ALPHA 0x858A #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF /*------------------------------------------------------------------------* * required OES extension tokens *------------------------------------------------------------------------*/ /* OES_read_format */ #ifndef GL_OES_read_format #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_compressed_paletted_texture #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 #endif /* OES_point_size_array */ #ifndef GL_OES_point_size_array #define GL_POINT_SIZE_ARRAY_OES 0x8B9C #define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A #define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B #define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C #define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F #endif /* GL_OES_point_sprite */ #ifndef GL_OES_point_sprite #define GL_POINT_SPRITE_OES 0x8861 #define GL_COORD_REPLACE_OES 0x8862 #endif /*************************************************************/ /* Available only in Common profile */ GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref); GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); GL_API void GL_APIENTRY glClearDepthf (GLclampf depth); GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation); GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param); GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]); GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param); GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param); GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glLineWidth (GLfloat width); GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m); GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param); GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m); GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz); GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param); GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glPointSize (GLfloat size); GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z); GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param); GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z); /* Available in both Common and Common-Lite profiles */ GL_API void GL_APIENTRY glActiveTexture (GLenum texture); GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref); GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); GL_API void GL_APIENTRY glClear (GLbitfield mask); GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); GL_API void GL_APIENTRY glClearDepthx (GLclampx depth); GL_API void GL_APIENTRY glClearStencil (GLint s); GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture); GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation); GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_API void GL_APIENTRY glCullFace (GLenum mode); GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GL_API void GL_APIENTRY glDepthFunc (GLenum func); GL_API void GL_APIENTRY glDepthMask (GLboolean flag); GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar); GL_API void GL_APIENTRY glDisable (GLenum cap); GL_API void GL_APIENTRY glDisableClientState (GLenum array); GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); GL_API void GL_APIENTRY glEnable (GLenum cap); GL_API void GL_APIENTRY glEnableClientState (GLenum array); GL_API void GL_APIENTRY glFinish (void); GL_API void GL_APIENTRY glFlush (void); GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glFrontFace (GLenum mode); GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params); GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]); GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); GL_API GLenum GL_APIENTRY glGetError (void); GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params); GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params); GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name); GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params); GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glLineWidthx (GLfixed width); GL_API void GL_APIENTRY glLoadIdentity (void); GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m); GL_API void GL_APIENTRY glLogicOp (GLenum opcode); GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glMatrixMode (GLenum mode); GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m); GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz); GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glPointSizex (GLfixed size); GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units); GL_API void GL_APIENTRY glPopMatrix (void); GL_API void GL_APIENTRY glPushMatrix (void); GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert); GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z); GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_API void GL_APIENTRY glShadeModel (GLenum mode); GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_API void GL_APIENTRY glStencilMask (GLuint mask); GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param); GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params); GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z); GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); /*------------------------------------------------------------------------* * Required OES extension functions *------------------------------------------------------------------------*/ /* GL_OES_read_format */ #ifndef GL_OES_read_format #define GL_OES_read_format 1 #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_compressed_paletted_texture #define GL_OES_compressed_paletted_texture 1 #endif /* GL_OES_point_size_array */ #ifndef GL_OES_point_size_array #define GL_OES_point_size_array 1 GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_OES_point_sprite */ #ifndef GL_OES_point_sprite #define GL_OES_point_sprite 1 #endif #ifdef __cplusplus } #endif #endif /* __gl_h_ */ opengl/include/GLES/glext.h0100644 0000000 0000000 00000175040 13077405420 014553 0ustar000000000 0000000 #ifndef __glext_h_ #define __glext_h_ /* $Revision: 20798 $ on $Date:: 2013-03-07 01:19:34 -0800 #$ */ #ifdef __cplusplus extern "C" { #endif /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ #ifndef GL_APIENTRYP # define GL_APIENTRYP GL_APIENTRY* #endif /*------------------------------------------------------------------------* * OES extension tokens *------------------------------------------------------------------------*/ /* GL_OES_blend_equation_separate */ #ifndef GL_OES_blend_equation_separate /* BLEND_EQUATION_RGB_OES same as BLEND_EQUATION_OES */ #define GL_BLEND_EQUATION_RGB_OES 0x8009 #define GL_BLEND_EQUATION_ALPHA_OES 0x883D #endif /* GL_OES_blend_func_separate */ #ifndef GL_OES_blend_func_separate #define GL_BLEND_DST_RGB_OES 0x80C8 #define GL_BLEND_SRC_RGB_OES 0x80C9 #define GL_BLEND_DST_ALPHA_OES 0x80CA #define GL_BLEND_SRC_ALPHA_OES 0x80CB #endif /* GL_OES_blend_subtract */ #ifndef GL_OES_blend_subtract #define GL_BLEND_EQUATION_OES 0x8009 #define GL_FUNC_ADD_OES 0x8006 #define GL_FUNC_SUBTRACT_OES 0x800A #define GL_FUNC_REVERSE_SUBTRACT_OES 0x800B #endif /* GL_OES_compressed_ETC1_RGB8_texture */ #ifndef GL_OES_compressed_ETC1_RGB8_texture #define GL_ETC1_RGB8_OES 0x8D64 #endif /* GL_OES_depth24 */ #ifndef GL_OES_depth24 #define GL_DEPTH_COMPONENT24_OES 0x81A6 #endif /* GL_OES_depth32 */ #ifndef GL_OES_depth32 #define GL_DEPTH_COMPONENT32_OES 0x81A7 #endif /* GL_OES_draw_texture */ #ifndef GL_OES_draw_texture #define GL_TEXTURE_CROP_RECT_OES 0x8B9D #endif /* GL_OES_EGL_image */ #ifndef GL_OES_EGL_image typedef void* GLeglImageOES; #endif /* GL_OES_EGL_image_external */ #ifndef GL_OES_EGL_image_external /* GLeglImageOES defined in GL_OES_EGL_image already. */ #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 #define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 #endif /* GL_OES_element_index_uint */ #ifndef GL_OES_element_index_uint #define GL_UNSIGNED_INT 0x1405 #endif /* GL_OES_fixed_point */ #ifndef GL_OES_fixed_point #define GL_FIXED_OES 0x140C #endif /* GL_OES_framebuffer_object */ #ifndef GL_OES_framebuffer_object #define GL_NONE_OES 0 #define GL_FRAMEBUFFER_OES 0x8D40 #define GL_RENDERBUFFER_OES 0x8D41 #define GL_RGBA4_OES 0x8056 #define GL_RGB5_A1_OES 0x8057 #define GL_RGB565_OES 0x8D62 #define GL_DEPTH_COMPONENT16_OES 0x81A5 #define GL_RENDERBUFFER_WIDTH_OES 0x8D42 #define GL_RENDERBUFFER_HEIGHT_OES 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44 #define GL_RENDERBUFFER_RED_SIZE_OES 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3 #define GL_COLOR_ATTACHMENT0_OES 0x8CE0 #define GL_DEPTH_ATTACHMENT_OES 0x8D00 #define GL_STENCIL_ATTACHMENT_OES 0x8D20 #define GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA #define GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD #define GL_FRAMEBUFFER_BINDING_OES 0x8CA6 #define GL_RENDERBUFFER_BINDING_OES 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506 #endif /* GL_OES_mapbuffer */ #ifndef GL_OES_mapbuffer #define GL_WRITE_ONLY_OES 0x88B9 #define GL_BUFFER_ACCESS_OES 0x88BB #define GL_BUFFER_MAPPED_OES 0x88BC #define GL_BUFFER_MAP_POINTER_OES 0x88BD #endif /* GL_OES_matrix_get */ #ifndef GL_OES_matrix_get #define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D #define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E #define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F #endif /* GL_OES_matrix_palette */ #ifndef GL_OES_matrix_palette #define GL_MAX_VERTEX_UNITS_OES 0x86A4 #define GL_MAX_PALETTE_MATRICES_OES 0x8842 #define GL_MATRIX_PALETTE_OES 0x8840 #define GL_MATRIX_INDEX_ARRAY_OES 0x8844 #define GL_WEIGHT_ARRAY_OES 0x86AD #define GL_CURRENT_PALETTE_MATRIX_OES 0x8843 #define GL_MATRIX_INDEX_ARRAY_SIZE_OES 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_OES 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_OES 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_OES 0x8849 #define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES 0x8B9E #define GL_WEIGHT_ARRAY_SIZE_OES 0x86AB #define GL_WEIGHT_ARRAY_TYPE_OES 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_OES 0x86AA #define GL_WEIGHT_ARRAY_POINTER_OES 0x86AC #define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES 0x889E #endif /* GL_OES_packed_depth_stencil */ #ifndef GL_OES_packed_depth_stencil #define GL_DEPTH_STENCIL_OES 0x84F9 #define GL_UNSIGNED_INT_24_8_OES 0x84FA #define GL_DEPTH24_STENCIL8_OES 0x88F0 #endif /* GL_OES_required_internalformat */ /* No new tokens introduced by this extension. */ /* GL_OES_rgb8_rgba8 */ #ifndef GL_OES_rgb8_rgba8 #define GL_RGB8_OES 0x8051 #define GL_RGBA8_OES 0x8058 #endif /* GL_OES_stencil1 */ #ifndef GL_OES_stencil1 #define GL_STENCIL_INDEX1_OES 0x8D46 #endif /* GL_OES_stencil4 */ #ifndef GL_OES_stencil4 #define GL_STENCIL_INDEX4_OES 0x8D47 #endif /* GL_OES_stencil8 */ #ifndef GL_OES_stencil8 #define GL_STENCIL_INDEX8_OES 0x8D48 #endif /* GL_OES_stencil_wrap */ #ifndef GL_OES_stencil_wrap #define GL_INCR_WRAP_OES 0x8507 #define GL_DECR_WRAP_OES 0x8508 #endif /* GL_OES_texture_cube_map */ #ifndef GL_OES_texture_cube_map #define GL_NORMAL_MAP_OES 0x8511 #define GL_REFLECTION_MAP_OES 0x8512 #define GL_TEXTURE_CUBE_MAP_OES 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_OES 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES 0x851C #define GL_TEXTURE_GEN_MODE_OES 0x2500 #define GL_TEXTURE_GEN_STR_OES 0x8D60 #endif /* GL_OES_texture_mirrored_repeat */ #ifndef GL_OES_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_OES 0x8370 #endif /* GL_OES_vertex_array_object */ #ifndef GL_OES_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 #endif /*------------------------------------------------------------------------* * AMD extension tokens *------------------------------------------------------------------------*/ /* GL_AMD_compressed_3DC_texture */ #ifndef GL_AMD_compressed_3DC_texture #define GL_3DC_X_AMD 0x87F9 #define GL_3DC_XY_AMD 0x87FA #endif /* GL_AMD_compressed_ATC_texture */ #ifndef GL_AMD_compressed_ATC_texture #define GL_ATC_RGB_AMD 0x8C92 #define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 #define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE #endif /*------------------------------------------------------------------------* * APPLE extension tokens *------------------------------------------------------------------------*/ /* GL_APPLE_copy_texture_levels */ /* No new tokens introduced by this extension. */ /* GL_APPLE_framebuffer_multisample */ #ifndef GL_APPLE_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 #define GL_MAX_SAMPLES_APPLE 0x8D57 #define GL_READ_FRAMEBUFFER_APPLE 0x8CA8 #define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA #endif /* GL_APPLE_sync */ #ifndef GL_APPLE_sync /* These types are defined with reference to * in the Apple extension spec, but here we use the Khronos * portable types in khrplatform.h, and assume those types * are always defined. * If any other extensions using these types are defined, * the typedefs must move out of this block and be shared. */ typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef struct __GLsync *GLsync; #define GL_SYNC_OBJECT_APPLE 0x8A53 #define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111 #define GL_OBJECT_TYPE_APPLE 0x9112 #define GL_SYNC_CONDITION_APPLE 0x9113 #define GL_SYNC_STATUS_APPLE 0x9114 #define GL_SYNC_FLAGS_APPLE 0x9115 #define GL_SYNC_FENCE_APPLE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117 #define GL_UNSIGNALED_APPLE 0x9118 #define GL_SIGNALED_APPLE 0x9119 #define GL_ALREADY_SIGNALED_APPLE 0x911A #define GL_TIMEOUT_EXPIRED_APPLE 0x911B #define GL_CONDITION_SATISFIED_APPLE 0x911C #define GL_WAIT_FAILED_APPLE 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001 #define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull #endif /* GL_APPLE_texture_2D_limited_npot */ /* No new tokens introduced by this extension. */ /* GL_APPLE_texture_format_BGRA8888 */ #ifndef GL_APPLE_texture_format_BGRA8888 #define GL_BGRA_EXT 0x80E1 #endif /* GL_APPLE_texture_max_level */ #ifndef GL_APPLE_texture_max_level #define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D #endif /*------------------------------------------------------------------------* * ARM extension tokens *------------------------------------------------------------------------*/ /* GL_ARM_rgba8 */ /* No new tokens introduced by this extension. */ /*------------------------------------------------------------------------* * EXT extension tokens *------------------------------------------------------------------------*/ /* GL_EXT_blend_minmax */ #ifndef GL_EXT_blend_minmax #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #endif /* GL_EXT_discard_framebuffer */ #ifndef GL_EXT_discard_framebuffer #define GL_COLOR_EXT 0x1800 #define GL_DEPTH_EXT 0x1801 #define GL_STENCIL_EXT 0x1802 #endif /* GL_EXT_map_buffer_range */ #ifndef GL_EXT_map_buffer_range #define GL_MAP_READ_BIT_EXT 0x0001 #define GL_MAP_WRITE_BIT_EXT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 #endif /* GL_EXT_multisampled_render_to_texture */ #ifndef GL_EXT_multisampled_render_to_texture #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C /* reuse values from GL_EXT_framebuffer_multisample (desktop extension) */ #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 #endif /* GL_EXT_multi_draw_arrays */ /* No new tokens introduced by this extension. */ /* GL_EXT_read_format_bgra */ #ifndef GL_EXT_read_format_bgra #define GL_BGRA_EXT 0x80E1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 #endif /* GL_EXT_robustness */ #ifndef GL_EXT_robustness /* reuse GL_NO_ERROR */ #define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 #define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 #define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 #define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 #define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 #define GL_NO_RESET_NOTIFICATION_EXT 0x8261 #endif /* GL_EXT_sRGB */ #ifndef GL_EXT_sRGB #define GL_SRGB_EXT 0x8C40 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 #endif /* GL_EXT_texture_compression_dxt1 */ #ifndef GL_EXT_texture_compression_dxt1 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif /* GL_EXT_texture_format_BGRA8888 */ #ifndef GL_EXT_texture_format_BGRA8888 #define GL_BGRA_EXT 0x80E1 #endif /* GL_EXT_texture_lod_bias */ #ifndef GL_EXT_texture_lod_bias #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif /* GL_EXT_texture_storage */ #ifndef GL_EXT_texture_storage #define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F #define GL_ALPHA8_EXT 0x803C #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_RGBA32F_EXT 0x8814 #define GL_RGB32F_EXT 0x8815 #define GL_ALPHA32F_EXT 0x8816 #define GL_LUMINANCE32F_EXT 0x8818 #define GL_LUMINANCE_ALPHA32F_EXT 0x8819 /* reuse GL_RGBA16F_EXT */ #define GL_RGB16F_EXT 0x881B #define GL_ALPHA16F_EXT 0x881C #define GL_LUMINANCE16F_EXT 0x881E #define GL_LUMINANCE_ALPHA16F_EXT 0x881F #define GL_RGB10_A2_EXT 0x8059 #define GL_RGB10_EXT 0x8052 #define GL_BGRA8_EXT 0x93A1 #endif /*------------------------------------------------------------------------* * IMG extension tokens *------------------------------------------------------------------------*/ /* GL_IMG_read_format */ #ifndef GL_IMG_read_format #define GL_BGRA_IMG 0x80E1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365 #endif /* GL_IMG_texture_compression_pvrtc */ #ifndef GL_IMG_texture_compression_pvrtc #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 #endif /* GL_IMG_texture_env_enhanced_fixed_function */ #ifndef GL_IMG_texture_env_enhanced_fixed_function #define GL_MODULATE_COLOR_IMG 0x8C04 #define GL_RECIP_ADD_SIGNED_ALPHA_IMG 0x8C05 #define GL_TEXTURE_ALPHA_MODULATE_IMG 0x8C06 #define GL_FACTOR_ALPHA_MODULATE_IMG 0x8C07 #define GL_FRAGMENT_ALPHA_MODULATE_IMG 0x8C08 #define GL_ADD_BLEND_IMG 0x8C09 #define GL_DOT3_RGBA_IMG 0x86AF #endif /* GL_IMG_user_clip_plane */ #ifndef GL_IMG_user_clip_plane #define GL_CLIP_PLANE0_IMG 0x3000 #define GL_CLIP_PLANE1_IMG 0x3001 #define GL_CLIP_PLANE2_IMG 0x3002 #define GL_CLIP_PLANE3_IMG 0x3003 #define GL_CLIP_PLANE4_IMG 0x3004 #define GL_CLIP_PLANE5_IMG 0x3005 #define GL_MAX_CLIP_PLANES_IMG 0x0D32 #endif /* GL_IMG_multisampled_render_to_texture */ #ifndef GL_IMG_multisampled_render_to_texture #define GL_RENDERBUFFER_SAMPLES_IMG 0x9133 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134 #define GL_MAX_SAMPLES_IMG 0x9135 #define GL_TEXTURE_SAMPLES_IMG 0x9136 #endif /*------------------------------------------------------------------------* * NV extension tokens *------------------------------------------------------------------------*/ /* GL_NV_fence */ #ifndef GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif /*------------------------------------------------------------------------* * QCOM extension tokens *------------------------------------------------------------------------*/ /* GL_QCOM_driver_control */ /* No new tokens introduced by this extension. */ /* GL_QCOM_extended_get */ #ifndef GL_QCOM_extended_get #define GL_TEXTURE_WIDTH_QCOM 0x8BD2 #define GL_TEXTURE_HEIGHT_QCOM 0x8BD3 #define GL_TEXTURE_DEPTH_QCOM 0x8BD4 #define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 #define GL_TEXTURE_FORMAT_QCOM 0x8BD6 #define GL_TEXTURE_TYPE_QCOM 0x8BD7 #define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 #define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 #define GL_TEXTURE_TARGET_QCOM 0x8BDA #define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB #define GL_STATE_RESTORE 0x8BDC #endif /* GL_QCOM_extended_get2 */ /* No new tokens introduced by this extension. */ /* GL_QCOM_perfmon_global_mode */ #ifndef GL_QCOM_perfmon_global_mode #define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 #endif /* GL_QCOM_writeonly_rendering */ #ifndef GL_QCOM_writeonly_rendering #define GL_WRITEONLY_RENDERING_QCOM 0x8823 #endif /* GL_QCOM_tiled_rendering */ #ifndef GL_QCOM_tiled_rendering #define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 #define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002 #define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004 #define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008 #define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010 #define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020 #define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040 #define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080 #define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100 #define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200 #define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400 #define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800 #define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000 #define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000 #define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000 #define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000 #define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000 #define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000 #define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000 #define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000 #define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000 #define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000 #define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000 #define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000 #define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000 #define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000 #define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000 #define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000 #define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000 #define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000 #define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000 #define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000 #endif /*------------------------------------------------------------------------* * End of extension tokens, start of corresponding extension functions *------------------------------------------------------------------------*/ /*------------------------------------------------------------------------* * OES extension functions *------------------------------------------------------------------------*/ /* GL_OES_blend_equation_separate */ #ifndef GL_OES_blend_equation_separate #define GL_OES_blend_equation_separate 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glBlendEquationSeparateOES (GLenum modeRGB, GLenum modeAlpha); #endif typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha); #endif /* GL_OES_blend_func_separate */ #ifndef GL_OES_blend_func_separate #define GL_OES_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glBlendFuncSeparateOES (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif /* GL_OES_blend_subtract */ #ifndef GL_OES_blend_subtract #define GL_OES_blend_subtract 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glBlendEquationOES (GLenum mode); #endif typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode); #endif /* GL_OES_byte_coordinates */ #ifndef GL_OES_byte_coordinates #define GL_OES_byte_coordinates 1 #endif /* GL_OES_compressed_ETC1_RGB8_texture */ #ifndef GL_OES_compressed_ETC1_RGB8_texture #define GL_OES_compressed_ETC1_RGB8_texture 1 #endif /* GL_OES_depth24 */ #ifndef GL_OES_depth24 #define GL_OES_depth24 1 #endif /* GL_OES_depth32 */ #ifndef GL_OES_depth32 #define GL_OES_depth32 1 #endif /* GL_OES_draw_texture */ #ifndef GL_OES_draw_texture #define GL_OES_draw_texture 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height); GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height); GL_API void GL_APIENTRY glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height); GL_API void GL_APIENTRY glDrawTexsvOES (const GLshort *coords); GL_API void GL_APIENTRY glDrawTexivOES (const GLint *coords); GL_API void GL_APIENTRY glDrawTexxvOES (const GLfixed *coords); GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height); GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords); #endif typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height); typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height); typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height); typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords); typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords); typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords); typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height); typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords); #endif /* GL_OES_EGL_image */ #ifndef GL_OES_EGL_image #define GL_OES_EGL_image 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); #endif typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); #endif /* GL_OES_EGL_image_external */ #ifndef GL_OES_EGL_image_external #define GL_OES_EGL_image_external 1 /* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */ #endif /* GL_OES_element_index_uint */ #ifndef GL_OES_element_index_uint #define GL_OES_element_index_uint 1 #endif /* GL_OES_extended_matrix_palette */ #ifndef GL_OES_extended_matrix_palette #define GL_OES_extended_matrix_palette 1 #endif /* GL_OES_fbo_render_mipmap */ #ifndef GL_OES_fbo_render_mipmap #define GL_OES_fbo_render_mipmap 1 #endif /* GL_OES_fixed_point */ #ifndef GL_OES_fixed_point #define GL_OES_fixed_point 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLclampx ref); GL_API void GL_APIENTRY glClearColorxOES (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); GL_API void GL_APIENTRY glClearDepthxOES (GLclampx depth); GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GL_API void GL_APIENTRY glDepthRangexOES (GLclampx zNear, GLclampx zFar); GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glFrustumxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum pname, GLfixed eqn[4]); GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum env, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width); GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m); GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m); GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); GL_API void GL_APIENTRY glOrthoxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param); GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glPointSizexOES (GLfixed size); GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert); GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); #endif typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLclampx ref); typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLclampx depth); typedef void (GL_APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); typedef void (GL_APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLclampx zNear, GLclampx zFar); typedef void (GL_APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum pname, GLfixed eqn[4]); typedef void (GL_APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params); typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params); typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum env, GLenum pname, GLfixed *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); typedef void (GL_APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); typedef void (GL_APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); typedef void (GL_APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); typedef void (GL_APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); typedef void (GL_APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert); typedef void (GL_APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); typedef void (GL_APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); #endif /* GL_OES_framebuffer_object */ #ifndef GL_OES_framebuffer_object #define GL_OES_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer); GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer); GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers); GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers); GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params); GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer); GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer); GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers); GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers); GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target); GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params); GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target); #endif typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFEROESPROC) (GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFEROESPROC) (GLenum target, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint* renderbuffers); typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint* renderbuffers); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint* params); typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFEROESPROC) (GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFEROESPROC) (GLenum target, GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint* framebuffers); typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint* framebuffers); typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSOESPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params); typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target); #endif /* GL_OES_mapbuffer */ #ifndef GL_OES_mapbuffer #define GL_OES_mapbuffer 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid ** params); #endif typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid ** params); #endif /* GL_OES_matrix_get */ #ifndef GL_OES_matrix_get #define GL_OES_matrix_get 1 #endif /* GL_OES_matrix_palette */ #ifndef GL_OES_matrix_palette #define GL_OES_matrix_palette 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glCurrentPaletteMatrixOES (GLuint matrixpaletteindex); GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES (void); GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex); typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void); typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_OES_packed_depth_stencil */ #ifndef GL_OES_packed_depth_stencil #define GL_OES_packed_depth_stencil 1 #endif /* GL_OES_required_internalformat */ #ifndef GL_OES_required_internalformat #define GL_OES_required_internalformat 1 #endif /* GL_OES_query_matrix */ #ifndef GL_OES_query_matrix #define GL_OES_query_matrix 1 #ifdef GL_GLEXT_PROTOTYPES GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed mantissa[16], GLint exponent[16]); #endif typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed mantissa[16], GLint exponent[16]); #endif /* GL_OES_rgb8_rgba8 */ #ifndef GL_OES_rgb8_rgba8 #define GL_OES_rgb8_rgba8 1 #endif /* GL_OES_single_precision */ #ifndef GL_OES_single_precision #define GL_OES_single_precision 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glDepthRangefOES (GLclampf zNear, GLclampf zFar); GL_API void GL_APIENTRY glFrustumfOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GL_API void GL_APIENTRY glOrthofOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum pname, GLfloat eqn[4]); GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth); #endif typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf zNear, GLclampf zFar); typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum pname, GLfloat eqn[4]); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); #endif /* GL_OES_stencil1 */ #ifndef GL_OES_stencil1 #define GL_OES_stencil1 1 #endif /* GL_OES_stencil4 */ #ifndef GL_OES_stencil4 #define GL_OES_stencil4 1 #endif /* GL_OES_stencil8 */ #ifndef GL_OES_stencil8 #define GL_OES_stencil8 1 #endif /* GL_OES_stencil_wrap */ #ifndef GL_OES_stencil_wrap #define GL_OES_stencil_wrap 1 #endif /* GL_OES_texture_cube_map */ #ifndef GL_OES_texture_cube_map #define GL_OES_texture_cube_map 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glTexGenfOES (GLenum coord, GLenum pname, GLfloat param); GL_API void GL_APIENTRY glTexGenfvOES (GLenum coord, GLenum pname, const GLfloat *params); GL_API void GL_APIENTRY glTexGeniOES (GLenum coord, GLenum pname, GLint param); GL_API void GL_APIENTRY glTexGenivOES (GLenum coord, GLenum pname, const GLint *params); GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); GL_API void GL_APIENTRY glGetTexGenfvOES (GLenum coord, GLenum pname, GLfloat *params); GL_API void GL_APIENTRY glGetTexGenivOES (GLenum coord, GLenum pname, GLint *params); GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); #endif typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params); typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); #endif /* GL_OES_texture_env_crossbar */ #ifndef GL_OES_texture_env_crossbar #define GL_OES_texture_env_crossbar 1 #endif /* GL_OES_texture_mirrored_repeat */ #ifndef GL_OES_texture_mirrored_repeat #define GL_OES_texture_mirrored_repeat 1 #endif /* GL_OES_vertex_array_object */ #ifndef GL_OES_vertex_array_object #define GL_OES_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glBindVertexArrayOES (GLuint array); GL_API void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); GL_API void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); GL_API GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); #endif typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); #endif /*------------------------------------------------------------------------* * AMD extension functions *------------------------------------------------------------------------*/ /* GL_AMD_compressed_3DC_texture */ #ifndef GL_AMD_compressed_3DC_texture #define GL_AMD_compressed_3DC_texture 1 #endif /* GL_AMD_compressed_ATC_texture */ #ifndef GL_AMD_compressed_ATC_texture #define GL_AMD_compressed_ATC_texture 1 #endif /*------------------------------------------------------------------------* * APPLE extension functions *------------------------------------------------------------------------*/ /* GL_APPLE_copy_texture_levels */ #ifndef GL_APPLE_copy_texture_levels #define GL_APPLE_copy_texture_levels 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount); #endif typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount); #endif /* GL_APPLE_framebuffer_multisample */ #ifndef GL_APPLE_framebuffer_multisample #define GL_APPLE_framebuffer_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void); #endif /* GL_APPLE_sync */ #ifndef GL_APPLE_sync #define GL_APPLE_sync 1 #ifdef GL_GLEXT_PROTOTYPES GL_API GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags); GL_API GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync); GL_API void GL_APIENTRY glDeleteSyncAPPLE (GLsync sync); GL_API GLenum GL_APIENTRY glClientWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_API void GL_APIENTRY glWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_API void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params); GL_API void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #endif typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync); typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync); typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #endif /* GL_APPLE_texture_2D_limited_npot */ #ifndef GL_APPLE_texture_2D_limited_npot #define GL_APPLE_texture_2D_limited_npot 1 #endif /* GL_APPLE_texture_format_BGRA8888 */ #ifndef GL_APPLE_texture_format_BGRA8888 #define GL_APPLE_texture_format_BGRA8888 1 #endif /* GL_APPLE_texture_max_level */ #ifndef GL_APPLE_texture_max_level #define GL_APPLE_texture_max_level 1 #endif /*------------------------------------------------------------------------* * ARM extension functions *------------------------------------------------------------------------*/ /* GL_ARM_rgba8 */ #ifndef GL_ARM_rgba8 #define GL_ARM_rgba8 1 #endif /*------------------------------------------------------------------------* * EXT extension functions *------------------------------------------------------------------------*/ /* GL_EXT_blend_minmax */ #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #endif /* GL_EXT_discard_framebuffer */ #ifndef GL_EXT_discard_framebuffer #define GL_EXT_discard_framebuffer 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif /* GL_EXT_map_buffer_range */ #ifndef GL_EXT_map_buffer_range #define GL_EXT_map_buffer_range 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY *glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GL_API void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length); #endif typedef void* (GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length); #endif /* GL_EXT_multisampled_render_to_texture */ #ifndef GL_EXT_multisampled_render_to_texture #define GL_EXT_multisampled_render_to_texture 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); #endif typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif /* GL_EXT_multi_draw_arrays */ #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum, const GLint *, const GLsizei *, GLsizei); GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* const*, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* const*indices, GLsizei primcount); #endif /* GL_EXT_read_format_bgra */ #ifndef GL_EXT_read_format_bgra #define GL_EXT_read_format_bgra 1 #endif /* GL_EXT_robustness */ #ifndef GL_EXT_robustness #define GL_EXT_robustness 1 #ifdef GL_GLEXT_PROTOTYPES GL_API GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); GL_API void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GL_API void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params); GL_API void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); #endif typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); #endif /* GL_EXT_sRGB */ #ifndef GL_EXT_sRGB #define GL_EXT_sRGB 1 #endif /* GL_EXT_texture_compression_dxt1 */ #ifndef GL_EXT_texture_compression_dxt1 #define GL_EXT_texture_compression_dxt1 1 #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #endif /* GL_EXT_texture_format_BGRA8888 */ #ifndef GL_EXT_texture_format_BGRA8888 #define GL_EXT_texture_format_BGRA8888 1 #endif /* GL_EXT_texture_lod_bias */ #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias 1 #endif /* GL_EXT_texture_storage */ #ifndef GL_EXT_texture_storage #define GL_EXT_texture_storage 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_API void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_API void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_API void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_API void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_API void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif /*------------------------------------------------------------------------* * IMG extension functions *------------------------------------------------------------------------*/ /* GL_IMG_read_format */ #ifndef GL_IMG_read_format #define GL_IMG_read_format 1 #endif /* GL_IMG_texture_compression_pvrtc */ #ifndef GL_IMG_texture_compression_pvrtc #define GL_IMG_texture_compression_pvrtc 1 #endif /* GL_IMG_texture_env_enhanced_fixed_function */ #ifndef GL_IMG_texture_env_enhanced_fixed_function #define GL_IMG_texture_env_enhanced_fixed_function 1 #endif /* GL_IMG_user_clip_plane */ #ifndef GL_IMG_user_clip_plane #define GL_IMG_user_clip_plane 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glClipPlanefIMG (GLenum, const GLfloat *); GL_API void GL_APIENTRY glClipPlanexIMG (GLenum, const GLfixed *); #endif typedef void (GL_APIENTRYP PFNGLCLIPPLANEFIMGPROC) (GLenum p, const GLfloat *eqn); typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMGPROC) (GLenum p, const GLfixed *eqn); #endif /* GL_IMG_multisampled_render_to_texture */ #ifndef GL_IMG_multisampled_render_to_texture #define GL_IMG_multisampled_render_to_texture 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); #endif typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif /*------------------------------------------------------------------------* * NV extension functions *------------------------------------------------------------------------*/ /* NV_fence */ #ifndef GL_NV_fence #define GL_NV_fence 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); GL_API void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *); GL_API GLboolean GL_APIENTRY glIsFenceNV (GLuint); GL_API GLboolean GL_APIENTRY glTestFenceNV (GLuint); GL_API void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); GL_API void GL_APIENTRY glFinishFenceNV (GLuint); GL_API void GL_APIENTRY glSetFenceNV (GLuint, GLenum); #endif typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #endif /*------------------------------------------------------------------------* * QCOM extension functions *------------------------------------------------------------------------*/ /* GL_QCOM_driver_control */ #ifndef GL_QCOM_driver_control #define GL_QCOM_driver_control 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); GL_API void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); GL_API void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); GL_API void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); #endif typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); #endif /* GL_QCOM_extended_get */ #ifndef GL_QCOM_extended_get #define GL_QCOM_extended_get 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); GL_API void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); GL_API void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); GL_API void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); GL_API void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); GL_API void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); GL_API void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); GL_API void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params); #endif typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params); #endif /* GL_QCOM_extended_get2 */ #ifndef GL_QCOM_extended_get2 #define GL_QCOM_extended_get2 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); GL_API void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); GL_API GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); GL_API void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #endif typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #endif /* GL_QCOM_perfmon_global_mode */ #ifndef GL_QCOM_perfmon_global_mode #define GL_QCOM_perfmon_global_mode 1 #endif /* GL_QCOM_writeonly_rendering */ #ifndef GL_QCOM_writeonly_rendering #define GL_QCOM_writeonly_rendering 1 #endif /* GL_QCOM_tiled_rendering */ #ifndef GL_QCOM_tiled_rendering #define GL_QCOM_tiled_rendering 1 #ifdef GL_GLEXT_PROTOTYPES GL_API void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); GL_API void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); #endif typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); #endif #ifdef __cplusplus } #endif #endif /* __glext_h_ */ opengl/include/GLES/glplatform.h0100644 0000000 0000000 00000001605 13077405420 015572 0ustar000000000 0000000 #ifndef __glplatform_h_ #define __glplatform_h_ /* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */ /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /* Platform-specific types and definitions for OpenGL ES 1.X gl.h * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) * by filing a bug against product "OpenGL-ES" component "Registry". */ #include #ifndef GL_API #define GL_API KHRONOS_APICALL #endif #ifndef GL_APIENTRY #define GL_APIENTRY KHRONOS_APIENTRY #endif #endif /* __glplatform_h_ */ opengl/include/GLES2/0040755 0000000 0000000 00000000000 13077405420 013335 5ustar000000000 0000000 opengl/include/GLES2/gl2.h0100644 0000000 0000000 00000126024 13077405420 014174 0ustar000000000 0000000 #ifndef __gl2_h_ #define __gl2_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2013-2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** ** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $ */ #include #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif #if !defined(GL_GLES_PROTOTYPES) #define GL_GLES_PROTOTYPES 1 #endif /* Generated on date 20151015 */ /* Generated C header for: * API: gles2 * Profile: common * Versions considered: 2\.[0-9] * Versions emitted: .* * Default extensions included: None * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_ES_VERSION_2_0 #define GL_ES_VERSION_2_0 1 #include typedef khronos_int8_t GLbyte; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef short GLshort; typedef unsigned short GLushort; typedef void GLvoid; typedef struct __GLsync *GLsync; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef unsigned int GLenum; typedef unsigned int GLuint; typedef char GLchar; typedef khronos_float_t GLfloat; typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; typedef unsigned int GLbitfield; typedef int GLint; typedef unsigned char GLboolean; typedef int GLsizei; typedef khronos_uint8_t GLubyte; #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_FALSE 0 #define GL_TRUE 1 #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_FUNC_ADD 0x8006 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_BLEND 0x0BE2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 #define GL_SCISSOR_TEST 0x0C11 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 #define GL_CW 0x0900 #define GL_CCW 0x0901 #define GL_LINE_WIDTH 0x0B21 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VIEWPORT 0x0BA2 #define GL_SCISSOR_BOX 0x0C10 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C #define GL_DEPTH_COMPONENT 0x1902 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_SHADER_TYPE 0x8B4F #define GL_DELETE_STATUS 0x8B80 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_INVERT 0x150A #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE 0x1702 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F #define GL_MIRRORED_REPEAT 0x8370 #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_CUBE 0x8B60 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGB565 0x8D62 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_STENCIL_INDEX8 0x8D48 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_NONE 0 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 typedef void (GL_APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (GL_APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (GL_APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (GL_APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GL_APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); typedef void (GL_APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GL_APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GL_APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (GL_APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (GL_APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); typedef void (GL_APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLDISABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLENABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLFINISHPROC) (void); typedef void (GL_APIENTRYP PFNGLFLUSHPROC) (void); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (GL_APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef void (GL_APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); typedef GLboolean (GL_APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef GLboolean (GL_APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); typedef void (GL_APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); typedef void (GL_APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); typedef void (GL_APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); typedef void (GL_APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); typedef void (GL_APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat d); GL_APICALL void GL_APIENTRY glClearStencil (GLint s); GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f); GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glDisable (GLenum cap); GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glEnable (GLenum cap); GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glFinish (void); GL_APICALL void GL_APIENTRY glFlush (void); GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL GLenum GL_APIENTRY glGetError (void); GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data); GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data); GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GL_APICALL const GLubyte *GL_APIENTRY glGetString (GLenum name); GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint v0); GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_ES_VERSION_2_0 */ #ifdef __cplusplus } #endif #endif opengl/include/GLES2/gl2ext.h0100644 0000000 0000000 00000521124 13077405420 014715 0ustar000000000 0000000 #ifndef __gl2ext_h_ #define __gl2ext_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2013-2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** ** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $ */ #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif /* Generated on date 20151015 */ /* Generated C header for: * API: gles2 * Profile: common * Versions considered: 2\.[0-9] * Versions emitted: _nomatch_^ * Default extensions included: gles2 * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_KHR_blend_equation_advanced #define GL_KHR_blend_equation_advanced 1 #define GL_MULTIPLY_KHR 0x9294 #define GL_SCREEN_KHR 0x9295 #define GL_OVERLAY_KHR 0x9296 #define GL_DARKEN_KHR 0x9297 #define GL_LIGHTEN_KHR 0x9298 #define GL_COLORDODGE_KHR 0x9299 #define GL_COLORBURN_KHR 0x929A #define GL_HARDLIGHT_KHR 0x929B #define GL_SOFTLIGHT_KHR 0x929C #define GL_DIFFERENCE_KHR 0x929E #define GL_EXCLUSION_KHR 0x92A0 #define GL_HSL_HUE_KHR 0x92AD #define GL_HSL_SATURATION_KHR 0x92AE #define GL_HSL_COLOR_KHR 0x92AF #define GL_HSL_LUMINOSITY_KHR 0x92B0 typedef void (GL_APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBlendBarrierKHR (void); #endif #endif /* GL_KHR_blend_equation_advanced */ #ifndef GL_KHR_blend_equation_advanced_coherent #define GL_KHR_blend_equation_advanced_coherent 1 #define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 #endif /* GL_KHR_blend_equation_advanced_coherent */ #ifndef GL_KHR_context_flush_control #define GL_KHR_context_flush_control 1 #define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC #endif /* GL_KHR_context_flush_control */ #ifndef GL_KHR_debug #define GL_KHR_debug 1 typedef void (GL_APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); #define GL_SAMPLER 0x82E6 #define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 #define GL_DEBUG_SOURCE_API_KHR 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 #define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A #define GL_DEBUG_SOURCE_OTHER_KHR 0x824B #define GL_DEBUG_TYPE_ERROR_KHR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E #define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F #define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 #define GL_DEBUG_TYPE_OTHER_KHR 0x8251 #define GL_DEBUG_TYPE_MARKER_KHR 0x8268 #define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 #define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A #define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B #define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C #define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D #define GL_BUFFER_KHR 0x82E0 #define GL_SHADER_KHR 0x82E1 #define GL_PROGRAM_KHR 0x82E2 #define GL_VERTEX_ARRAY_KHR 0x8074 #define GL_QUERY_KHR 0x82E3 #define GL_PROGRAM_PIPELINE_KHR 0x82E4 #define GL_SAMPLER_KHR 0x82E6 #define GL_MAX_LABEL_LENGTH_KHR 0x82E8 #define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 #define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 #define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 #define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 #define GL_DEBUG_OUTPUT_KHR 0x92E0 #define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 #define GL_STACK_OVERFLOW_KHR 0x0503 #define GL_STACK_UNDERFLOW_KHR 0x0504 typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC) (GLDEBUGPROCKHR callback, const void *userParam); typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC) (void); typedef void (GL_APIENTRYP PFNGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (GL_APIENTRYP PFNGLGETPOINTERVKHRPROC) (GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDebugMessageControlKHR (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GL_APICALL void GL_APIENTRY glDebugMessageInsertKHR (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GL_APICALL void GL_APIENTRY glDebugMessageCallbackKHR (GLDEBUGPROCKHR callback, const void *userParam); GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLogKHR (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); GL_APICALL void GL_APIENTRY glPushDebugGroupKHR (GLenum source, GLuint id, GLsizei length, const GLchar *message); GL_APICALL void GL_APIENTRY glPopDebugGroupKHR (void); GL_APICALL void GL_APIENTRY glObjectLabelKHR (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectLabelKHR (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); GL_APICALL void GL_APIENTRY glObjectPtrLabelKHR (const void *ptr, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectPtrLabelKHR (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); GL_APICALL void GL_APIENTRY glGetPointervKHR (GLenum pname, void **params); #endif #endif /* GL_KHR_debug */ #ifndef GL_KHR_no_error #define GL_KHR_no_error 1 #define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 #endif /* GL_KHR_no_error */ #ifndef GL_KHR_robust_buffer_access_behavior #define GL_KHR_robust_buffer_access_behavior 1 #endif /* GL_KHR_robust_buffer_access_behavior */ #ifndef GL_KHR_robustness #define GL_KHR_robustness 1 #define GL_CONTEXT_ROBUST_ACCESS_KHR 0x90F3 #define GL_LOSE_CONTEXT_ON_RESET_KHR 0x8252 #define GL_GUILTY_CONTEXT_RESET_KHR 0x8253 #define GL_INNOCENT_CONTEXT_RESET_KHR 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_KHR 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY_KHR 0x8256 #define GL_NO_RESET_NOTIFICATION_KHR 0x8261 #define GL_CONTEXT_LOST_KHR 0x0507 typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC) (void); typedef void (GL_APIENTRYP PFNGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusKHR (void); GL_APICALL void GL_APIENTRY glReadnPixelsKHR (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GL_APICALL void GL_APIENTRY glGetnUniformfvKHR (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GL_APICALL void GL_APIENTRY glGetnUniformivKHR (GLuint program, GLint location, GLsizei bufSize, GLint *params); GL_APICALL void GL_APIENTRY glGetnUniformuivKHR (GLuint program, GLint location, GLsizei bufSize, GLuint *params); #endif #endif /* GL_KHR_robustness */ #ifndef GL_KHR_texture_compression_astc_hdr #define GL_KHR_texture_compression_astc_hdr 1 #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 #define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 #define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 #define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 #define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 #define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 #define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 #define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 #define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 #define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA #define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB #define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC #define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD #endif /* GL_KHR_texture_compression_astc_hdr */ #ifndef GL_KHR_texture_compression_astc_ldr #define GL_KHR_texture_compression_astc_ldr 1 #endif /* GL_KHR_texture_compression_astc_ldr */ #ifndef GL_KHR_texture_compression_astc_sliced_3d #define GL_KHR_texture_compression_astc_sliced_3d 1 #endif /* GL_KHR_texture_compression_astc_sliced_3d */ #ifndef GL_OES_EGL_image #define GL_OES_EGL_image 1 typedef void *GLeglImageOES; typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); #endif #endif /* GL_OES_EGL_image */ #ifndef GL_OES_EGL_image_external #define GL_OES_EGL_image_external 1 #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 #define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 #define GL_SAMPLER_EXTERNAL_OES 0x8D66 #endif /* GL_OES_EGL_image_external */ #ifndef GL_OES_EGL_image_external_essl3 #define GL_OES_EGL_image_external_essl3 1 #endif /* GL_OES_EGL_image_external_essl3 */ #ifndef GL_OES_compressed_ETC1_RGB8_sub_texture #define GL_OES_compressed_ETC1_RGB8_sub_texture 1 #endif /* GL_OES_compressed_ETC1_RGB8_sub_texture */ #ifndef GL_OES_compressed_ETC1_RGB8_texture #define GL_OES_compressed_ETC1_RGB8_texture 1 #define GL_ETC1_RGB8_OES 0x8D64 #endif /* GL_OES_compressed_ETC1_RGB8_texture */ #ifndef GL_OES_compressed_paletted_texture #define GL_OES_compressed_paletted_texture 1 #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_copy_image #define GL_OES_copy_image 1 typedef void (GL_APIENTRYP PFNGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCopyImageSubDataOES (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); #endif #endif /* GL_OES_copy_image */ #ifndef GL_OES_depth24 #define GL_OES_depth24 1 #define GL_DEPTH_COMPONENT24_OES 0x81A6 #endif /* GL_OES_depth24 */ #ifndef GL_OES_depth32 #define GL_OES_depth32 1 #define GL_DEPTH_COMPONENT32_OES 0x81A7 #endif /* GL_OES_depth32 */ #ifndef GL_OES_depth_texture #define GL_OES_depth_texture 1 #endif /* GL_OES_depth_texture */ #ifndef GL_OES_draw_buffers_indexed #define GL_OES_draw_buffers_indexed 1 #define GL_MIN 0x8007 #define GL_MAX 0x8008 typedef void (GL_APIENTRYP PFNGLENABLEIOESPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLDISABLEIOESPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (GL_APIENTRYP PFNGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDIOESPROC) (GLenum target, GLuint index); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glEnableiOES (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glDisableiOES (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glBlendEquationiOES (GLuint buf, GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparateiOES (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunciOES (GLuint buf, GLenum src, GLenum dst); GL_APICALL void GL_APIENTRY glBlendFuncSeparateiOES (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GL_APICALL void GL_APIENTRY glColorMaskiOES (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GL_APICALL GLboolean GL_APIENTRY glIsEnablediOES (GLenum target, GLuint index); #endif #endif /* GL_OES_draw_buffers_indexed */ #ifndef GL_OES_draw_elements_base_vertex #define GL_OES_draw_elements_base_vertex 1 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawElementsBaseVertexOES (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawRangeElementsBaseVertexOES (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertexOES (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexOES (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex); #endif #endif /* GL_OES_draw_elements_base_vertex */ #ifndef GL_OES_element_index_uint #define GL_OES_element_index_uint 1 #endif /* GL_OES_element_index_uint */ #ifndef GL_OES_fbo_render_mipmap #define GL_OES_fbo_render_mipmap 1 #endif /* GL_OES_fbo_render_mipmap */ #ifndef GL_OES_fragment_precision_high #define GL_OES_fragment_precision_high 1 #endif /* GL_OES_fragment_precision_high */ #ifndef GL_OES_geometry_point_size #define GL_OES_geometry_point_size 1 #endif /* GL_OES_geometry_point_size */ #ifndef GL_OES_geometry_shader #define GL_OES_geometry_shader 1 #define GL_GEOMETRY_SHADER_OES 0x8DD9 #define GL_GEOMETRY_SHADER_BIT_OES 0x00000004 #define GL_GEOMETRY_LINKED_VERTICES_OUT_OES 0x8916 #define GL_GEOMETRY_LINKED_INPUT_TYPE_OES 0x8917 #define GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES 0x8918 #define GL_GEOMETRY_SHADER_INVOCATIONS_OES 0x887F #define GL_LAYER_PROVOKING_VERTEX_OES 0x825E #define GL_LINES_ADJACENCY_OES 0x000A #define GL_LINE_STRIP_ADJACENCY_OES 0x000B #define GL_TRIANGLES_ADJACENCY_OES 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_OES 0x000D #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8DDF #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES 0x8A2C #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES 0x8A32 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES 0x9124 #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES 0x8DE1 #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES 0x8E5A #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES 0x8C29 #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES 0x92CF #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES 0x92D5 #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES 0x90CD #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES 0x90D7 #define GL_FIRST_VERTEX_CONVENTION_OES 0x8E4D #define GL_LAST_VERTEX_CONVENTION_OES 0x8E4E #define GL_UNDEFINED_VERTEX_OES 0x8260 #define GL_PRIMITIVES_GENERATED_OES 0x8C87 #define GL_FRAMEBUFFER_DEFAULT_LAYERS_OES 0x9312 #define GL_MAX_FRAMEBUFFER_LAYERS_OES 0x9317 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES 0x8DA8 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES 0x8DA7 #define GL_REFERENCED_BY_GEOMETRY_SHADER_OES 0x9309 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferTextureOES (GLenum target, GLenum attachment, GLuint texture, GLint level); #endif #endif /* GL_OES_geometry_shader */ #ifndef GL_OES_get_program_binary #define GL_OES_get_program_binary 1 #define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE #define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length); #endif #endif /* GL_OES_get_program_binary */ #ifndef GL_OES_gpu_shader5 #define GL_OES_gpu_shader5 1 #endif /* GL_OES_gpu_shader5 */ #ifndef GL_OES_mapbuffer #define GL_OES_mapbuffer 1 #define GL_WRITE_ONLY_OES 0x88B9 #define GL_BUFFER_ACCESS_OES 0x88BB #define GL_BUFFER_MAPPED_OES 0x88BC #define GL_BUFFER_MAP_POINTER_OES 0x88BD typedef void *(GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void *GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void **params); #endif #endif /* GL_OES_mapbuffer */ #ifndef GL_OES_packed_depth_stencil #define GL_OES_packed_depth_stencil 1 #define GL_DEPTH_STENCIL_OES 0x84F9 #define GL_UNSIGNED_INT_24_8_OES 0x84FA #define GL_DEPTH24_STENCIL8_OES 0x88F0 #endif /* GL_OES_packed_depth_stencil */ #ifndef GL_OES_primitive_bounding_box #define GL_OES_primitive_bounding_box 1 #define GL_PRIMITIVE_BOUNDING_BOX_OES 0x92BE typedef void (GL_APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glPrimitiveBoundingBoxOES (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #endif #endif /* GL_OES_primitive_bounding_box */ #ifndef GL_OES_required_internalformat #define GL_OES_required_internalformat 1 #define GL_ALPHA8_OES 0x803C #define GL_DEPTH_COMPONENT16_OES 0x81A5 #define GL_LUMINANCE4_ALPHA4_OES 0x8043 #define GL_LUMINANCE8_ALPHA8_OES 0x8045 #define GL_LUMINANCE8_OES 0x8040 #define GL_RGBA4_OES 0x8056 #define GL_RGB5_A1_OES 0x8057 #define GL_RGB565_OES 0x8D62 #define GL_RGB8_OES 0x8051 #define GL_RGBA8_OES 0x8058 #define GL_RGB10_EXT 0x8052 #define GL_RGB10_A2_EXT 0x8059 #endif /* GL_OES_required_internalformat */ #ifndef GL_OES_rgb8_rgba8 #define GL_OES_rgb8_rgba8 1 #endif /* GL_OES_rgb8_rgba8 */ #ifndef GL_OES_sample_shading #define GL_OES_sample_shading 1 #define GL_SAMPLE_SHADING_OES 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE_OES 0x8C37 typedef void (GL_APIENTRYP PFNGLMINSAMPLESHADINGOESPROC) (GLfloat value); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glMinSampleShadingOES (GLfloat value); #endif #endif /* GL_OES_sample_shading */ #ifndef GL_OES_sample_variables #define GL_OES_sample_variables 1 #endif /* GL_OES_sample_variables */ #ifndef GL_OES_shader_image_atomic #define GL_OES_shader_image_atomic 1 #endif /* GL_OES_shader_image_atomic */ #ifndef GL_OES_shader_io_blocks #define GL_OES_shader_io_blocks 1 #endif /* GL_OES_shader_io_blocks */ #ifndef GL_OES_shader_multisample_interpolation #define GL_OES_shader_multisample_interpolation 1 #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES 0x8E5D #endif /* GL_OES_shader_multisample_interpolation */ #ifndef GL_OES_standard_derivatives #define GL_OES_standard_derivatives 1 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B #endif /* GL_OES_standard_derivatives */ #ifndef GL_OES_stencil1 #define GL_OES_stencil1 1 #define GL_STENCIL_INDEX1_OES 0x8D46 #endif /* GL_OES_stencil1 */ #ifndef GL_OES_stencil4 #define GL_OES_stencil4 1 #define GL_STENCIL_INDEX4_OES 0x8D47 #endif /* GL_OES_stencil4 */ #ifndef GL_OES_surfaceless_context #define GL_OES_surfaceless_context 1 #define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219 #endif /* GL_OES_surfaceless_context */ #ifndef GL_OES_tessellation_point_size #define GL_OES_tessellation_point_size 1 #endif /* GL_OES_tessellation_point_size */ #ifndef GL_OES_tessellation_shader #define GL_OES_tessellation_shader 1 #define GL_PATCHES_OES 0x000E #define GL_PATCH_VERTICES_OES 0x8E72 #define GL_TESS_CONTROL_OUTPUT_VERTICES_OES 0x8E75 #define GL_TESS_GEN_MODE_OES 0x8E76 #define GL_TESS_GEN_SPACING_OES 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER_OES 0x8E78 #define GL_TESS_GEN_POINT_MODE_OES 0x8E79 #define GL_ISOLINES_OES 0x8E7A #define GL_QUADS_OES 0x0007 #define GL_FRACTIONAL_ODD_OES 0x8E7B #define GL_FRACTIONAL_EVEN_OES 0x8E7C #define GL_MAX_PATCH_VERTICES_OES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS_OES 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES 0x8E1F #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES 0x92CE #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES 0x92D4 #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES 0x90CC #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES 0x90D9 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES 0x8221 #define GL_IS_PER_PATCH_OES 0x92E7 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES 0x9308 #define GL_TESS_CONTROL_SHADER_OES 0x8E88 #define GL_TESS_EVALUATION_SHADER_OES 0x8E87 #define GL_TESS_CONTROL_SHADER_BIT_OES 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT_OES 0x00000010 typedef void (GL_APIENTRYP PFNGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glPatchParameteriOES (GLenum pname, GLint value); #endif #endif /* GL_OES_tessellation_shader */ #ifndef GL_OES_texture_3D #define GL_OES_texture_3D 1 #define GL_TEXTURE_WRAP_R_OES 0x8072 #define GL_TEXTURE_3D_OES 0x806F #define GL_TEXTURE_BINDING_3D_OES 0x806A #define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 #define GL_SAMPLER_3D_OES 0x8B5F #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); #endif #endif /* GL_OES_texture_3D */ #ifndef GL_OES_texture_border_clamp #define GL_OES_texture_border_clamp 1 #define GL_TEXTURE_BORDER_COLOR_OES 0x1004 #define GL_CLAMP_TO_BORDER_OES 0x812D typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexParameterIivOES (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexParameterIuivOES (GLenum target, GLenum pname, const GLuint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIivOES (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIuivOES (GLenum target, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glSamplerParameterIivOES (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterIuivOES (GLuint sampler, GLenum pname, const GLuint *param); GL_APICALL void GL_APIENTRY glGetSamplerParameterIivOES (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterIuivOES (GLuint sampler, GLenum pname, GLuint *params); #endif #endif /* GL_OES_texture_border_clamp */ #ifndef GL_OES_texture_buffer #define GL_OES_texture_buffer 1 #define GL_TEXTURE_BUFFER_OES 0x8C2A #define GL_TEXTURE_BUFFER_BINDING_OES 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_OES 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_OES 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES 0x8C2D #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES 0x919F #define GL_SAMPLER_BUFFER_OES 0x8DC2 #define GL_INT_SAMPLER_BUFFER_OES 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_OES 0x8DD8 #define GL_IMAGE_BUFFER_OES 0x9051 #define GL_INT_IMAGE_BUFFER_OES 0x905C #define GL_UNSIGNED_INT_IMAGE_BUFFER_OES 0x9067 #define GL_TEXTURE_BUFFER_OFFSET_OES 0x919D #define GL_TEXTURE_BUFFER_SIZE_OES 0x919E typedef void (GL_APIENTRYP PFNGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexBufferOES (GLenum target, GLenum internalformat, GLuint buffer); GL_APICALL void GL_APIENTRY glTexBufferRangeOES (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); #endif #endif /* GL_OES_texture_buffer */ #ifndef GL_OES_texture_compression_astc #define GL_OES_texture_compression_astc 1 #define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 #define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 #define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 #define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 #define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 #define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 #define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 #define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 #define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 #define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 #endif /* GL_OES_texture_compression_astc */ #ifndef GL_OES_texture_cube_map_array #define GL_OES_texture_cube_map_array 1 #define GL_TEXTURE_CUBE_MAP_ARRAY_OES 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES 0x900A #define GL_SAMPLER_CUBE_MAP_ARRAY_OES 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES 0x900F #define GL_IMAGE_CUBE_MAP_ARRAY_OES 0x9054 #define GL_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x905F #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES 0x906A #endif /* GL_OES_texture_cube_map_array */ #ifndef GL_OES_texture_float #define GL_OES_texture_float 1 #endif /* GL_OES_texture_float */ #ifndef GL_OES_texture_float_linear #define GL_OES_texture_float_linear 1 #endif /* GL_OES_texture_float_linear */ #ifndef GL_OES_texture_half_float #define GL_OES_texture_half_float 1 #define GL_HALF_FLOAT_OES 0x8D61 #endif /* GL_OES_texture_half_float */ #ifndef GL_OES_texture_half_float_linear #define GL_OES_texture_half_float_linear 1 #endif /* GL_OES_texture_half_float_linear */ #ifndef GL_OES_texture_npot #define GL_OES_texture_npot 1 #endif /* GL_OES_texture_npot */ #ifndef GL_OES_texture_stencil8 #define GL_OES_texture_stencil8 1 #define GL_STENCIL_INDEX_OES 0x1901 #define GL_STENCIL_INDEX8_OES 0x8D48 #endif /* GL_OES_texture_stencil8 */ #ifndef GL_OES_texture_storage_multisample_2d_array #define GL_OES_texture_storage_multisample_2d_array 1 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES 0x9102 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES 0x9105 #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES 0x910D typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexStorage3DMultisampleOES (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); #endif #endif /* GL_OES_texture_storage_multisample_2d_array */ #ifndef GL_OES_texture_view #define GL_OES_texture_view 1 #define GL_TEXTURE_VIEW_MIN_LEVEL_OES 0x82DB #define GL_TEXTURE_VIEW_NUM_LEVELS_OES 0x82DC #define GL_TEXTURE_VIEW_MIN_LAYER_OES 0x82DD #define GL_TEXTURE_VIEW_NUM_LAYERS_OES 0x82DE #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF typedef void (GL_APIENTRYP PFNGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTextureViewOES (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); #endif #endif /* GL_OES_texture_view */ #ifndef GL_OES_vertex_array_object #define GL_OES_vertex_array_object 1 #define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array); GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); #endif #endif /* GL_OES_vertex_array_object */ #ifndef GL_OES_vertex_half_float #define GL_OES_vertex_half_float 1 #endif /* GL_OES_vertex_half_float */ #ifndef GL_OES_vertex_type_10_10_10_2 #define GL_OES_vertex_type_10_10_10_2 1 #define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 #define GL_INT_10_10_10_2_OES 0x8DF7 #endif /* GL_OES_vertex_type_10_10_10_2 */ #ifndef GL_AMD_compressed_3DC_texture #define GL_AMD_compressed_3DC_texture 1 #define GL_3DC_X_AMD 0x87F9 #define GL_3DC_XY_AMD 0x87FA #endif /* GL_AMD_compressed_3DC_texture */ #ifndef GL_AMD_compressed_ATC_texture #define GL_AMD_compressed_ATC_texture 1 #define GL_ATC_RGB_AMD 0x8C92 #define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 #define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE #endif /* GL_AMD_compressed_ATC_texture */ #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 #define GL_COUNTER_TYPE_AMD 0x8BC0 #define GL_COUNTER_RANGE_AMD 0x8BC1 #define GL_UNSIGNED_INT64_AMD 0x8BC2 #define GL_PERCENTAGE_AMD 0x8BC3 #define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 #define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 #define GL_PERFMON_RESULT_AMD 0x8BC6 typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor); GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif #endif /* GL_AMD_performance_monitor */ #ifndef GL_AMD_program_binary_Z400 #define GL_AMD_program_binary_Z400 1 #define GL_Z400_BINARY_AMD 0x8740 #endif /* GL_AMD_program_binary_Z400 */ #ifndef GL_ANDROID_extension_pack_es31a #define GL_ANDROID_extension_pack_es31a 1 #endif /* GL_ANDROID_extension_pack_es31a */ #ifndef GL_ANGLE_depth_texture #define GL_ANGLE_depth_texture 1 #endif /* GL_ANGLE_depth_texture */ #ifndef GL_ANGLE_framebuffer_blit #define GL_ANGLE_framebuffer_blit 1 #define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8 #define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif #endif /* GL_ANGLE_framebuffer_blit */ #ifndef GL_ANGLE_framebuffer_multisample #define GL_ANGLE_framebuffer_multisample 1 #define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56 #define GL_MAX_SAMPLES_ANGLE 0x8D57 typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_ANGLE_framebuffer_multisample */ #ifndef GL_ANGLE_instanced_arrays #define GL_ANGLE_instanced_arrays 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor); #endif #endif /* GL_ANGLE_instanced_arrays */ #ifndef GL_ANGLE_pack_reverse_row_order #define GL_ANGLE_pack_reverse_row_order 1 #define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 #endif /* GL_ANGLE_pack_reverse_row_order */ #ifndef GL_ANGLE_program_binary #define GL_ANGLE_program_binary 1 #define GL_PROGRAM_BINARY_ANGLE 0x93A6 #endif /* GL_ANGLE_program_binary */ #ifndef GL_ANGLE_texture_compression_dxt3 #define GL_ANGLE_texture_compression_dxt3 1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 #endif /* GL_ANGLE_texture_compression_dxt3 */ #ifndef GL_ANGLE_texture_compression_dxt5 #define GL_ANGLE_texture_compression_dxt5 1 #define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 #endif /* GL_ANGLE_texture_compression_dxt5 */ #ifndef GL_ANGLE_texture_usage #define GL_ANGLE_texture_usage 1 #define GL_TEXTURE_USAGE_ANGLE 0x93A2 #define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 #endif /* GL_ANGLE_texture_usage */ #ifndef GL_ANGLE_translated_shader_source #define GL_ANGLE_translated_shader_source 1 #define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); #endif #endif /* GL_ANGLE_translated_shader_source */ #ifndef GL_APPLE_clip_distance #define GL_APPLE_clip_distance 1 #define GL_MAX_CLIP_DISTANCES_APPLE 0x0D32 #define GL_CLIP_DISTANCE0_APPLE 0x3000 #define GL_CLIP_DISTANCE1_APPLE 0x3001 #define GL_CLIP_DISTANCE2_APPLE 0x3002 #define GL_CLIP_DISTANCE3_APPLE 0x3003 #define GL_CLIP_DISTANCE4_APPLE 0x3004 #define GL_CLIP_DISTANCE5_APPLE 0x3005 #define GL_CLIP_DISTANCE6_APPLE 0x3006 #define GL_CLIP_DISTANCE7_APPLE 0x3007 #endif /* GL_APPLE_clip_distance */ #ifndef GL_APPLE_color_buffer_packed_float #define GL_APPLE_color_buffer_packed_float 1 #endif /* GL_APPLE_color_buffer_packed_float */ #ifndef GL_APPLE_copy_texture_levels #define GL_APPLE_copy_texture_levels 1 typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount); #endif #endif /* GL_APPLE_copy_texture_levels */ #ifndef GL_APPLE_framebuffer_multisample #define GL_APPLE_framebuffer_multisample 1 #define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 #define GL_MAX_SAMPLES_APPLE 0x8D57 #define GL_READ_FRAMEBUFFER_APPLE 0x8CA8 #define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void); #endif #endif /* GL_APPLE_framebuffer_multisample */ #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 #define GL_RGB_422_APPLE 0x8A1F #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #define GL_RGB_RAW_422_APPLE 0x8A51 #endif /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_sync #define GL_APPLE_sync 1 #define GL_SYNC_OBJECT_APPLE 0x8A53 #define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111 #define GL_OBJECT_TYPE_APPLE 0x9112 #define GL_SYNC_CONDITION_APPLE 0x9113 #define GL_SYNC_STATUS_APPLE 0x9114 #define GL_SYNC_FLAGS_APPLE 0x9115 #define GL_SYNC_FENCE_APPLE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117 #define GL_UNSIGNALED_APPLE 0x9118 #define GL_SIGNALED_APPLE 0x9119 #define GL_ALREADY_SIGNALED_APPLE 0x911A #define GL_TIMEOUT_EXPIRED_APPLE 0x911B #define GL_CONDITION_SATISFIED_APPLE 0x911C #define GL_WAIT_FAILED_APPLE 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001 #define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync); typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync); typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags); GL_APICALL GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync); GL_APICALL void GL_APIENTRY glDeleteSyncAPPLE (GLsync sync); GL_APICALL GLenum GL_APIENTRY glClientWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params); GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #endif #endif /* GL_APPLE_sync */ #ifndef GL_APPLE_texture_format_BGRA8888 #define GL_APPLE_texture_format_BGRA8888 1 #define GL_BGRA_EXT 0x80E1 #define GL_BGRA8_EXT 0x93A1 #endif /* GL_APPLE_texture_format_BGRA8888 */ #ifndef GL_APPLE_texture_max_level #define GL_APPLE_texture_max_level 1 #define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D #endif /* GL_APPLE_texture_max_level */ #ifndef GL_APPLE_texture_packed_float #define GL_APPLE_texture_packed_float 1 #define GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE 0x8C3B #define GL_UNSIGNED_INT_5_9_9_9_REV_APPLE 0x8C3E #define GL_R11F_G11F_B10F_APPLE 0x8C3A #define GL_RGB9_E5_APPLE 0x8C3D #endif /* GL_APPLE_texture_packed_float */ #ifndef GL_ARM_mali_program_binary #define GL_ARM_mali_program_binary 1 #define GL_MALI_PROGRAM_BINARY_ARM 0x8F61 #endif /* GL_ARM_mali_program_binary */ #ifndef GL_ARM_mali_shader_binary #define GL_ARM_mali_shader_binary 1 #define GL_MALI_SHADER_BINARY_ARM 0x8F60 #endif /* GL_ARM_mali_shader_binary */ #ifndef GL_ARM_rgba8 #define GL_ARM_rgba8 1 #endif /* GL_ARM_rgba8 */ #ifndef GL_ARM_shader_framebuffer_fetch #define GL_ARM_shader_framebuffer_fetch 1 #define GL_FETCH_PER_SAMPLE_ARM 0x8F65 #define GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM 0x8F66 #endif /* GL_ARM_shader_framebuffer_fetch */ #ifndef GL_ARM_shader_framebuffer_fetch_depth_stencil #define GL_ARM_shader_framebuffer_fetch_depth_stencil 1 #endif /* GL_ARM_shader_framebuffer_fetch_depth_stencil */ #ifndef GL_DMP_program_binary #define GL_DMP_program_binary 1 #define GL_SMAPHS30_PROGRAM_BINARY_DMP 0x9251 #define GL_SMAPHS_PROGRAM_BINARY_DMP 0x9252 #define GL_DMP_PROGRAM_BINARY_DMP 0x9253 #endif /* GL_DMP_program_binary */ #ifndef GL_DMP_shader_binary #define GL_DMP_shader_binary 1 #define GL_SHADER_BINARY_DMP 0x9250 #endif /* GL_DMP_shader_binary */ #ifndef GL_EXT_YUV_target #define GL_EXT_YUV_target 1 #define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 #endif /* GL_EXT_YUV_target */ #ifndef GL_EXT_base_instance #define GL_EXT_base_instance 1 typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedBaseInstanceEXT (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseInstanceEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertexBaseInstanceEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); #endif #endif /* GL_EXT_base_instance */ #ifndef GL_EXT_blend_func_extended #define GL_EXT_blend_func_extended 1 #define GL_SRC1_COLOR_EXT 0x88F9 #define GL_SRC1_ALPHA_EXT 0x8589 #define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA #define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB #define GL_SRC_ALPHA_SATURATE_EXT 0x0308 #define GL_LOCATION_INDEX_EXT 0x930F #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC typedef void (GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); typedef void (GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef GLint (GL_APIENTRYP PFNGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBindFragDataLocationIndexedEXT (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); GL_APICALL void GL_APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); GL_APICALL GLint GL_APIENTRY glGetProgramResourceLocationIndexEXT (GLuint program, GLenum programInterface, const GLchar *name); GL_APICALL GLint GL_APIENTRY glGetFragDataIndexEXT (GLuint program, const GLchar *name); #endif #endif /* GL_EXT_blend_func_extended */ #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #endif /* GL_EXT_blend_minmax */ #ifndef GL_EXT_buffer_storage #define GL_EXT_buffer_storage 1 #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_PERSISTENT_BIT_EXT 0x0040 #define GL_MAP_COHERENT_BIT_EXT 0x0080 #define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100 #define GL_CLIENT_STORAGE_BIT_EXT 0x0200 #define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000 #define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F #define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220 typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBufferStorageEXT (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); #endif #endif /* GL_EXT_buffer_storage */ #ifndef GL_EXT_color_buffer_float #define GL_EXT_color_buffer_float 1 #endif /* GL_EXT_color_buffer_float */ #ifndef GL_EXT_color_buffer_half_float #define GL_EXT_color_buffer_half_float 1 #define GL_RGBA16F_EXT 0x881A #define GL_RGB16F_EXT 0x881B #define GL_RG16F_EXT 0x822F #define GL_R16F_EXT 0x822D #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 #define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 #endif /* GL_EXT_color_buffer_half_float */ #ifndef GL_EXT_copy_image #define GL_EXT_copy_image 1 typedef void (GL_APIENTRYP PFNGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCopyImageSubDataEXT (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); #endif #endif /* GL_EXT_copy_image */ #ifndef GL_EXT_debug_label #define GL_EXT_debug_label 1 #define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F #define GL_PROGRAM_OBJECT_EXT 0x8B40 #define GL_SHADER_OBJECT_EXT 0x8B48 #define GL_BUFFER_OBJECT_EXT 0x9151 #define GL_QUERY_OBJECT_EXT 0x9153 #define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 #define GL_TRANSFORM_FEEDBACK 0x8E22 typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #endif #endif /* GL_EXT_debug_label */ #ifndef GL_EXT_debug_marker #define GL_EXT_debug_marker 1 typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void); #endif #endif /* GL_EXT_debug_marker */ #ifndef GL_EXT_discard_framebuffer #define GL_EXT_discard_framebuffer 1 #define GL_COLOR_EXT 0x1800 #define GL_DEPTH_EXT 0x1801 #define GL_STENCIL_EXT 0x1802 typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif #endif /* GL_EXT_discard_framebuffer */ #ifndef GL_EXT_disjoint_timer_query #define GL_EXT_disjoint_timer_query 1 #define GL_QUERY_COUNTER_BITS_EXT 0x8864 #define GL_CURRENT_QUERY_EXT 0x8865 #define GL_QUERY_RESULT_EXT 0x8866 #define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 #define GL_TIME_ELAPSED_EXT 0x88BF #define GL_TIMESTAMP_EXT 0x8E28 #define GL_GPU_DISJOINT_EXT 0x8FBB typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids); typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target); typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids); GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id); GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target); GL_APICALL void GL_APIENTRY glQueryCounterEXT (GLuint id, GLenum target); GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectivEXT (GLuint id, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); GL_APICALL void GL_APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); #endif #endif /* GL_EXT_disjoint_timer_query */ #ifndef GL_EXT_draw_buffers #define GL_EXT_draw_buffers 1 #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_MAX_DRAW_BUFFERS_EXT 0x8824 #define GL_DRAW_BUFFER0_EXT 0x8825 #define GL_DRAW_BUFFER1_EXT 0x8826 #define GL_DRAW_BUFFER2_EXT 0x8827 #define GL_DRAW_BUFFER3_EXT 0x8828 #define GL_DRAW_BUFFER4_EXT 0x8829 #define GL_DRAW_BUFFER5_EXT 0x882A #define GL_DRAW_BUFFER6_EXT 0x882B #define GL_DRAW_BUFFER7_EXT 0x882C #define GL_DRAW_BUFFER8_EXT 0x882D #define GL_DRAW_BUFFER9_EXT 0x882E #define GL_DRAW_BUFFER10_EXT 0x882F #define GL_DRAW_BUFFER11_EXT 0x8830 #define GL_DRAW_BUFFER12_EXT 0x8831 #define GL_DRAW_BUFFER13_EXT 0x8832 #define GL_DRAW_BUFFER14_EXT 0x8833 #define GL_DRAW_BUFFER15_EXT 0x8834 #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei n, const GLenum *bufs); #endif #endif /* GL_EXT_draw_buffers */ #ifndef GL_EXT_draw_buffers_indexed #define GL_EXT_draw_buffers_indexed 1 typedef void (GL_APIENTRYP PFNGLENABLEIEXTPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLDISABLEIEXTPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (GL_APIENTRYP PFNGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDIEXTPROC) (GLenum target, GLuint index); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glEnableiEXT (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glDisableiEXT (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glBlendEquationiEXT (GLuint buf, GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparateiEXT (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunciEXT (GLuint buf, GLenum src, GLenum dst); GL_APICALL void GL_APIENTRY glBlendFuncSeparateiEXT (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GL_APICALL void GL_APIENTRY glColorMaskiEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GL_APICALL GLboolean GL_APIENTRY glIsEnablediEXT (GLenum target, GLuint index); #endif #endif /* GL_EXT_draw_buffers_indexed */ #ifndef GL_EXT_draw_elements_base_vertex #define GL_EXT_draw_elements_base_vertex 1 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawElementsBaseVertexEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawRangeElementsBaseVertexEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertexEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex); #endif #endif /* GL_EXT_draw_elements_base_vertex */ #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_EXT_draw_instanced */ #ifndef GL_EXT_float_blend #define GL_EXT_float_blend 1 #endif /* GL_EXT_float_blend */ #ifndef GL_EXT_geometry_point_size #define GL_EXT_geometry_point_size 1 #endif /* GL_EXT_geometry_point_size */ #ifndef GL_EXT_geometry_shader #define GL_EXT_geometry_shader 1 #define GL_GEOMETRY_SHADER_EXT 0x8DD9 #define GL_GEOMETRY_SHADER_BIT_EXT 0x00000004 #define GL_GEOMETRY_LINKED_VERTICES_OUT_EXT 0x8916 #define GL_GEOMETRY_LINKED_INPUT_TYPE_EXT 0x8917 #define GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT 0x8918 #define GL_GEOMETRY_SHADER_INVOCATIONS_EXT 0x887F #define GL_LAYER_PROVOKING_VERTEX_EXT 0x825E #define GL_LINES_ADJACENCY_EXT 0x000A #define GL_LINE_STRIP_ADJACENCY_EXT 0x000B #define GL_TRIANGLES_ADJACENCY_EXT 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT 0x8A2C #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8A32 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT 0x9124 #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT 0x8E5A #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT 0x92CF #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT 0x92D5 #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT 0x90CD #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT 0x90D7 #define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D #define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E #define GL_UNDEFINED_VERTEX_EXT 0x8260 #define GL_PRIMITIVES_GENERATED_EXT 0x8C87 #define GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT 0x9312 #define GL_MAX_FRAMEBUFFER_LAYERS_EXT 0x9317 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_REFERENCED_BY_GEOMETRY_SHADER_EXT 0x9309 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); #endif #endif /* GL_EXT_geometry_shader */ #ifndef GL_EXT_gpu_shader5 #define GL_EXT_gpu_shader5 1 #endif /* GL_EXT_gpu_shader5 */ #ifndef GL_EXT_instanced_arrays #define GL_EXT_instanced_arrays 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT 0x88FE typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glVertexAttribDivisorEXT (GLuint index, GLuint divisor); #endif #endif /* GL_EXT_instanced_arrays */ #ifndef GL_EXT_map_buffer_range #define GL_EXT_map_buffer_range 1 #define GL_MAP_READ_BIT_EXT 0x0001 #define GL_MAP_WRITE_BIT_EXT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020 typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void *GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length); #endif #endif /* GL_EXT_map_buffer_range */ #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #endif #endif /* GL_EXT_multi_draw_arrays */ #ifndef GL_EXT_multi_draw_indirect #define GL_EXT_multi_draw_indirect 1 typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glMultiDrawArraysIndirectEXT (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); GL_APICALL void GL_APIENTRY glMultiDrawElementsIndirectEXT (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); #endif #endif /* GL_EXT_multi_draw_indirect */ #ifndef GL_EXT_multisampled_compatibility #define GL_EXT_multisampled_compatibility 1 #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #endif /* GL_EXT_multisampled_compatibility */ #ifndef GL_EXT_multisampled_render_to_texture #define GL_EXT_multisampled_render_to_texture 1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif #endif /* GL_EXT_multisampled_render_to_texture */ #ifndef GL_EXT_multiview_draw_buffers #define GL_EXT_multiview_draw_buffers 1 #define GL_COLOR_ATTACHMENT_EXT 0x90F0 #define GL_MULTIVIEW_EXT 0x90F1 #define GL_DRAW_BUFFER_EXT 0x0C01 #define GL_READ_BUFFER_EXT 0x0C02 #define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2 typedef void (GL_APIENTRYP PFNGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index); typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices); typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBufferIndexedEXT (GLenum src, GLint index); GL_APICALL void GL_APIENTRY glDrawBuffersIndexedEXT (GLint n, const GLenum *location, const GLint *indices); GL_APICALL void GL_APIENTRY glGetIntegeri_vEXT (GLenum target, GLuint index, GLint *data); #endif #endif /* GL_EXT_multiview_draw_buffers */ #ifndef GL_EXT_occlusion_query_boolean #define GL_EXT_occlusion_query_boolean 1 #define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A #endif /* GL_EXT_occlusion_query_boolean */ #ifndef GL_EXT_post_depth_coverage #define GL_EXT_post_depth_coverage 1 #endif /* GL_EXT_post_depth_coverage */ #ifndef GL_EXT_primitive_bounding_box #define GL_EXT_primitive_bounding_box 1 #define GL_PRIMITIVE_BOUNDING_BOX_EXT 0x92BE typedef void (GL_APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glPrimitiveBoundingBoxEXT (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #endif #endif /* GL_EXT_primitive_bounding_box */ #ifndef GL_EXT_pvrtc_sRGB #define GL_EXT_pvrtc_sRGB 1 #define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 #define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 #define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 #define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 #define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0 #define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1 #endif /* GL_EXT_pvrtc_sRGB */ #ifndef GL_EXT_raster_multisample #define GL_EXT_raster_multisample 1 #define GL_RASTER_MULTISAMPLE_EXT 0x9327 #define GL_RASTER_SAMPLES_EXT 0x9328 #define GL_MAX_RASTER_SAMPLES_EXT 0x9329 #define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A #define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B #define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C typedef void (GL_APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations); #endif #endif /* GL_EXT_raster_multisample */ #ifndef GL_EXT_read_format_bgra #define GL_EXT_read_format_bgra 1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 #endif /* GL_EXT_read_format_bgra */ #ifndef GL_EXT_render_snorm #define GL_EXT_render_snorm 1 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGBA8_SNORM 0x8F97 #define GL_R16_SNORM_EXT 0x8F98 #define GL_RG16_SNORM_EXT 0x8F99 #define GL_RGBA16_SNORM_EXT 0x8F9B #endif /* GL_EXT_render_snorm */ #ifndef GL_EXT_robustness #define GL_EXT_robustness 1 #define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 #define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 #define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 #define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 #define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 #define GL_NO_RESET_NOTIFICATION_EXT 0x8261 typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); #endif #endif /* GL_EXT_robustness */ #ifndef GL_EXT_sRGB #define GL_EXT_sRGB 1 #define GL_SRGB_EXT 0x8C40 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 #endif /* GL_EXT_sRGB */ #ifndef GL_EXT_sRGB_write_control #define GL_EXT_sRGB_write_control 1 #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #endif /* GL_EXT_sRGB_write_control */ #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 #define GL_ACTIVE_PROGRAM_EXT 0x8259 #define GL_VERTEX_SHADER_BIT_EXT 0x00000001 #define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 #define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE_EXT 0x8258 #define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program); typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines); typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program); GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline); GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings); GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines); GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines); GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params); GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline); GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program); GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline); GL_APICALL void GL_APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif #endif /* GL_EXT_separate_shader_objects */ #ifndef GL_EXT_shader_framebuffer_fetch #define GL_EXT_shader_framebuffer_fetch 1 #define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 #endif /* GL_EXT_shader_framebuffer_fetch */ #ifndef GL_EXT_shader_implicit_conversions #define GL_EXT_shader_implicit_conversions 1 #endif /* GL_EXT_shader_implicit_conversions */ #ifndef GL_EXT_shader_integer_mix #define GL_EXT_shader_integer_mix 1 #endif /* GL_EXT_shader_integer_mix */ #ifndef GL_EXT_shader_io_blocks #define GL_EXT_shader_io_blocks 1 #endif /* GL_EXT_shader_io_blocks */ #ifndef GL_EXT_shader_pixel_local_storage #define GL_EXT_shader_pixel_local_storage 1 #define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 #define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT 0x8F67 #define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 #endif /* GL_EXT_shader_pixel_local_storage */ #ifndef GL_EXT_shader_texture_lod #define GL_EXT_shader_texture_lod 1 #endif /* GL_EXT_shader_texture_lod */ #ifndef GL_EXT_shadow_samplers #define GL_EXT_shadow_samplers 1 #define GL_TEXTURE_COMPARE_MODE_EXT 0x884C #define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D #define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E #define GL_SAMPLER_2D_SHADOW_EXT 0x8B62 #endif /* GL_EXT_shadow_samplers */ #ifndef GL_EXT_sparse_texture #define GL_EXT_sparse_texture 1 #define GL_TEXTURE_SPARSE_EXT 0x91A6 #define GL_VIRTUAL_PAGE_SIZE_INDEX_EXT 0x91A7 #define GL_NUM_SPARSE_LEVELS_EXT 0x91AA #define GL_NUM_VIRTUAL_PAGE_SIZES_EXT 0x91A8 #define GL_VIRTUAL_PAGE_SIZE_X_EXT 0x9195 #define GL_VIRTUAL_PAGE_SIZE_Y_EXT 0x9196 #define GL_VIRTUAL_PAGE_SIZE_Z_EXT 0x9197 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_3D 0x806F #define GL_MAX_SPARSE_TEXTURE_SIZE_EXT 0x9198 #define GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT 0x9199 #define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT 0x919A #define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT 0x91A9 typedef void (GL_APIENTRYP PFNGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexPageCommitmentEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); #endif #endif /* GL_EXT_sparse_texture */ #ifndef GL_EXT_tessellation_point_size #define GL_EXT_tessellation_point_size 1 #endif /* GL_EXT_tessellation_point_size */ #ifndef GL_EXT_tessellation_shader #define GL_EXT_tessellation_shader 1 #define GL_PATCHES_EXT 0x000E #define GL_PATCH_VERTICES_EXT 0x8E72 #define GL_TESS_CONTROL_OUTPUT_VERTICES_EXT 0x8E75 #define GL_TESS_GEN_MODE_EXT 0x8E76 #define GL_TESS_GEN_SPACING_EXT 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER_EXT 0x8E78 #define GL_TESS_GEN_POINT_MODE_EXT 0x8E79 #define GL_ISOLINES_EXT 0x8E7A #define GL_QUADS_EXT 0x0007 #define GL_FRACTIONAL_ODD_EXT 0x8E7B #define GL_FRACTIONAL_EVEN_EXT 0x8E7C #define GL_MAX_PATCH_VERTICES_EXT 0x8E7D #define GL_MAX_TESS_GEN_LEVEL_EXT 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS_EXT 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT 0x8E1F #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT 0x92CE #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT 0x92D4 #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT 0x90CC #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT 0x90D9 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 #define GL_IS_PER_PATCH_EXT 0x92E7 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT 0x9308 #define GL_TESS_CONTROL_SHADER_EXT 0x8E88 #define GL_TESS_EVALUATION_SHADER_EXT 0x8E87 #define GL_TESS_CONTROL_SHADER_BIT_EXT 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT_EXT 0x00000010 typedef void (GL_APIENTRYP PFNGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glPatchParameteriEXT (GLenum pname, GLint value); #endif #endif /* GL_EXT_tessellation_shader */ #ifndef GL_EXT_texture_border_clamp #define GL_EXT_texture_border_clamp 1 #define GL_TEXTURE_BORDER_COLOR_EXT 0x1004 #define GL_CLAMP_TO_BORDER_EXT 0x812D typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glSamplerParameterIivEXT (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterIuivEXT (GLuint sampler, GLenum pname, const GLuint *param); GL_APICALL void GL_APIENTRY glGetSamplerParameterIivEXT (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterIuivEXT (GLuint sampler, GLenum pname, GLuint *params); #endif #endif /* GL_EXT_texture_border_clamp */ #ifndef GL_EXT_texture_buffer #define GL_EXT_texture_buffer 1 #define GL_TEXTURE_BUFFER_EXT 0x8C2A #define GL_TEXTURE_BUFFER_BINDING_EXT 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT 0x919F #define GL_SAMPLER_BUFFER_EXT 0x8DC2 #define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 #define GL_IMAGE_BUFFER_EXT 0x9051 #define GL_INT_IMAGE_BUFFER_EXT 0x905C #define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 #define GL_TEXTURE_BUFFER_OFFSET_EXT 0x919D #define GL_TEXTURE_BUFFER_SIZE_EXT 0x919E typedef void (GL_APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); GL_APICALL void GL_APIENTRY glTexBufferRangeEXT (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); #endif #endif /* GL_EXT_texture_buffer */ #ifndef GL_EXT_texture_compression_dxt1 #define GL_EXT_texture_compression_dxt1 1 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #endif /* GL_EXT_texture_compression_dxt1 */ #ifndef GL_EXT_texture_compression_s3tc #define GL_EXT_texture_compression_s3tc 1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif /* GL_EXT_texture_compression_s3tc */ #ifndef GL_EXT_texture_cube_map_array #define GL_EXT_texture_cube_map_array 1 #define GL_TEXTURE_CUBE_MAP_ARRAY_EXT 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT 0x900A #define GL_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT 0x900F #define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 #define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A #endif /* GL_EXT_texture_cube_map_array */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_minmax #define GL_EXT_texture_filter_minmax 1 #endif /* GL_EXT_texture_filter_minmax */ #ifndef GL_EXT_texture_format_BGRA8888 #define GL_EXT_texture_format_BGRA8888 1 #endif /* GL_EXT_texture_format_BGRA8888 */ #ifndef GL_EXT_texture_norm16 #define GL_EXT_texture_norm16 1 #define GL_R16_EXT 0x822A #define GL_RG16_EXT 0x822C #define GL_RGBA16_EXT 0x805B #define GL_RGB16_EXT 0x8054 #define GL_RGB16_SNORM_EXT 0x8F9A #endif /* GL_EXT_texture_norm16 */ #ifndef GL_EXT_texture_rg #define GL_EXT_texture_rg 1 #define GL_RED_EXT 0x1903 #define GL_RG_EXT 0x8227 #define GL_R8_EXT 0x8229 #define GL_RG8_EXT 0x822B #endif /* GL_EXT_texture_rg */ #ifndef GL_EXT_texture_sRGB_R8 #define GL_EXT_texture_sRGB_R8 1 #define GL_SR8_EXT 0x8FBD #endif /* GL_EXT_texture_sRGB_R8 */ #ifndef GL_EXT_texture_sRGB_RG8 #define GL_EXT_texture_sRGB_RG8 1 #define GL_SRG8_EXT 0x8FBE #endif /* GL_EXT_texture_sRGB_RG8 */ #ifndef GL_EXT_texture_sRGB_decode #define GL_EXT_texture_sRGB_decode 1 #define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 #define GL_DECODE_EXT 0x8A49 #define GL_SKIP_DECODE_EXT 0x8A4A #endif /* GL_EXT_texture_sRGB_decode */ #ifndef GL_EXT_texture_storage #define GL_EXT_texture_storage 1 #define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F #define GL_ALPHA8_EXT 0x803C #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_RGBA32F_EXT 0x8814 #define GL_RGB32F_EXT 0x8815 #define GL_ALPHA32F_EXT 0x8816 #define GL_LUMINANCE32F_EXT 0x8818 #define GL_LUMINANCE_ALPHA32F_EXT 0x8819 #define GL_ALPHA16F_EXT 0x881C #define GL_LUMINANCE16F_EXT 0x881E #define GL_LUMINANCE_ALPHA16F_EXT 0x881F #define GL_R32F_EXT 0x822E #define GL_RG32F_EXT 0x8230 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif #endif /* GL_EXT_texture_storage */ #ifndef GL_EXT_texture_type_2_10_10_10_REV #define GL_EXT_texture_type_2_10_10_10_REV 1 #define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 #endif /* GL_EXT_texture_type_2_10_10_10_REV */ #ifndef GL_EXT_texture_view #define GL_EXT_texture_view 1 #define GL_TEXTURE_VIEW_MIN_LEVEL_EXT 0x82DB #define GL_TEXTURE_VIEW_NUM_LEVELS_EXT 0x82DC #define GL_TEXTURE_VIEW_MIN_LAYER_EXT 0x82DD #define GL_TEXTURE_VIEW_NUM_LAYERS_EXT 0x82DE typedef void (GL_APIENTRYP PFNGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTextureViewEXT (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); #endif #endif /* GL_EXT_texture_view */ #ifndef GL_EXT_unpack_subimage #define GL_EXT_unpack_subimage 1 #define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2 #define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3 #define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 #endif /* GL_EXT_unpack_subimage */ #ifndef GL_FJ_shader_binary_GCCSO #define GL_FJ_shader_binary_GCCSO 1 #define GL_GCCSO_SHADER_BINARY_FJ 0x9260 #endif /* GL_FJ_shader_binary_GCCSO */ #ifndef GL_IMG_multisampled_render_to_texture #define GL_IMG_multisampled_render_to_texture 1 #define GL_RENDERBUFFER_SAMPLES_IMG 0x9133 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134 #define GL_MAX_SAMPLES_IMG 0x9135 #define GL_TEXTURE_SAMPLES_IMG 0x9136 typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif #endif /* GL_IMG_multisampled_render_to_texture */ #ifndef GL_IMG_program_binary #define GL_IMG_program_binary 1 #define GL_SGX_PROGRAM_BINARY_IMG 0x9130 #endif /* GL_IMG_program_binary */ #ifndef GL_IMG_read_format #define GL_IMG_read_format 1 #define GL_BGRA_IMG 0x80E1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365 #endif /* GL_IMG_read_format */ #ifndef GL_IMG_shader_binary #define GL_IMG_shader_binary 1 #define GL_SGX_BINARY_IMG 0x8C0A #endif /* GL_IMG_shader_binary */ #ifndef GL_IMG_texture_compression_pvrtc #define GL_IMG_texture_compression_pvrtc 1 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 #endif /* GL_IMG_texture_compression_pvrtc */ #ifndef GL_IMG_texture_compression_pvrtc2 #define GL_IMG_texture_compression_pvrtc2 1 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138 #endif /* GL_IMG_texture_compression_pvrtc2 */ #ifndef GL_IMG_texture_filter_cubic #define GL_IMG_texture_filter_cubic 1 #define GL_CUBIC_IMG 0x9139 #define GL_CUBIC_MIPMAP_NEAREST_IMG 0x913A #define GL_CUBIC_MIPMAP_LINEAR_IMG 0x913B #endif /* GL_IMG_texture_filter_cubic */ #ifndef GL_INTEL_framebuffer_CMAA #define GL_INTEL_framebuffer_CMAA 1 typedef void (GL_APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); #endif #endif /* GL_INTEL_framebuffer_CMAA */ #ifndef GL_INTEL_performance_query #define GL_INTEL_performance_query 1 #define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 #define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 #define GL_PERFQUERY_WAIT_INTEL 0x83FB #define GL_PERFQUERY_FLUSH_INTEL 0x83FA #define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 #define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 #define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 #define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 #define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 #define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 #define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 #define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 #define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 #define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA #define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB #define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC #define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD #define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE #define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF #define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 typedef void (GL_APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (GL_APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); typedef void (GL_APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (GL_APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (GL_APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); typedef void (GL_APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); typedef void (GL_APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); typedef void (GL_APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); typedef void (GL_APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); typedef void (GL_APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); GL_APICALL void GL_APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); GL_APICALL void GL_APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); GL_APICALL void GL_APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); GL_APICALL void GL_APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); GL_APICALL void GL_APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); GL_APICALL void GL_APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); GL_APICALL void GL_APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); GL_APICALL void GL_APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); GL_APICALL void GL_APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); #endif #endif /* GL_INTEL_performance_query */ #ifndef GL_NV_bindless_texture #define GL_NV_bindless_texture 1 typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); typedef void (GL_APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); typedef void (GL_APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); typedef GLuint64 (GL_APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); typedef void (GL_APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); typedef void (GL_APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); typedef GLboolean (GL_APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLuint64 GL_APIENTRY glGetTextureHandleNV (GLuint texture); GL_APICALL GLuint64 GL_APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); GL_APICALL void GL_APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); GL_APICALL void GL_APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); GL_APICALL GLuint64 GL_APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); GL_APICALL void GL_APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); GL_APICALL void GL_APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); GL_APICALL void GL_APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); GL_APICALL void GL_APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); GL_APICALL void GL_APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); GL_APICALL void GL_APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); GL_APICALL GLboolean GL_APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); GL_APICALL GLboolean GL_APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #endif #endif /* GL_NV_bindless_texture */ #ifndef GL_NV_blend_equation_advanced #define GL_NV_blend_equation_advanced 1 #define GL_BLEND_OVERLAP_NV 0x9281 #define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 #define GL_BLUE_NV 0x1905 #define GL_COLORBURN_NV 0x929A #define GL_COLORDODGE_NV 0x9299 #define GL_CONJOINT_NV 0x9284 #define GL_CONTRAST_NV 0x92A1 #define GL_DARKEN_NV 0x9297 #define GL_DIFFERENCE_NV 0x929E #define GL_DISJOINT_NV 0x9283 #define GL_DST_ATOP_NV 0x928F #define GL_DST_IN_NV 0x928B #define GL_DST_NV 0x9287 #define GL_DST_OUT_NV 0x928D #define GL_DST_OVER_NV 0x9289 #define GL_EXCLUSION_NV 0x92A0 #define GL_GREEN_NV 0x1904 #define GL_HARDLIGHT_NV 0x929B #define GL_HARDMIX_NV 0x92A9 #define GL_HSL_COLOR_NV 0x92AF #define GL_HSL_HUE_NV 0x92AD #define GL_HSL_LUMINOSITY_NV 0x92B0 #define GL_HSL_SATURATION_NV 0x92AE #define GL_INVERT_OVG_NV 0x92B4 #define GL_INVERT_RGB_NV 0x92A3 #define GL_LIGHTEN_NV 0x9298 #define GL_LINEARBURN_NV 0x92A5 #define GL_LINEARDODGE_NV 0x92A4 #define GL_LINEARLIGHT_NV 0x92A7 #define GL_MINUS_CLAMPED_NV 0x92B3 #define GL_MINUS_NV 0x929F #define GL_MULTIPLY_NV 0x9294 #define GL_OVERLAY_NV 0x9296 #define GL_PINLIGHT_NV 0x92A8 #define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 #define GL_PLUS_CLAMPED_NV 0x92B1 #define GL_PLUS_DARKER_NV 0x9292 #define GL_PLUS_NV 0x9291 #define GL_RED_NV 0x1903 #define GL_SCREEN_NV 0x9295 #define GL_SOFTLIGHT_NV 0x929C #define GL_SRC_ATOP_NV 0x928E #define GL_SRC_IN_NV 0x928A #define GL_SRC_NV 0x9286 #define GL_SRC_OUT_NV 0x928C #define GL_SRC_OVER_NV 0x9288 #define GL_UNCORRELATED_NV 0x9282 #define GL_VIVIDLIGHT_NV 0x92A6 #define GL_XOR_NV 0x1506 typedef void (GL_APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBlendParameteriNV (GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glBlendBarrierNV (void); #endif #endif /* GL_NV_blend_equation_advanced */ #ifndef GL_NV_blend_equation_advanced_coherent #define GL_NV_blend_equation_advanced_coherent 1 #define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 #endif /* GL_NV_blend_equation_advanced_coherent */ #ifndef GL_NV_conditional_render #define GL_NV_conditional_render 1 #define GL_QUERY_WAIT_NV 0x8E13 #define GL_QUERY_NO_WAIT_NV 0x8E14 #define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 typedef void (GL_APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); typedef void (GL_APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); GL_APICALL void GL_APIENTRY glEndConditionalRenderNV (void); #endif #endif /* GL_NV_conditional_render */ #ifndef GL_NV_conservative_raster #define GL_NV_conservative_raster 1 #define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 #define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347 #define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348 #define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349 typedef void (GL_APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits); #endif #endif /* GL_NV_conservative_raster */ #ifndef GL_NV_copy_buffer #define GL_NV_copy_buffer 1 #define GL_COPY_READ_BUFFER_NV 0x8F36 #define GL_COPY_WRITE_BUFFER_NV 0x8F37 typedef void (GL_APIENTRYP PFNGLCOPYBUFFERSUBDATANVPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCopyBufferSubDataNV (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif #endif /* GL_NV_copy_buffer */ #ifndef GL_NV_coverage_sample #define GL_NV_coverage_sample 1 #define GL_COVERAGE_COMPONENT_NV 0x8ED0 #define GL_COVERAGE_COMPONENT4_NV 0x8ED1 #define GL_COVERAGE_ATTACHMENT_NV 0x8ED2 #define GL_COVERAGE_BUFFERS_NV 0x8ED3 #define GL_COVERAGE_SAMPLES_NV 0x8ED4 #define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5 #define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6 #define GL_COVERAGE_AUTOMATIC_NV 0x8ED7 #define GL_COVERAGE_BUFFER_BIT_NV 0x00008000 typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask); typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask); GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation); #endif #endif /* GL_NV_coverage_sample */ #ifndef GL_NV_depth_nonlinear #define GL_NV_depth_nonlinear 1 #define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C #endif /* GL_NV_depth_nonlinear */ #ifndef GL_NV_draw_buffers #define GL_NV_draw_buffers 1 #define GL_MAX_DRAW_BUFFERS_NV 0x8824 #define GL_DRAW_BUFFER0_NV 0x8825 #define GL_DRAW_BUFFER1_NV 0x8826 #define GL_DRAW_BUFFER2_NV 0x8827 #define GL_DRAW_BUFFER3_NV 0x8828 #define GL_DRAW_BUFFER4_NV 0x8829 #define GL_DRAW_BUFFER5_NV 0x882A #define GL_DRAW_BUFFER6_NV 0x882B #define GL_DRAW_BUFFER7_NV 0x882C #define GL_DRAW_BUFFER8_NV 0x882D #define GL_DRAW_BUFFER9_NV 0x882E #define GL_DRAW_BUFFER10_NV 0x882F #define GL_DRAW_BUFFER11_NV 0x8830 #define GL_DRAW_BUFFER12_NV 0x8831 #define GL_DRAW_BUFFER13_NV 0x8832 #define GL_DRAW_BUFFER14_NV 0x8833 #define GL_DRAW_BUFFER15_NV 0x8834 #define GL_COLOR_ATTACHMENT0_NV 0x8CE0 #define GL_COLOR_ATTACHMENT1_NV 0x8CE1 #define GL_COLOR_ATTACHMENT2_NV 0x8CE2 #define GL_COLOR_ATTACHMENT3_NV 0x8CE3 #define GL_COLOR_ATTACHMENT4_NV 0x8CE4 #define GL_COLOR_ATTACHMENT5_NV 0x8CE5 #define GL_COLOR_ATTACHMENT6_NV 0x8CE6 #define GL_COLOR_ATTACHMENT7_NV 0x8CE7 #define GL_COLOR_ATTACHMENT8_NV 0x8CE8 #define GL_COLOR_ATTACHMENT9_NV 0x8CE9 #define GL_COLOR_ATTACHMENT10_NV 0x8CEA #define GL_COLOR_ATTACHMENT11_NV 0x8CEB #define GL_COLOR_ATTACHMENT12_NV 0x8CEC #define GL_COLOR_ATTACHMENT13_NV 0x8CED #define GL_COLOR_ATTACHMENT14_NV 0x8CEE #define GL_COLOR_ATTACHMENT15_NV 0x8CEF typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs); #endif #endif /* GL_NV_draw_buffers */ #ifndef GL_NV_draw_instanced #define GL_NV_draw_instanced 1 typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDNVPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDNVPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedNV (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedNV (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_NV_draw_instanced */ #ifndef GL_NV_explicit_attrib_location #define GL_NV_explicit_attrib_location 1 #endif /* GL_NV_explicit_attrib_location */ #ifndef GL_NV_fbo_color_attachments #define GL_NV_fbo_color_attachments 1 #define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF #endif /* GL_NV_fbo_color_attachments */ #ifndef GL_NV_fence #define GL_NV_fence 1 #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint fence); GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint fence); GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint fence); GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition); #endif #endif /* GL_NV_fence */ #ifndef GL_NV_fill_rectangle #define GL_NV_fill_rectangle 1 #define GL_FILL_RECTANGLE_NV 0x933C #endif /* GL_NV_fill_rectangle */ #ifndef GL_NV_fragment_coverage_to_color #define GL_NV_fragment_coverage_to_color 1 #define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD #define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE typedef void (GL_APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFragmentCoverageColorNV (GLuint color); #endif #endif /* GL_NV_fragment_coverage_to_color */ #ifndef GL_NV_fragment_shader_interlock #define GL_NV_fragment_shader_interlock 1 #endif /* GL_NV_fragment_shader_interlock */ #ifndef GL_NV_framebuffer_blit #define GL_NV_framebuffer_blit 1 #define GL_READ_FRAMEBUFFER_NV 0x8CA8 #define GL_DRAW_FRAMEBUFFER_NV 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_NV 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_NV 0x8CAA typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERNVPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBlitFramebufferNV (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif #endif /* GL_NV_framebuffer_blit */ #ifndef GL_NV_framebuffer_mixed_samples #define GL_NV_framebuffer_mixed_samples 1 #define GL_COVERAGE_MODULATION_TABLE_NV 0x9331 #define GL_COLOR_SAMPLES_NV 0x8E20 #define GL_DEPTH_SAMPLES_NV 0x932D #define GL_STENCIL_SAMPLES_NV 0x932E #define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F #define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330 #define GL_COVERAGE_MODULATION_NV 0x9332 #define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333 typedef void (GL_APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufsize, GLfloat *v); typedef void (GL_APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v); GL_APICALL void GL_APIENTRY glGetCoverageModulationTableNV (GLsizei bufsize, GLfloat *v); GL_APICALL void GL_APIENTRY glCoverageModulationNV (GLenum components); #endif #endif /* GL_NV_framebuffer_mixed_samples */ #ifndef GL_NV_framebuffer_multisample #define GL_NV_framebuffer_multisample 1 #define GL_RENDERBUFFER_SAMPLES_NV 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56 #define GL_MAX_SAMPLES_NV 0x8D57 typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleNV (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_NV_framebuffer_multisample */ #ifndef GL_NV_generate_mipmap_sRGB #define GL_NV_generate_mipmap_sRGB 1 #endif /* GL_NV_generate_mipmap_sRGB */ #ifndef GL_NV_geometry_shader_passthrough #define GL_NV_geometry_shader_passthrough 1 #endif /* GL_NV_geometry_shader_passthrough */ #ifndef GL_NV_image_formats #define GL_NV_image_formats 1 #endif /* GL_NV_image_formats */ #ifndef GL_NV_instanced_arrays #define GL_NV_instanced_arrays 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORNVPROC) (GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV (GLuint index, GLuint divisor); #endif #endif /* GL_NV_instanced_arrays */ #ifndef GL_NV_internalformat_sample_query #define GL_NV_internalformat_sample_query 1 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_MULTISAMPLES_NV 0x9371 #define GL_SUPERSAMPLE_SCALE_X_NV 0x9372 #define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 #define GL_CONFORMANT_NV 0x9374 typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params); #endif #endif /* GL_NV_internalformat_sample_query */ #ifndef GL_NV_non_square_matrices #define GL_NV_non_square_matrices 1 #define GL_FLOAT_MAT2x3_NV 0x8B65 #define GL_FLOAT_MAT2x4_NV 0x8B66 #define GL_FLOAT_MAT3x2_NV 0x8B67 #define GL_FLOAT_MAT3x4_NV 0x8B68 #define GL_FLOAT_MAT4x2_NV 0x8B69 #define GL_FLOAT_MAT4x3_NV 0x8B6A typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X3FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X2FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X4FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X2FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X4FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X3FVNVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glUniformMatrix2x3fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x2fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix2x4fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x2fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x4fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x3fvNV (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif #endif /* GL_NV_non_square_matrices */ #ifndef GL_NV_path_rendering #define GL_NV_path_rendering 1 #define GL_PATH_FORMAT_SVG_NV 0x9070 #define GL_PATH_FORMAT_PS_NV 0x9071 #define GL_STANDARD_FONT_NAME_NV 0x9072 #define GL_SYSTEM_FONT_NAME_NV 0x9073 #define GL_FILE_NAME_NV 0x9074 #define GL_PATH_STROKE_WIDTH_NV 0x9075 #define GL_PATH_END_CAPS_NV 0x9076 #define GL_PATH_INITIAL_END_CAP_NV 0x9077 #define GL_PATH_TERMINAL_END_CAP_NV 0x9078 #define GL_PATH_JOIN_STYLE_NV 0x9079 #define GL_PATH_MITER_LIMIT_NV 0x907A #define GL_PATH_DASH_CAPS_NV 0x907B #define GL_PATH_INITIAL_DASH_CAP_NV 0x907C #define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D #define GL_PATH_DASH_OFFSET_NV 0x907E #define GL_PATH_CLIENT_LENGTH_NV 0x907F #define GL_PATH_FILL_MODE_NV 0x9080 #define GL_PATH_FILL_MASK_NV 0x9081 #define GL_PATH_FILL_COVER_MODE_NV 0x9082 #define GL_PATH_STROKE_COVER_MODE_NV 0x9083 #define GL_PATH_STROKE_MASK_NV 0x9084 #define GL_COUNT_UP_NV 0x9088 #define GL_COUNT_DOWN_NV 0x9089 #define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A #define GL_CONVEX_HULL_NV 0x908B #define GL_BOUNDING_BOX_NV 0x908D #define GL_TRANSLATE_X_NV 0x908E #define GL_TRANSLATE_Y_NV 0x908F #define GL_TRANSLATE_2D_NV 0x9090 #define GL_TRANSLATE_3D_NV 0x9091 #define GL_AFFINE_2D_NV 0x9092 #define GL_AFFINE_3D_NV 0x9094 #define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 #define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 #define GL_UTF8_NV 0x909A #define GL_UTF16_NV 0x909B #define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C #define GL_PATH_COMMAND_COUNT_NV 0x909D #define GL_PATH_COORD_COUNT_NV 0x909E #define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F #define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 #define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 #define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 #define GL_SQUARE_NV 0x90A3 #define GL_ROUND_NV 0x90A4 #define GL_TRIANGULAR_NV 0x90A5 #define GL_BEVEL_NV 0x90A6 #define GL_MITER_REVERT_NV 0x90A7 #define GL_MITER_TRUNCATE_NV 0x90A8 #define GL_SKIP_MISSING_GLYPH_NV 0x90A9 #define GL_USE_MISSING_GLYPH_NV 0x90AA #define GL_PATH_ERROR_POSITION_NV 0x90AB #define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD #define GL_ADJACENT_PAIRS_NV 0x90AE #define GL_FIRST_TO_REST_NV 0x90AF #define GL_PATH_GEN_MODE_NV 0x90B0 #define GL_PATH_GEN_COEFF_NV 0x90B1 #define GL_PATH_GEN_COMPONENTS_NV 0x90B3 #define GL_PATH_STENCIL_FUNC_NV 0x90B7 #define GL_PATH_STENCIL_REF_NV 0x90B8 #define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 #define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD #define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE #define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF #define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 #define GL_MOVE_TO_RESETS_NV 0x90B5 #define GL_MOVE_TO_CONTINUES_NV 0x90B6 #define GL_CLOSE_PATH_NV 0x00 #define GL_MOVE_TO_NV 0x02 #define GL_RELATIVE_MOVE_TO_NV 0x03 #define GL_LINE_TO_NV 0x04 #define GL_RELATIVE_LINE_TO_NV 0x05 #define GL_HORIZONTAL_LINE_TO_NV 0x06 #define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 #define GL_VERTICAL_LINE_TO_NV 0x08 #define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 #define GL_QUADRATIC_CURVE_TO_NV 0x0A #define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B #define GL_CUBIC_CURVE_TO_NV 0x0C #define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D #define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E #define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F #define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 #define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 #define GL_SMALL_CCW_ARC_TO_NV 0x12 #define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 #define GL_SMALL_CW_ARC_TO_NV 0x14 #define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 #define GL_LARGE_CCW_ARC_TO_NV 0x16 #define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 #define GL_LARGE_CW_ARC_TO_NV 0x18 #define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 #define GL_RESTART_PATH_NV 0xF0 #define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 #define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 #define GL_RECT_NV 0xF6 #define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 #define GL_CIRCULAR_CW_ARC_TO_NV 0xFA #define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC #define GL_ARC_TO_NV 0xFE #define GL_RELATIVE_ARC_TO_NV 0xFF #define GL_BOLD_BIT_NV 0x01 #define GL_ITALIC_BIT_NV 0x02 #define GL_GLYPH_WIDTH_BIT_NV 0x01 #define GL_GLYPH_HEIGHT_BIT_NV 0x02 #define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 #define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 #define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 #define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 #define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 #define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 #define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 #define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 #define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 #define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 #define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 #define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 #define GL_FONT_ASCENDER_BIT_NV 0x00200000 #define GL_FONT_DESCENDER_BIT_NV 0x00400000 #define GL_FONT_HEIGHT_BIT_NV 0x00800000 #define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 #define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 #define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 #define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 #define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 #define GL_ROUNDED_RECT_NV 0xE8 #define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 #define GL_ROUNDED_RECT2_NV 0xEA #define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB #define GL_ROUNDED_RECT4_NV 0xEC #define GL_RELATIVE_ROUNDED_RECT4_NV 0xED #define GL_ROUNDED_RECT8_NV 0xEE #define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF #define GL_RELATIVE_RECT_NV 0xF7 #define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 #define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 #define GL_FONT_UNAVAILABLE_NV 0x936A #define GL_FONT_UNINTELLIGIBLE_NV 0x936B #define GL_CONIC_CURVE_TO_NV 0x1A #define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B #define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 #define GL_STANDARD_FONT_FORMAT_NV 0x936C #define GL_PATH_PROJECTION_NV 0x1701 #define GL_PATH_MODELVIEW_NV 0x1700 #define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 #define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 #define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 #define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 #define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 #define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 #define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 #define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 #define GL_FRAGMENT_INPUT_NV 0x936D typedef GLuint (GL_APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); typedef void (GL_APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); typedef GLboolean (GL_APIENTRYP PFNGLISPATHNVPROC) (GLuint path); typedef void (GL_APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (GL_APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (GL_APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (GL_APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (GL_APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); typedef void (GL_APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (GL_APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (GL_APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); typedef void (GL_APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); typedef void (GL_APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); typedef void (GL_APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); typedef void (GL_APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); typedef void (GL_APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); typedef void (GL_APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); typedef void (GL_APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); typedef void (GL_APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); typedef void (GL_APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); typedef void (GL_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); typedef void (GL_APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); typedef void (GL_APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); typedef void (GL_APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); typedef void (GL_APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); typedef void (GL_APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); typedef void (GL_APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); typedef void (GL_APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); typedef GLboolean (GL_APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); typedef GLboolean (GL_APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); typedef GLfloat (GL_APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); typedef GLboolean (GL_APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); typedef void (GL_APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (GL_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); typedef void (GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); typedef void (GL_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef GLenum (GL_APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); typedef GLenum (GL_APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef GLenum (GL_APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (GL_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLuint GL_APIENTRY glGenPathsNV (GLsizei range); GL_APICALL void GL_APIENTRY glDeletePathsNV (GLuint path, GLsizei range); GL_APICALL GLboolean GL_APIENTRY glIsPathNV (GLuint path); GL_APICALL void GL_APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); GL_APICALL void GL_APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); GL_APICALL void GL_APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); GL_APICALL void GL_APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); GL_APICALL void GL_APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); GL_APICALL void GL_APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GL_APICALL void GL_APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GL_APICALL void GL_APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); GL_APICALL void GL_APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); GL_APICALL void GL_APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); GL_APICALL void GL_APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); GL_APICALL void GL_APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); GL_APICALL void GL_APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); GL_APICALL void GL_APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); GL_APICALL void GL_APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); GL_APICALL void GL_APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glPathCoverDepthFuncNV (GLenum func); GL_APICALL void GL_APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); GL_APICALL void GL_APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); GL_APICALL void GL_APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); GL_APICALL void GL_APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); GL_APICALL void GL_APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); GL_APICALL void GL_APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); GL_APICALL void GL_APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); GL_APICALL void GL_APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); GL_APICALL void GL_APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); GL_APICALL void GL_APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); GL_APICALL GLboolean GL_APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); GL_APICALL GLboolean GL_APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); GL_APICALL GLfloat GL_APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); GL_APICALL GLboolean GL_APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); GL_APICALL void GL_APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); GL_APICALL void GL_APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); GL_APICALL void GL_APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode); GL_APICALL void GL_APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GL_APICALL void GL_APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GL_APICALL GLenum GL_APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); GL_APICALL GLenum GL_APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GL_APICALL GLenum GL_APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GL_APICALL void GL_APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); GL_APICALL void GL_APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); #endif #endif /* GL_NV_path_rendering */ #ifndef GL_NV_path_rendering_shared_edge #define GL_NV_path_rendering_shared_edge 1 #define GL_SHARED_EDGE_NV 0xC0 #endif /* GL_NV_path_rendering_shared_edge */ #ifndef GL_NV_polygon_mode #define GL_NV_polygon_mode 1 #define GL_POLYGON_MODE_NV 0x0B40 #define GL_POLYGON_OFFSET_POINT_NV 0x2A01 #define GL_POLYGON_OFFSET_LINE_NV 0x2A02 #define GL_POINT_NV 0x1B00 #define GL_LINE_NV 0x1B01 #define GL_FILL_NV 0x1B02 typedef void (GL_APIENTRYP PFNGLPOLYGONMODENVPROC) (GLenum face, GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glPolygonModeNV (GLenum face, GLenum mode); #endif #endif /* GL_NV_polygon_mode */ #ifndef GL_NV_read_buffer #define GL_NV_read_buffer 1 #define GL_READ_BUFFER_NV 0x0C02 typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode); #endif #endif /* GL_NV_read_buffer */ #ifndef GL_NV_read_buffer_front #define GL_NV_read_buffer_front 1 #endif /* GL_NV_read_buffer_front */ #ifndef GL_NV_read_depth #define GL_NV_read_depth 1 #endif /* GL_NV_read_depth */ #ifndef GL_NV_read_depth_stencil #define GL_NV_read_depth_stencil 1 #endif /* GL_NV_read_depth_stencil */ #ifndef GL_NV_read_stencil #define GL_NV_read_stencil 1 #endif /* GL_NV_read_stencil */ #ifndef GL_NV_sRGB_formats #define GL_NV_sRGB_formats 1 #define GL_SLUMINANCE_NV 0x8C46 #define GL_SLUMINANCE_ALPHA_NV 0x8C44 #define GL_SRGB8_NV 0x8C41 #define GL_SLUMINANCE8_NV 0x8C47 #define GL_SLUMINANCE8_ALPHA8_NV 0x8C45 #define GL_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F #define GL_ETC1_SRGB8_NV 0x88EE #endif /* GL_NV_sRGB_formats */ #ifndef GL_NV_sample_locations #define GL_NV_sample_locations 1 #define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D #define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E #define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F #define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340 #define GL_SAMPLE_LOCATION_NV 0x8E50 #define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 #define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 #define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v); GL_APICALL void GL_APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); GL_APICALL void GL_APIENTRY glResolveDepthValuesNV (void); #endif #endif /* GL_NV_sample_locations */ #ifndef GL_NV_sample_mask_override_coverage #define GL_NV_sample_mask_override_coverage 1 #endif /* GL_NV_sample_mask_override_coverage */ #ifndef GL_NV_shader_noperspective_interpolation #define GL_NV_shader_noperspective_interpolation 1 #endif /* GL_NV_shader_noperspective_interpolation */ #ifndef GL_NV_shadow_samplers_array #define GL_NV_shadow_samplers_array 1 #define GL_SAMPLER_2D_ARRAY_SHADOW_NV 0x8DC4 #endif /* GL_NV_shadow_samplers_array */ #ifndef GL_NV_shadow_samplers_cube #define GL_NV_shadow_samplers_cube 1 #define GL_SAMPLER_CUBE_SHADOW_NV 0x8DC5 #endif /* GL_NV_shadow_samplers_cube */ #ifndef GL_NV_texture_border_clamp #define GL_NV_texture_border_clamp 1 #define GL_TEXTURE_BORDER_COLOR_NV 0x1004 #define GL_CLAMP_TO_BORDER_NV 0x812D #endif /* GL_NV_texture_border_clamp */ #ifndef GL_NV_texture_compression_s3tc_update #define GL_NV_texture_compression_s3tc_update 1 #endif /* GL_NV_texture_compression_s3tc_update */ #ifndef GL_NV_texture_npot_2D_mipmap #define GL_NV_texture_npot_2D_mipmap 1 #endif /* GL_NV_texture_npot_2D_mipmap */ #ifndef GL_NV_viewport_array #define GL_NV_viewport_array 1 #define GL_MAX_VIEWPORTS_NV 0x825B #define GL_VIEWPORT_SUBPIXEL_BITS_NV 0x825C #define GL_VIEWPORT_BOUNDS_RANGE_NV 0x825D #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV 0x825F typedef void (GL_APIENTRYP PFNGLVIEWPORTARRAYVNVPROC) (GLuint first, GLsizei count, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFVNVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLSCISSORARRAYVNVPROC) (GLuint first, GLsizei count, const GLint *v); typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDNVPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDVNVPROC) (GLuint index, const GLint *v); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEARRAYFVNVPROC) (GLuint first, GLsizei count, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEINDEXEDFNVPROC) (GLuint index, GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLGETFLOATI_VNVPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (GL_APIENTRYP PFNGLENABLEINVPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLDISABLEINVPROC) (GLenum target, GLuint index); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDINVPROC) (GLenum target, GLuint index); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glViewportArrayvNV (GLuint first, GLsizei count, const GLfloat *v); GL_APICALL void GL_APIENTRY glViewportIndexedfNV (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); GL_APICALL void GL_APIENTRY glViewportIndexedfvNV (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glScissorArrayvNV (GLuint first, GLsizei count, const GLint *v); GL_APICALL void GL_APIENTRY glScissorIndexedNV (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glScissorIndexedvNV (GLuint index, const GLint *v); GL_APICALL void GL_APIENTRY glDepthRangeArrayfvNV (GLuint first, GLsizei count, const GLfloat *v); GL_APICALL void GL_APIENTRY glDepthRangeIndexedfNV (GLuint index, GLfloat n, GLfloat f); GL_APICALL void GL_APIENTRY glGetFloati_vNV (GLenum target, GLuint index, GLfloat *data); GL_APICALL void GL_APIENTRY glEnableiNV (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glDisableiNV (GLenum target, GLuint index); GL_APICALL GLboolean GL_APIENTRY glIsEnablediNV (GLenum target, GLuint index); #endif #endif /* GL_NV_viewport_array */ #ifndef GL_NV_viewport_array2 #define GL_NV_viewport_array2 1 #endif /* GL_NV_viewport_array2 */ #ifndef GL_OVR_multiview #define GL_OVR_multiview 1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 #define GL_MAX_VIEWS_OVR 0x9631 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); #endif #endif /* GL_OVR_multiview */ #ifndef GL_OVR_multiview2 #define GL_OVR_multiview2 1 #endif /* GL_OVR_multiview2 */ #ifndef GL_OVR_multiview_multisampled_render_to_texture #define GL_OVR_multiview_multisampled_render_to_texture 1 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferTextureMultisampleMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews); #endif #endif /* GL_OVR_multiview_multisampled_render_to_texture */ #ifndef GL_QCOM_alpha_test #define GL_QCOM_alpha_test 1 #define GL_ALPHA_TEST_QCOM 0x0BC0 #define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1 #define GL_ALPHA_TEST_REF_QCOM 0x0BC2 typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref); #endif #endif /* GL_QCOM_alpha_test */ #ifndef GL_QCOM_binning_control #define GL_QCOM_binning_control 1 #define GL_BINNING_CONTROL_HINT_QCOM 0x8FB0 #define GL_CPU_OPTIMIZED_QCOM 0x8FB1 #define GL_GPU_OPTIMIZED_QCOM 0x8FB2 #define GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM 0x8FB3 #endif /* GL_QCOM_binning_control */ #ifndef GL_QCOM_driver_control #define GL_QCOM_driver_control 1 typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); #endif #endif /* GL_QCOM_driver_control */ #ifndef GL_QCOM_extended_get #define GL_QCOM_extended_get 1 #define GL_TEXTURE_WIDTH_QCOM 0x8BD2 #define GL_TEXTURE_HEIGHT_QCOM 0x8BD3 #define GL_TEXTURE_DEPTH_QCOM 0x8BD4 #define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 #define GL_TEXTURE_FORMAT_QCOM 0x8BD6 #define GL_TEXTURE_TYPE_QCOM 0x8BD7 #define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 #define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 #define GL_TEXTURE_TARGET_QCOM 0x8BDA #define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB #define GL_STATE_RESTORE 0x8BDC typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, void **params); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels); GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, void **params); #endif #endif /* GL_QCOM_extended_get */ #ifndef GL_QCOM_extended_get2 #define GL_QCOM_extended_get2 1 typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #endif #endif /* GL_QCOM_extended_get2 */ #ifndef GL_QCOM_perfmon_global_mode #define GL_QCOM_perfmon_global_mode 1 #define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 #endif /* GL_QCOM_perfmon_global_mode */ #ifndef GL_QCOM_tiled_rendering #define GL_QCOM_tiled_rendering 1 #define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 #define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002 #define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004 #define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008 #define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010 #define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020 #define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040 #define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080 #define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100 #define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200 #define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400 #define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800 #define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000 #define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000 #define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000 #define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000 #define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000 #define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000 #define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000 #define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000 #define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000 #define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000 #define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000 #define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000 #define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000 #define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000 #define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000 #define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000 #define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000 #define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000 #define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000 #define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000 typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); #endif #endif /* GL_QCOM_tiled_rendering */ #ifndef GL_QCOM_writeonly_rendering #define GL_QCOM_writeonly_rendering 1 #define GL_WRITEONLY_RENDERING_QCOM 0x8823 #endif /* GL_QCOM_writeonly_rendering */ #ifndef GL_VIV_shader_binary #define GL_VIV_shader_binary 1 #define GL_SHADER_BINARY_VIV 0x8FC4 #endif /* GL_VIV_shader_binary */ #ifdef __cplusplus } #endif #endif opengl/include/GLES2/gl2platform.h0100644 0000000 0000000 00000001615 13077405420 015737 0ustar000000000 0000000 #ifndef __gl2platform_h_ #define __gl2platform_h_ /* $Revision: 23328 $ on $Date:: 2013-10-02 02:28:28 -0700 #$ */ /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /* Platform-specific types and definitions for OpenGL ES 2.X gl2.h * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) * by filing a bug against product "OpenGL-ES" component "Registry". */ #include #ifndef GL_APICALL #define GL_APICALL KHRONOS_APICALL #endif #ifndef GL_APIENTRY #define GL_APIENTRY KHRONOS_APIENTRY #endif #endif /* __gl2platform_h_ */ opengl/include/GLES3/0040755 0000000 0000000 00000000000 13077405420 013336 5ustar000000000 0000000 opengl/include/GLES3/gl3.h0100644 0000000 0000000 00000241450 13077405420 014177 0ustar000000000 0000000 #ifndef __gl3_h_ #define __gl3_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2013-2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** ** Khronos $Revision: 32120 $ on $Date: 2015-10-15 04:27:13 -0700 (Thu, 15 Oct 2015) $ */ #include #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif #if !defined(GL_GLES_PROTOTYPES) #define GL_GLES_PROTOTYPES 1 #endif /* Generated on date 20151015 */ /* Generated C header for: * API: gles2 * Profile: common * Versions considered: 2\.[0-9]|3\.0 * Versions emitted: .* * Default extensions included: None * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_ES_VERSION_2_0 #define GL_ES_VERSION_2_0 1 #include typedef khronos_int8_t GLbyte; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef short GLshort; typedef unsigned short GLushort; typedef void GLvoid; typedef struct __GLsync *GLsync; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef unsigned int GLenum; typedef unsigned int GLuint; typedef char GLchar; typedef khronos_float_t GLfloat; typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; typedef unsigned int GLbitfield; typedef int GLint; typedef unsigned char GLboolean; typedef int GLsizei; typedef khronos_uint8_t GLubyte; #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_FALSE 0 #define GL_TRUE 1 #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_FUNC_ADD 0x8006 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_BLEND 0x0BE2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 #define GL_SCISSOR_TEST 0x0C11 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 #define GL_CW 0x0900 #define GL_CCW 0x0901 #define GL_LINE_WIDTH 0x0B21 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VIEWPORT 0x0BA2 #define GL_SCISSOR_BOX 0x0C10 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C #define GL_DEPTH_COMPONENT 0x1902 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_SHADER_TYPE 0x8B4F #define GL_DELETE_STATUS 0x8B80 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_INVERT 0x150A #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE 0x1702 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F #define GL_MIRRORED_REPEAT 0x8370 #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_CUBE 0x8B60 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGB565 0x8D62 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_STENCIL_INDEX8 0x8D48 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_NONE 0 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 typedef void (GL_APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (GL_APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (GL_APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (GL_APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GL_APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); typedef void (GL_APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GL_APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GL_APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (GL_APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (GL_APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); typedef void (GL_APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLDISABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLENABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLFINISHPROC) (void); typedef void (GL_APIENTRYP PFNGLFLUSHPROC) (void); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (GL_APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef void (GL_APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); typedef GLboolean (GL_APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef GLboolean (GL_APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); typedef void (GL_APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); typedef void (GL_APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); typedef void (GL_APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); typedef void (GL_APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); typedef void (GL_APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat d); GL_APICALL void GL_APIENTRY glClearStencil (GLint s); GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f); GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glDisable (GLenum cap); GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glEnable (GLenum cap); GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glFinish (void); GL_APICALL void GL_APIENTRY glFlush (void); GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL GLenum GL_APIENTRY glGetError (void); GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data); GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data); GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GL_APICALL const GLubyte *GL_APIENTRY glGetString (GLenum name); GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint v0); GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_ES_VERSION_2_0 */ #ifndef GL_ES_VERSION_3_0 #define GL_ES_VERSION_3_0 1 typedef unsigned short GLhalf; #define GL_READ_BUFFER 0x0C02 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 #define GL_STENCIL 0x1802 #define GL_RED 0x1903 #define GL_RGB8 0x8051 #define GL_RGBA8 0x8058 #define GL_RGB10_A2 0x8059 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #define GL_HALF_FLOAT 0x140B #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_RG8 0x822B #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_COPY_READ_BUFFER_BINDING 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_SAMPLER_BINDING 0x8919 #define GL_RGB10_A2UI 0x906F #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_GREEN 0x1904 #define GL_BLUE 0x1905 #define GL_INT_2_10_10_10_REV 0x8D9F #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_NUM_SAMPLE_COUNTS 0x9380 #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF typedef void (GL_APIENTRYP PFNGLREADBUFFERPROC) (GLenum src); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (GL_APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (GL_APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (GL_APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); typedef void (GL_APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (GL_APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef GLint (GL_APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); typedef void (GL_APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); typedef GLuint (GL_APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (GL_APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (GL_APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (GL_APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (GL_APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); typedef GLboolean (GL_APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); typedef void (GL_APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); typedef void (GL_APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); typedef void (GL_APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (GL_APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src); GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint *ids); GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id); GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glEndQuery (GLenum target); GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target); GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GL_APICALL void *GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode); GL_APICALL void GL_APIENTRY glEndTransformFeedback (void); GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GL_APICALL const GLubyte *GL_APIENTRY glGetStringi (GLenum name, GLuint index); GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync); GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync); GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler); GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler); GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id); GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void); GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void); GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #endif #endif /* GL_ES_VERSION_3_0 */ #ifdef __cplusplus } #endif #endif opengl/include/GLES3/gl31.h0100644 0000000 0000000 00000321715 13077405420 014263 0ustar000000000 0000000 #ifndef __gl31_h_ #define __gl31_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2013-2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** ** Khronos $Revision$ on $Date$ */ #include #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif #if !defined(GL_GLES_PROTOTYPES) #define GL_GLES_PROTOTYPES 1 #endif /* Generated on date 20151015 */ /* Generated C header for: * API: gles2 * Profile: common * Versions considered: 2\.[0-9]|3\.[01] * Versions emitted: .* * Default extensions included: None * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_ES_VERSION_2_0 #define GL_ES_VERSION_2_0 1 #include typedef khronos_int8_t GLbyte; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef short GLshort; typedef unsigned short GLushort; typedef void GLvoid; typedef struct __GLsync *GLsync; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef unsigned int GLenum; typedef unsigned int GLuint; typedef char GLchar; typedef khronos_float_t GLfloat; typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; typedef unsigned int GLbitfield; typedef int GLint; typedef unsigned char GLboolean; typedef int GLsizei; typedef khronos_uint8_t GLubyte; #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_FALSE 0 #define GL_TRUE 1 #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_FUNC_ADD 0x8006 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_BLEND 0x0BE2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 #define GL_SCISSOR_TEST 0x0C11 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 #define GL_CW 0x0900 #define GL_CCW 0x0901 #define GL_LINE_WIDTH 0x0B21 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VIEWPORT 0x0BA2 #define GL_SCISSOR_BOX 0x0C10 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C #define GL_DEPTH_COMPONENT 0x1902 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_SHADER_TYPE 0x8B4F #define GL_DELETE_STATUS 0x8B80 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_INVERT 0x150A #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE 0x1702 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F #define GL_MIRRORED_REPEAT 0x8370 #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_CUBE 0x8B60 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGB565 0x8D62 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_STENCIL_INDEX8 0x8D48 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_NONE 0 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 typedef void (GL_APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (GL_APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (GL_APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (GL_APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GL_APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); typedef void (GL_APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GL_APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GL_APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (GL_APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (GL_APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); typedef void (GL_APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLDISABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLENABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLFINISHPROC) (void); typedef void (GL_APIENTRYP PFNGLFLUSHPROC) (void); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (GL_APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef void (GL_APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); typedef GLboolean (GL_APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef GLboolean (GL_APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); typedef void (GL_APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); typedef void (GL_APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); typedef void (GL_APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); typedef void (GL_APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); typedef void (GL_APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat d); GL_APICALL void GL_APIENTRY glClearStencil (GLint s); GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f); GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glDisable (GLenum cap); GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glEnable (GLenum cap); GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glFinish (void); GL_APICALL void GL_APIENTRY glFlush (void); GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL GLenum GL_APIENTRY glGetError (void); GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data); GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data); GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GL_APICALL const GLubyte *GL_APIENTRY glGetString (GLenum name); GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint v0); GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_ES_VERSION_2_0 */ #ifndef GL_ES_VERSION_3_0 #define GL_ES_VERSION_3_0 1 typedef unsigned short GLhalf; #define GL_READ_BUFFER 0x0C02 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 #define GL_STENCIL 0x1802 #define GL_RED 0x1903 #define GL_RGB8 0x8051 #define GL_RGBA8 0x8058 #define GL_RGB10_A2 0x8059 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #define GL_HALF_FLOAT 0x140B #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_RG8 0x822B #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_COPY_READ_BUFFER_BINDING 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_SAMPLER_BINDING 0x8919 #define GL_RGB10_A2UI 0x906F #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_GREEN 0x1904 #define GL_BLUE 0x1905 #define GL_INT_2_10_10_10_REV 0x8D9F #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_NUM_SAMPLE_COUNTS 0x9380 #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF typedef void (GL_APIENTRYP PFNGLREADBUFFERPROC) (GLenum src); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (GL_APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (GL_APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (GL_APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); typedef void (GL_APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (GL_APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef GLint (GL_APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); typedef void (GL_APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); typedef GLuint (GL_APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (GL_APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (GL_APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (GL_APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (GL_APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); typedef GLboolean (GL_APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); typedef void (GL_APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); typedef void (GL_APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); typedef void (GL_APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (GL_APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src); GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint *ids); GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id); GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glEndQuery (GLenum target); GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target); GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GL_APICALL void *GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode); GL_APICALL void GL_APIENTRY glEndTransformFeedback (void); GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GL_APICALL const GLubyte *GL_APIENTRY glGetStringi (GLenum name, GLuint index); GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync); GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync); GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler); GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler); GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id); GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void); GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void); GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #endif #endif /* GL_ES_VERSION_3_0 */ #ifndef GL_ES_VERSION_3_1 #define GL_ES_VERSION_3_1 1 #define GL_COMPUTE_SHADER 0x91B9 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC #define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF #define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #define GL_MAX_UNIFORM_LOCATIONS 0x826E #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 #define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 #define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 #define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 #define GL_UNIFORM 0x92E1 #define GL_UNIFORM_BLOCK 0x92E2 #define GL_PROGRAM_INPUT 0x92E3 #define GL_PROGRAM_OUTPUT 0x92E4 #define GL_BUFFER_VARIABLE 0x92E5 #define GL_SHADER_STORAGE_BLOCK 0x92E6 #define GL_ATOMIC_COUNTER_BUFFER 0x92C0 #define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 #define GL_ACTIVE_RESOURCES 0x92F5 #define GL_MAX_NAME_LENGTH 0x92F6 #define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_NAME_LENGTH 0x92F9 #define GL_TYPE 0x92FA #define GL_ARRAY_SIZE 0x92FB #define GL_OFFSET 0x92FC #define GL_BLOCK_INDEX 0x92FD #define GL_ARRAY_STRIDE 0x92FE #define GL_MATRIX_STRIDE 0x92FF #define GL_IS_ROW_MAJOR 0x9300 #define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 #define GL_BUFFER_BINDING 0x9302 #define GL_BUFFER_DATA_SIZE 0x9303 #define GL_NUM_ACTIVE_VARIABLES 0x9304 #define GL_ACTIVE_VARIABLES 0x9305 #define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A #define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B #define GL_TOP_LEVEL_ARRAY_SIZE 0x930C #define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D #define GL_LOCATION 0x930E #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_ACTIVE_PROGRAM 0x8259 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 #define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 #define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 #define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 #define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC #define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF #define GL_IMAGE_BINDING_NAME 0x8F3A #define GL_IMAGE_BINDING_LEVEL 0x8F3B #define GL_IMAGE_BINDING_LAYERED 0x8F3C #define GL_IMAGE_BINDING_LAYER 0x8F3D #define GL_IMAGE_BINDING_ACCESS 0x8F3E #define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 #define GL_UNIFORM_BARRIER_BIT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 #define GL_COMMAND_BARRIER_BIT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 #define GL_ALL_BARRIER_BITS 0xFFFFFFFF #define GL_IMAGE_2D 0x904D #define GL_IMAGE_3D 0x904E #define GL_IMAGE_CUBE 0x9050 #define GL_IMAGE_2D_ARRAY 0x9053 #define GL_INT_IMAGE_2D 0x9058 #define GL_INT_IMAGE_3D 0x9059 #define GL_INT_IMAGE_CUBE 0x905B #define GL_INT_IMAGE_2D_ARRAY 0x905E #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_SHADER_STORAGE_BUFFER 0x90D2 #define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 #define GL_SHADER_STORAGE_BUFFER_START 0x90D4 #define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 #define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA #define GL_STENCIL_INDEX 0x1901 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_RED_SIZE 0x805C #define GL_TEXTURE_GREEN_SIZE 0x805D #define GL_TEXTURE_BLUE_SIZE 0x805E #define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA #define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 typedef void (GL_APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); typedef void (GL_APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); typedef GLuint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (GL_APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (GL_APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); typedef void (GL_APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (GL_APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (GL_APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); typedef void (GL_APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); GL_APICALL void GL_APIENTRY glDispatchComputeIndirect (GLintptr indirect); GL_APICALL void GL_APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); GL_APICALL void GL_APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); GL_APICALL void GL_APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); GL_APICALL GLuint GL_APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); GL_APICALL void GL_APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GL_APICALL void GL_APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); GL_APICALL GLint GL_APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); GL_APICALL void GL_APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); GL_APICALL void GL_APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); GL_APICALL void GL_APIENTRY glBindProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); GL_APICALL void GL_APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); GL_APICALL GLboolean GL_APIENTRY glIsProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); GL_APICALL void GL_APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glValidateProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GL_APICALL void GL_APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); GL_APICALL void GL_APIENTRY glMemoryBarrier (GLbitfield barriers); GL_APICALL void GL_APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); GL_APICALL void GL_APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GL_APICALL void GL_APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); GL_APICALL void GL_APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); GL_APICALL void GL_APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GL_APICALL void GL_APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GL_APICALL void GL_APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GL_APICALL void GL_APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); GL_APICALL void GL_APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); #endif #endif /* GL_ES_VERSION_3_1 */ #ifdef __cplusplus } #endif #endif opengl/include/GLES3/gl32.h0100644 0000000 0000000 00000372535 13077405420 014272 0ustar000000000 0000000 #ifndef __gl32_h_ #define __gl32_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2013-2015 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** ** Khronos $Revision$ on $Date$ */ #include #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif #if !defined(GL_GLES_PROTOTYPES) #define GL_GLES_PROTOTYPES 1 #endif /* Generated on date 20151015 */ /* Generated C header for: * API: gles2 * Profile: common * Versions considered: 2\.[0-9]|3\.[012] * Versions emitted: .* * Default extensions included: None * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_ES_VERSION_2_0 #define GL_ES_VERSION_2_0 1 #include typedef khronos_int8_t GLbyte; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef short GLshort; typedef unsigned short GLushort; typedef void GLvoid; typedef struct __GLsync *GLsync; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef unsigned int GLenum; typedef unsigned int GLuint; typedef char GLchar; typedef khronos_float_t GLfloat; typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; typedef unsigned int GLbitfield; typedef int GLint; typedef unsigned char GLboolean; typedef int GLsizei; typedef khronos_uint8_t GLubyte; #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_FALSE 0 #define GL_TRUE 1 #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_FUNC_ADD 0x8006 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_BLEND 0x0BE2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 #define GL_SCISSOR_TEST 0x0C11 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 #define GL_CW 0x0900 #define GL_CCW 0x0901 #define GL_LINE_WIDTH 0x0B21 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VIEWPORT 0x0BA2 #define GL_SCISSOR_BOX 0x0C10 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C #define GL_DEPTH_COMPONENT 0x1902 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_SHADER_TYPE 0x8B4F #define GL_DELETE_STATUS 0x8B80 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_INVERT 0x150A #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE 0x1702 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F #define GL_MIRRORED_REPEAT 0x8370 #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_CUBE 0x8B60 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGB565 0x8D62 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_STENCIL_INDEX8 0x8D48 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_NONE 0 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 typedef void (GL_APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (GL_APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (GL_APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (GL_APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GL_APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); typedef void (GL_APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); typedef void (GL_APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); typedef void (GL_APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s); typedef void (GL_APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GL_APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GL_APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (GL_APIENTRYP PFNGLCULLFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (GL_APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (GL_APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func); typedef void (GL_APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag); typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (GL_APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (GL_APIENTRYP PFNGLDISABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLENABLEPROC) (GLenum cap); typedef void (GL_APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (GL_APIENTRYP PFNGLFINISHPROC) (void); typedef void (GL_APIENTRYP PFNGLFLUSHPROC) (void); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode); typedef void (GL_APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (GL_APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (GL_APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef void (GL_APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode); typedef GLboolean (GL_APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef GLboolean (GL_APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef GLboolean (GL_APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture); typedef void (GL_APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width); typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); typedef void (GL_APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); typedef void (GL_APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); typedef void (GL_APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (GL_APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); typedef void (GL_APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat d); GL_APICALL void GL_APIENTRY glClearStencil (GLint s); GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f); GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glDisable (GLenum cap); GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glEnable (GLenum cap); GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glFinish (void); GL_APICALL void GL_APIENTRY glFlush (void); GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures); GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *data); GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL GLenum GL_APIENTRY glGetError (void); GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *data); GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *data); GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GL_APICALL const GLubyte *GL_APIENTRY glGetString (GLenum name); GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint v0); GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_ES_VERSION_2_0 */ #ifndef GL_ES_VERSION_3_0 #define GL_ES_VERSION_3_0 1 typedef unsigned short GLhalf; #define GL_READ_BUFFER 0x0C02 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 #define GL_STENCIL 0x1802 #define GL_RED 0x1903 #define GL_RGB8 0x8051 #define GL_RGBA8 0x8058 #define GL_RGB10_A2 0x8059 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #define GL_HALF_FLOAT 0x140B #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_RG8 0x822B #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_COPY_READ_BUFFER_BINDING 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_SAMPLER_BINDING 0x8919 #define GL_RGB10_A2UI 0x906F #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_GREEN 0x1904 #define GL_BLUE 0x1905 #define GL_INT_2_10_10_10_REV 0x8D9F #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_NUM_SAMPLE_COUNTS 0x9380 #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF typedef void (GL_APIENTRYP PFNGLREADBUFFERPROC) (GLenum src); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (GL_APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (GL_APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void *(GL_APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (GL_APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (GL_APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); typedef void (GL_APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (GL_APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef GLint (GL_APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte *(GL_APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); typedef void (GL_APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); typedef GLuint (GL_APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); typedef void (GL_APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (GL_APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (GL_APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GL_APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (GL_APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (GL_APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (GL_APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); typedef GLboolean (GL_APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); typedef void (GL_APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); typedef void (GL_APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); typedef void (GL_APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (GL_APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src); GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint *ids); GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id); GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glEndQuery (GLenum target); GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target); GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GL_APICALL void *GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array); GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode); GL_APICALL void GL_APIENTRY glEndTransformFeedback (void); GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GL_APICALL const GLubyte *GL_APIENTRY glGetStringi (GLenum name, GLuint index); GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync); GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync); GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler); GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler); GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id); GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void); GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void); GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #endif #endif /* GL_ES_VERSION_3_0 */ #ifndef GL_ES_VERSION_3_1 #define GL_ES_VERSION_3_1 1 #define GL_COMPUTE_SHADER 0x91B9 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC #define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF #define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #define GL_MAX_UNIFORM_LOCATIONS 0x826E #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 #define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 #define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 #define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 #define GL_UNIFORM 0x92E1 #define GL_UNIFORM_BLOCK 0x92E2 #define GL_PROGRAM_INPUT 0x92E3 #define GL_PROGRAM_OUTPUT 0x92E4 #define GL_BUFFER_VARIABLE 0x92E5 #define GL_SHADER_STORAGE_BLOCK 0x92E6 #define GL_ATOMIC_COUNTER_BUFFER 0x92C0 #define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 #define GL_ACTIVE_RESOURCES 0x92F5 #define GL_MAX_NAME_LENGTH 0x92F6 #define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_NAME_LENGTH 0x92F9 #define GL_TYPE 0x92FA #define GL_ARRAY_SIZE 0x92FB #define GL_OFFSET 0x92FC #define GL_BLOCK_INDEX 0x92FD #define GL_ARRAY_STRIDE 0x92FE #define GL_MATRIX_STRIDE 0x92FF #define GL_IS_ROW_MAJOR 0x9300 #define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 #define GL_BUFFER_BINDING 0x9302 #define GL_BUFFER_DATA_SIZE 0x9303 #define GL_NUM_ACTIVE_VARIABLES 0x9304 #define GL_ACTIVE_VARIABLES 0x9305 #define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A #define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B #define GL_TOP_LEVEL_ARRAY_SIZE 0x930C #define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D #define GL_LOCATION 0x930E #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_ACTIVE_PROGRAM 0x8259 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 #define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 #define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 #define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 #define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC #define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF #define GL_IMAGE_BINDING_NAME 0x8F3A #define GL_IMAGE_BINDING_LEVEL 0x8F3B #define GL_IMAGE_BINDING_LAYERED 0x8F3C #define GL_IMAGE_BINDING_LAYER 0x8F3D #define GL_IMAGE_BINDING_ACCESS 0x8F3E #define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 #define GL_UNIFORM_BARRIER_BIT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 #define GL_COMMAND_BARRIER_BIT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 #define GL_ALL_BARRIER_BITS 0xFFFFFFFF #define GL_IMAGE_2D 0x904D #define GL_IMAGE_3D 0x904E #define GL_IMAGE_CUBE 0x9050 #define GL_IMAGE_2D_ARRAY 0x9053 #define GL_INT_IMAGE_2D 0x9058 #define GL_INT_IMAGE_3D 0x9059 #define GL_INT_IMAGE_CUBE 0x905B #define GL_INT_IMAGE_2D_ARRAY 0x905E #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_SHADER_STORAGE_BUFFER 0x90D2 #define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 #define GL_SHADER_STORAGE_BUFFER_START 0x90D4 #define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 #define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA #define GL_STENCIL_INDEX 0x1901 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_RED_SIZE 0x805C #define GL_TEXTURE_GREEN_SIZE 0x805D #define GL_TEXTURE_BLUE_SIZE 0x805E #define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA #define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 typedef void (GL_APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); typedef void (GL_APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); typedef GLuint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); typedef GLint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (GL_APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (GL_APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (GL_APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); typedef void (GL_APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (GL_APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (GL_APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (GL_APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); typedef void (GL_APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); GL_APICALL void GL_APIENTRY glDispatchComputeIndirect (GLintptr indirect); GL_APICALL void GL_APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); GL_APICALL void GL_APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); GL_APICALL void GL_APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); GL_APICALL GLuint GL_APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); GL_APICALL void GL_APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GL_APICALL void GL_APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); GL_APICALL GLint GL_APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); GL_APICALL void GL_APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); GL_APICALL void GL_APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); GL_APICALL void GL_APIENTRY glBindProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); GL_APICALL void GL_APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); GL_APICALL GLboolean GL_APIENTRY glIsProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); GL_APICALL void GL_APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); GL_APICALL void GL_APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GL_APICALL void GL_APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GL_APICALL void GL_APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); GL_APICALL void GL_APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); GL_APICALL void GL_APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GL_APICALL void GL_APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GL_APICALL void GL_APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); GL_APICALL void GL_APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); GL_APICALL void GL_APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GL_APICALL void GL_APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GL_APICALL void GL_APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GL_APICALL void GL_APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glValidateProgramPipeline (GLuint pipeline); GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GL_APICALL void GL_APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GL_APICALL void GL_APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); GL_APICALL void GL_APIENTRY glMemoryBarrier (GLbitfield barriers); GL_APICALL void GL_APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); GL_APICALL void GL_APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GL_APICALL void GL_APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); GL_APICALL void GL_APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); GL_APICALL void GL_APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params); GL_APICALL void GL_APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GL_APICALL void GL_APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GL_APICALL void GL_APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GL_APICALL void GL_APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); GL_APICALL void GL_APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); #endif #endif /* GL_ES_VERSION_3_1 */ #ifndef GL_ES_VERSION_3_2 #define GL_ES_VERSION_3_2 1 typedef void (GL_APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); #define GL_MULTISAMPLE_LINE_WIDTH_RANGE 0x9381 #define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY 0x9382 #define GL_MULTIPLY 0x9294 #define GL_SCREEN 0x9295 #define GL_OVERLAY 0x9296 #define GL_DARKEN 0x9297 #define GL_LIGHTEN 0x9298 #define GL_COLORDODGE 0x9299 #define GL_COLORBURN 0x929A #define GL_HARDLIGHT 0x929B #define GL_SOFTLIGHT 0x929C #define GL_DIFFERENCE 0x929E #define GL_EXCLUSION 0x92A0 #define GL_HSL_HUE 0x92AD #define GL_HSL_SATURATION 0x92AE #define GL_HSL_COLOR 0x92AF #define GL_HSL_LUMINOSITY 0x92B0 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 #define GL_DEBUG_SOURCE_API 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 #define GL_DEBUG_SOURCE_APPLICATION 0x824A #define GL_DEBUG_SOURCE_OTHER 0x824B #define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E #define GL_DEBUG_TYPE_PORTABILITY 0x824F #define GL_DEBUG_TYPE_PERFORMANCE 0x8250 #define GL_DEBUG_TYPE_OTHER 0x8251 #define GL_DEBUG_TYPE_MARKER 0x8268 #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 #define GL_DEBUG_TYPE_POP_GROUP 0x826A #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D #define GL_BUFFER 0x82E0 #define GL_SHADER 0x82E1 #define GL_PROGRAM 0x82E2 #define GL_VERTEX_ARRAY 0x8074 #define GL_QUERY 0x82E3 #define GL_PROGRAM_PIPELINE 0x82E4 #define GL_SAMPLER 0x82E6 #define GL_MAX_LABEL_LENGTH 0x82E8 #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 #define GL_DEBUG_LOGGED_MESSAGES 0x9145 #define GL_DEBUG_SEVERITY_HIGH 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 #define GL_DEBUG_SEVERITY_LOW 0x9148 #define GL_DEBUG_OUTPUT 0x92E0 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_SHADER_BIT 0x00000004 #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_UNDEFINED_VERTEX 0x8260 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 #define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 #define GL_PRIMITIVE_BOUNDING_BOX 0x92BE #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 #define GL_CONTEXT_FLAGS 0x821E #define GL_LOSE_CONTEXT_ON_RESET 0x8252 #define GL_GUILTY_CONTEXT_RESET 0x8253 #define GL_INNOCENT_CONTEXT_RESET 0x8254 #define GL_UNKNOWN_CONTEXT_RESET 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY 0x8256 #define GL_NO_RESET_NOTIFICATION 0x8261 #define GL_CONTEXT_LOST 0x0507 #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_PATCHES 0x000E #define GL_PATCH_VERTICES 0x8E72 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TESS_GEN_POINT_MODE 0x8E79 #define GL_ISOLINES 0x8E7A #define GL_QUADS 0x0007 #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRACTIONAL_EVEN 0x8E7C #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 #define GL_IS_PER_PATCH 0x92E7 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 #define GL_TESS_CONTROL_SHADER 0x8E88 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_CONTROL_SHADER_BIT 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 #define GL_TEXTURE_BORDER_COLOR 0x1004 #define GL_CLAMP_TO_BORDER 0x812D #define GL_TEXTURE_BUFFER 0x8C2A #define GL_TEXTURE_BUFFER_BINDING 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_IMAGE_BUFFER 0x9051 #define GL_INT_IMAGE_BUFFER 0x905C #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 #define GL_TEXTURE_BUFFER_OFFSET 0x919D #define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0 #define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1 #define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2 #define GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3 #define GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4 #define GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5 #define GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6 #define GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7 #define GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8 #define GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9 #define GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA #define GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB #define GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC #define GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F #define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 #define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D typedef void (GL_APIENTRYP PFNGLBLENDBARRIERPROC) (void); typedef void (GL_APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); typedef void (GL_APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (GL_APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params); typedef void (GL_APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (GL_APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef GLboolean (GL_APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (GL_APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void); typedef void (GL_APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); typedef void (GL_APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); typedef void (GL_APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); typedef void (GL_APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (GL_APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); #if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glBlendBarrier (void); GL_APICALL void GL_APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); GL_APICALL void GL_APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GL_APICALL void GL_APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GL_APICALL void GL_APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); GL_APICALL void GL_APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); GL_APICALL void GL_APIENTRY glPopDebugGroup (void); GL_APICALL void GL_APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); GL_APICALL void GL_APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); GL_APICALL void GL_APIENTRY glGetPointerv (GLenum pname, void **params); GL_APICALL void GL_APIENTRY glEnablei (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glDisablei (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glBlendEquationi (GLuint buf, GLenum mode); GL_APICALL void GL_APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); GL_APICALL void GL_APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GL_APICALL void GL_APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GL_APICALL GLboolean GL_APIENTRY glIsEnabledi (GLenum target, GLuint index); GL_APICALL void GL_APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); GL_APICALL void GL_APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glPrimitiveBoundingBox (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatus (void); GL_APICALL void GL_APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GL_APICALL void GL_APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GL_APICALL void GL_APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params); GL_APICALL void GL_APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params); GL_APICALL void GL_APIENTRY glMinSampleShading (GLfloat value); GL_APICALL void GL_APIENTRY glPatchParameteri (GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); GL_APICALL void GL_APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); GL_APICALL void GL_APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); GL_APICALL void GL_APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); GL_APICALL void GL_APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); GL_APICALL void GL_APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GL_APICALL void GL_APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); #endif #endif /* GL_ES_VERSION_3_2 */ #ifdef __cplusplus } #endif #endif opengl/include/GLES3/gl3ext.h0100644 0000000 0000000 00000001345 13077405420 014715 0ustar000000000 0000000 #ifndef __gl3ext_h_ #define __gl3ext_h_ /* $Revision: 17809 $ on $Date:: 2012-05-14 08:03:36 -0700 #$ */ /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /* OpenGL ES 3 Extensions * * After an OES extension's interactions with OpenGl ES 3.0 have been documented, * its tokens and function definitions should be added to this file in a manner * that does not conflict with gl2ext.h or gl3.h. * * Tokens and function definitions for extensions that have become standard * features in OpenGL ES 3.0 will not be added to this file. * * Applications using OpenGL-ES-2-only extensions should include gl2ext.h */ #endif /* __gl3ext_h_ */ opengl/include/GLES3/gl3platform.h0100644 0000000 0000000 00000001615 13077405420 015741 0ustar000000000 0000000 #ifndef __gl3platform_h_ #define __gl3platform_h_ /* $Revision: 23328 $ on $Date:: 2013-10-02 02:28:28 -0700 #$ */ /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /* Platform-specific types and definitions for OpenGL ES 3.X gl3.h * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) * by filing a bug against product "OpenGL-ES" component "Registry". */ #include #ifndef GL_APICALL #define GL_APICALL KHRONOS_APICALL #endif #ifndef GL_APIENTRY #define GL_APIENTRY KHRONOS_APIENTRY #endif #endif /* __gl3platform_h_ */ opengl/include/KHR/0040755 0000000 0000000 00000000000 13077405420 013145 5ustar000000000 0000000 opengl/include/KHR/khrplatform.h0100644 0000000 0000000 00000022730 13077405420 015650 0ustar000000000 0000000 #ifndef __khrplatform_h_ #define __khrplatform_h_ /* ** Copyright (c) 2008-2009 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Khronos platform-specific types and definitions. * * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $ * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos * group so that they can be included in future versions of this file. * Please submit changes by sending them to the public Khronos Bugzilla * (http://khronos.org/bugzilla) by filing a bug against product * "Khronos (general)" component "Registry". * * A predefined template which fills in some of the bug fields can be * reached using http://tinyurl.com/khrplatform-h-bugreport, but you * must create a Bugzilla login first. * * * See the Implementer's Guidelines for information about where this file * should be located on your system and for more details of its use: * http://www.khronos.org/registry/implementers_guide.pdf * * This file should be included as * #include * by Khronos client API header files that use its types and defines. * * The types in khrplatform.h should only be used to define API-specific types. * * Types defined in khrplatform.h: * khronos_int8_t signed 8 bit * khronos_uint8_t unsigned 8 bit * khronos_int16_t signed 16 bit * khronos_uint16_t unsigned 16 bit * khronos_int32_t signed 32 bit * khronos_uint32_t unsigned 32 bit * khronos_int64_t signed 64 bit * khronos_uint64_t unsigned 64 bit * khronos_intptr_t signed same number of bits as a pointer * khronos_uintptr_t unsigned same number of bits as a pointer * khronos_ssize_t signed size * khronos_usize_t unsigned size * khronos_float_t signed 32 bit floating point * khronos_time_ns_t unsigned 64 bit time in nanoseconds * khronos_utime_nanoseconds_t unsigned time interval or absolute time in * nanoseconds * khronos_stime_nanoseconds_t signed time interval in nanoseconds * khronos_boolean_enum_t enumerated boolean type. This should * only be used as a base type when a client API's boolean type is * an enum. Client APIs which use an integer or other type for * booleans cannot use this as the base type for their boolean. * * Tokens defined in khrplatform.h: * * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. * * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. * * Calling convention macros defined in this file: * KHRONOS_APICALL * KHRONOS_APIENTRY * KHRONOS_APIATTRIBUTES * * These may be used in function prototypes as: * * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( * int arg1, * int arg2) KHRONOS_APIATTRIBUTES; */ /*------------------------------------------------------------------------- * Definition of KHRONOS_APICALL *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ #if defined(_WIN32) && !defined(__SCITECH_SNAP__) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C #elif defined(ANDROID) # define KHRONOS_APICALL __attribute__((visibility("default"))) #else # define KHRONOS_APICALL #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIENTRY *------------------------------------------------------------------------- * This follows the return type of the function and precedes the function * name in the function prototype. */ #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) /* Win32 but not WinCE */ # define KHRONOS_APIENTRY __stdcall #else # define KHRONOS_APIENTRY #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIATTRIBUTES *------------------------------------------------------------------------- * This follows the closing parenthesis of the function prototype arguments. */ #if defined (__ARMCC_2__) #define KHRONOS_APIATTRIBUTES __softfp #else #define KHRONOS_APIATTRIBUTES #endif /*------------------------------------------------------------------------- * basic type definitions *-----------------------------------------------------------------------*/ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__VMS ) || defined(__sgi) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) /* * Win32 */ typedef __int32 khronos_int32_t; typedef unsigned __int32 khronos_uint32_t; typedef __int64 khronos_int64_t; typedef unsigned __int64 khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__sun__) || defined(__digital__) /* * Sun or Digital */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #if defined(__arch64__) || defined(_LP64) typedef long int khronos_int64_t; typedef unsigned long int khronos_uint64_t; #else typedef long long int khronos_int64_t; typedef unsigned long long int khronos_uint64_t; #endif /* __arch64__ */ #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif 0 /* * Hypothetical platform with no float or int64 support */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #define KHRONOS_SUPPORT_INT64 0 #define KHRONOS_SUPPORT_FLOAT 0 #else /* * Generic fallback */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #endif /* * Types that are (so far) the same on all platforms */ typedef signed char khronos_int8_t; typedef unsigned char khronos_uint8_t; typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #if KHRONOS_SUPPORT_FLOAT /* * Float type */ typedef float khronos_float_t; #endif #if KHRONOS_SUPPORT_INT64 /* Time types * * These types can be used to represent a time interval in nanoseconds or * an absolute Unadjusted System Time. Unadjusted System Time is the number * of nanoseconds since some arbitrary system event (e.g. since the last * time the system booted). The Unadjusted System Time is an unsigned * 64 bit value that wraps back to 0 every 584 years. Time intervals * may be either signed or unsigned. */ typedef khronos_uint64_t khronos_utime_nanoseconds_t; typedef khronos_int64_t khronos_stime_nanoseconds_t; #endif /* * Dummy value used to pad enum types to 32 bits. */ #ifndef KHRONOS_MAX_ENUM #define KHRONOS_MAX_ENUM 0x7FFFFFFF #endif /* * Enumerated boolean type * * Values other than zero should be considered to be true. Therefore * comparisons should not be made against KHRONOS_TRUE. */ typedef enum { KHRONOS_FALSE = 0, KHRONOS_TRUE = 1, KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; #endif /* __khrplatform_h_ */ opengl/include/MODULE_LICENSE_MIT0100644 0000000 0000000 00000000000 13077405420 015267 0ustar000000000 0000000 opengl/libagl/0040755 0000000 0000000 00000000000 13077405420 012330 5ustar000000000 0000000 opengl/libagl/Android.mk0100644 0000000 0000000 00000002334 13077405420 014240 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) # # Build the software OpenGL ES library # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ egl.cpp \ state.cpp \ texture.cpp \ Tokenizer.cpp \ TokenManager.cpp \ TextureObjectManager.cpp \ BufferObjectManager.cpp \ array.cpp.arm \ fp.cpp.arm \ light.cpp.arm \ matrix.cpp.arm \ mipmap.cpp.arm \ primitives.cpp.arm \ vertex.cpp.arm LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S LOCAL_CFLAGS_arm += -fstrict-aliasing ifndef ARCH_MIPS_REV6 LOCAL_SRC_FILES_mips += arch-mips/fixed_asm.S endif LOCAL_CFLAGS_mips += -fstrict-aliasing # The graphics code can generate division by zero LOCAL_CFLAGS_mips += -mno-check-zero-division # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private LOCAL_MODULE_RELATIVE_PATH := egl LOCAL_MODULE:= libGLES_android include $(BUILD_SHARED_LIBRARY) opengl/libagl/BufferObjectManager.cpp0100644 0000000 0000000 00000005133 13077405420 016666 0ustar000000000 0000000 /* ** Copyright 2008, 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 #include #include #include #include #include #include #include #include "BufferObjectManager.h" namespace android { using namespace gl; // ---------------------------------------------------------------------------- EGLBufferObjectManager::EGLBufferObjectManager() : TokenManager(), mCount(0) { } EGLBufferObjectManager::~EGLBufferObjectManager() { // destroy all the buffer objects and their storage GLsizei n = mBuffers.size(); for (GLsizei i=0 ; idata); delete bo; } } buffer_t const* EGLBufferObjectManager::bind(GLuint buffer) { Mutex::Autolock _l(mLock); int32_t i = mBuffers.indexOfKey(buffer); if (i >= 0) { return mBuffers.valueAt(i); } buffer_t* bo = new buffer_t; bo->data = 0; bo->usage = GL_STATIC_DRAW; bo->size = 0; bo->name = buffer; mBuffers.add(buffer, bo); return bo; } int EGLBufferObjectManager::allocateStore(buffer_t* bo, GLsizeiptr size, GLenum usage) { Mutex::Autolock _l(mLock); if (size != bo->size) { uint8_t* data = (uint8_t*)malloc(size); if (data == 0) return -1; free(bo->data); bo->data = data; bo->size = size; } bo->usage = usage; return 0; } void EGLBufferObjectManager::deleteBuffers(GLsizei n, const GLuint* buffers) { Mutex::Autolock _l(mLock); while (n--) { const GLuint t = *buffers++; if (t) { int32_t index = mBuffers.indexOfKey(t); if (index >= 0) { buffer_t* bo = mBuffers.valueAt(index); free(bo->data); mBuffers.removeItemsAt(index); delete bo; } } } } // ---------------------------------------------------------------------------- }; // namespace android opengl/libagl/BufferObjectManager.h0100644 0000000 0000000 00000004517 13077405420 016340 0ustar000000000 0000000 /* ** ** Copyright 2006, 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_OPENGLES_BUFFER_OBJECT_MANAGER_H #define ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H #include #include #include #include #include #include #include #include #include "Tokenizer.h" #include "TokenManager.h" namespace android { // ---------------------------------------------------------------------------- namespace gl { struct buffer_t { GLsizeiptr size; GLenum usage; uint8_t* data; uint32_t name; }; }; class EGLBufferObjectManager : public TokenManager { public: EGLBufferObjectManager(); ~EGLBufferObjectManager(); // protocol for sp<> inline void incStrong(const void* id) const; inline void decStrong(const void* id) const; typedef void weakref_type; gl::buffer_t const* bind(GLuint buffer); int allocateStore(gl::buffer_t* bo, GLsizeiptr size, GLenum usage); void deleteBuffers(GLsizei n, const GLuint* buffers); private: mutable std::atomic_size_t mCount; mutable Mutex mLock; KeyedVector mBuffers; }; void EGLBufferObjectManager::incStrong(const void* /*id*/) const { mCount.fetch_add(1, std::memory_order_relaxed); } void EGLBufferObjectManager::decStrong(const void* /*id*/) const { if (mCount.fetch_sub(1, std::memory_order_release) == 0) { std::atomic_thread_fence(std::memory_order_acquire); delete this; } } // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H opengl/libagl/TextureObjectManager.cpp0100644 0000000 0000000 00000020531 13077405420 017114 0ustar000000000 0000000 /* ** Copyright 2006, 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 #include #include "context.h" #include "TextureObjectManager.h" namespace android { // ---------------------------------------------------------------------------- EGLTextureObject::EGLTextureObject() : mSize(0) { init(); } EGLTextureObject::~EGLTextureObject() { if (!direct) { if (mSize && surface.data) free(surface.data); if (mMipmaps) freeMipmaps(); } } void EGLTextureObject::init() { memset(&surface, 0, sizeof(surface)); surface.version = sizeof(surface); mMipmaps = 0; mNumExtraLod = 0; mIsComplete = false; wraps = GL_REPEAT; wrapt = GL_REPEAT; min_filter = GL_LINEAR; mag_filter = GL_LINEAR; internalformat = 0; memset(crop_rect, 0, sizeof(crop_rect)); generate_mipmap = GL_FALSE; direct = GL_FALSE; buffer = 0; } void EGLTextureObject::copyParameters(const sp& old) { wraps = old->wraps; wrapt = old->wrapt; min_filter = old->min_filter; mag_filter = old->mag_filter; memcpy(crop_rect, old->crop_rect, sizeof(crop_rect)); generate_mipmap = old->generate_mipmap; direct = old->direct; } status_t EGLTextureObject::allocateMipmaps() { // here, by construction, mMipmaps=0 && mNumExtraLod=0 if (!surface.data) return NO_INIT; int w = surface.width; int h = surface.height; const int numLods = 31 - gglClz(max(w,h)); if (numLods <= 0) return NO_ERROR; mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface)); if (!mMipmaps) return NO_MEMORY; memset(mMipmaps, 0, numLods * sizeof(GGLSurface)); mNumExtraLod = numLods; return NO_ERROR; } void EGLTextureObject::freeMipmaps() { if (mMipmaps) { for (int i=0 ; i(mip(lod)); } status_t EGLTextureObject::setSurface(GGLSurface const* s) { // XXX: glFlush() on 's' if (mSize && surface.data) { free(surface.data); } surface = *s; internalformat = 0; buffer = 0; // we should keep the crop_rect, but it's delicate because // the new size of the surface could make it invalid. // so for now, we just loose it. memset(crop_rect, 0, sizeof(crop_rect)); // it would be nice if we could keep the generate_mipmap flag, // we would have to generate them right now though. generate_mipmap = GL_FALSE; direct = GL_TRUE; mSize = 0; // we don't own this surface if (mMipmaps) freeMipmaps(); mIsComplete = true; return NO_ERROR; } status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer) { GGLSurface sur; sur.version = sizeof(GGLSurface); sur.width = native_buffer->width; sur.height= native_buffer->height; sur.stride= native_buffer->stride; sur.format= native_buffer->format; sur.data = 0; setSurface(&sur); buffer = native_buffer; return NO_ERROR; } status_t EGLTextureObject::reallocate( GLint level, int w, int h, int s, int format, int compressedFormat, int bpr) { const size_t size = h * bpr; if (level == 0) { if (size!=mSize || !surface.data) { if (mSize && surface.data) { free(surface.data); } surface.data = (GGLubyte*)malloc(size); if (!surface.data) { mSize = 0; mIsComplete = false; return NO_MEMORY; } mSize = size; } surface.version = sizeof(GGLSurface); surface.width = w; surface.height = h; surface.stride = s; surface.format = format; surface.compressedFormat = compressedFormat; if (mMipmaps) freeMipmaps(); mIsComplete = true; } else { if (!mMipmaps) { if (allocateMipmaps() != NO_ERROR) return NO_MEMORY; } ALOGW_IF(level-1 >= mNumExtraLod, "specifying mipmap level %d, but # of level is %d", level, mNumExtraLod+1); GGLSurface& mipmap = editMip(level); if (mipmap.data) free(mipmap.data); mipmap.data = (GGLubyte*)malloc(size); if (!mipmap.data) { memset(&mipmap, 0, sizeof(GGLSurface)); mIsComplete = false; return NO_MEMORY; } mipmap.version = sizeof(GGLSurface); mipmap.width = w; mipmap.height = h; mipmap.stride = s; mipmap.format = format; mipmap.compressedFormat = compressedFormat; // check if the texture is complete mIsComplete = true; const GGLSurface* prev = &surface; for (int i=0 ; iformat != surface.format) { mIsComplete = false; break; } uint32_t w = (prev->width >> 1) ? : 1; uint32_t h = (prev->height >> 1) ? : 1; if (w != curr->width || h != curr->height) { mIsComplete = false; break; } prev = curr; } } return NO_ERROR; } // ---------------------------------------------------------------------------- EGLSurfaceManager::EGLSurfaceManager() : TokenManager() { } EGLSurfaceManager::~EGLSurfaceManager() { // everything gets freed automatically here... } sp EGLSurfaceManager::createTexture(GLuint name) { sp result; Mutex::Autolock _l(mLock); if (mTextures.indexOfKey(name) >= 0) return result; // already exists! result = new EGLTextureObject(); status_t err = mTextures.add(name, result); if (err < 0) result.clear(); return result; } sp EGLSurfaceManager::removeTexture(GLuint name) { Mutex::Autolock _l(mLock); const ssize_t index = mTextures.indexOfKey(name); if (index >= 0) { sp result(mTextures.valueAt(index)); mTextures.removeItemsAt(index); return result; } return 0; } sp EGLSurfaceManager::replaceTexture(GLuint name) { sp tex; Mutex::Autolock _l(mLock); const ssize_t index = mTextures.indexOfKey(name); if (index >= 0) { const sp& old = mTextures.valueAt(index); const uint32_t refs = old->getStrongCount(); if (ggl_likely(refs == 1)) { // we're the only owner tex = old; } else { // keep the texture's parameters tex = new EGLTextureObject(); tex->copyParameters(old); mTextures.removeItemsAt(index); mTextures.add(name, tex); } } return tex; } void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens) { // free all textures Mutex::Autolock _l(mLock); for (GLsizei i=0 ; i EGLSurfaceManager::texture(GLuint name) { Mutex::Autolock _l(mLock); const ssize_t index = mTextures.indexOfKey(name); if (index >= 0) return mTextures.valueAt(index); return 0; } // ---------------------------------------------------------------------------- }; // namespace android opengl/libagl/TextureObjectManager.h0100644 0000000 0000000 00000006614 13077405420 016567 0ustar000000000 0000000 /* ** Copyright 2006, 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_OPENGLES_SURFACE_H #define ANDROID_OPENGLES_SURFACE_H #include #include #include #include #include #include #include #include #include #include #include #include #include "Tokenizer.h" #include "TokenManager.h" namespace android { // ---------------------------------------------------------------------------- class EGLTextureObject : public LightRefBase { public: EGLTextureObject(); ~EGLTextureObject(); status_t setSurface(GGLSurface const* s); status_t setImage(ANativeWindowBuffer* buffer); void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; } status_t reallocate(GLint level, int w, int h, int s, int format, int compressedFormat, int bpr); inline size_t size() const { return mSize; } const GGLSurface& mip(int lod) const; GGLSurface& editMip(int lod); bool hasMipmaps() const { return mMipmaps!=0; } bool isComplete() const { return mIsComplete; } void copyParameters(const sp& old); private: status_t allocateMipmaps(); void freeMipmaps(); void init(); size_t mSize; GGLSurface *mMipmaps; int mNumExtraLod; bool mIsComplete; public: GGLSurface surface; GLenum wraps; GLenum wrapt; GLenum min_filter; GLenum mag_filter; GLenum internalformat; GLint crop_rect[4]; GLint generate_mipmap; GLint direct; ANativeWindowBuffer* buffer; }; // ---------------------------------------------------------------------------- class EGLSurfaceManager : public LightRefBase, public TokenManager { public: EGLSurfaceManager(); ~EGLSurfaceManager(); sp createTexture(GLuint name); sp removeTexture(GLuint name); sp replaceTexture(GLuint name); void deleteTextures(GLsizei n, const GLuint *tokens); sp texture(GLuint name); private: mutable Mutex mLock; KeyedVector< GLuint, sp > mTextures; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_OPENGLES_SURFACE_H opengl/libagl/TokenManager.cpp0100644 0000000 0000000 00000003132 13077405420 015403 0ustar000000000 0000000 /* libs/opengles/surface.cpp ** ** Copyright 2006, 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 #include #include "TokenManager.h" namespace android { // ---------------------------------------------------------------------------- TokenManager::TokenManager() { // token 0 is always reserved mTokenizer.reserve(0); } TokenManager::~TokenManager() { } status_t TokenManager::getToken(GLsizei n, GLuint *tokens) { Mutex::Autolock _l(mLock); for (GLsizei i=0 ; i #include #include #include #include #include "Tokenizer.h" namespace android { // ---------------------------------------------------------------------------- class TokenManager { public: TokenManager(); ~TokenManager(); status_t getToken(GLsizei n, GLuint *tokens); void recycleTokens(GLsizei n, const GLuint *tokens); bool isTokenValid(GLuint token) const; private: mutable Mutex mLock; Tokenizer mTokenizer; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_OPENGLES_TOKEN_MANAGER_H opengl/libagl/Tokenizer.cpp0100644 0000000 0000000 00000011042 13077405420 015001 0ustar000000000 0000000 /* libs/opengles/Tokenizer.cpp ** ** Copyright 2006, 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 #include "Tokenizer.h" // ---------------------------------------------------------------------------- namespace android { ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t) Tokenizer::Tokenizer() { } Tokenizer::Tokenizer(const Tokenizer& other) : mRanges(other.mRanges) { } Tokenizer::~Tokenizer() { } uint32_t Tokenizer::acquire() { if (!mRanges.size() || mRanges[0].first) { _insertTokenAt(0,0); return 0; } // just extend the first run const run_t& run = mRanges[0]; uint32_t token = run.first + run.length; _insertTokenAt(token, 1); return token; } bool Tokenizer::isAcquired(uint32_t token) const { return (_indexOrderOf(token) >= 0); } status_t Tokenizer::reserve(uint32_t token) { size_t o; const ssize_t i = _indexOrderOf(token, &o); if (i >= 0) { return BAD_VALUE; // this token is already taken } ssize_t err = _insertTokenAt(token, o); return (err<0) ? err : status_t(NO_ERROR); } status_t Tokenizer::release(uint32_t token) { const ssize_t i = _indexOrderOf(token); if (i >= 0) { const run_t& run = mRanges[i]; if ((token >= run.first) && (token < run.first+run.length)) { // token in this range, we need to split run_t& run = mRanges.editItemAt(i); if ((token == run.first) || (token == run.first+run.length-1)) { if (token == run.first) { run.first += 1; } run.length -= 1; if (run.length == 0) { // XXX: should we systematically remove a run that's empty? mRanges.removeItemsAt(i); } } else { // split the run run_t new_run; new_run.first = token+1; new_run.length = run.first+run.length - new_run.first; run.length = token - run.first; mRanges.insertAt(new_run, i+1); } return NO_ERROR; } } return NAME_NOT_FOUND; } ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const { // binary search ssize_t err = NAME_NOT_FOUND; ssize_t l = 0; ssize_t h = mRanges.size()-1; ssize_t mid; const run_t* a = mRanges.array(); while (l <= h) { mid = l + (h - l)/2; const run_t* const curr = a + mid; int c = 0; if (token < curr->first) c = 1; else if (token >= curr->first+curr->length) c = -1; if (c == 0) { err = l = mid; break; } else if (c < 0) { l = mid + 1; } else { h = mid - 1; } } if (order) *order = l; return err; } ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index) { const size_t c = mRanges.size(); if (index >= 1) { // do we need to merge with the previous run? run_t& p = mRanges.editItemAt(index-1); if (p.first+p.length == token) { p.length += 1; if (index < c) { const run_t& n = mRanges[index]; if (token+1 == n.first) { p.length += n.length; mRanges.removeItemsAt(index); } } return index; } } if (index < c) { // do we need to merge with the next run? run_t& n = mRanges.editItemAt(index); if (token+1 == n.first) { n.first -= 1; n.length += 1; return index; } } return mRanges.insertAt(run_t(token,1), index); } void Tokenizer::dump() const { const run_t* ranges = mRanges.array(); const size_t c = mRanges.size(); ALOGD("Tokenizer (%p, size = %zu)\n", this, c); for (size_t i=0 ; i #include // ---------------------------------------------------------------------------- namespace android { class Tokenizer { public: Tokenizer(); Tokenizer(const Tokenizer& other); ~Tokenizer(); uint32_t acquire(); status_t reserve(uint32_t token); status_t release(uint32_t token); bool isAcquired(uint32_t token) const; void dump() const; struct run_t { run_t() {}; run_t(uint32_t f, uint32_t l) : first(f), length(l) {} uint32_t first; uint32_t length; }; private: ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const; ssize_t _insertTokenAt(uint32_t token, size_t index); Vector mRanges; }; }; // namespace android // ---------------------------------------------------------------------------- #endif // ANDROID_OPENGLES_TOKENIZER_H opengl/libagl/arch-mips/0040755 0000000 0000000 00000000000 13077405420 014213 5ustar000000000 0000000 opengl/libagl/arch-mips/fixed_asm.S0100644 0000000 0000000 00000003312 13077405420 016272 0ustar000000000 0000000 /* libs/opengles/arch-mips/fixed_asm.S ** ** Copyright 2012, 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. */ .text .align /* * this version rounds-to-nearest and saturates numbers * outside the range (but not NaNs). */ .global gglFloatToFixed .ent gglFloatToFixed .type gglFloatToFixed, @function gglFloatToFixed: #if !defined(__mips_soft_float) mfc1 $a0,$f12 #endif srl $t0,$a0,31 /* t0 <- sign bit */ srl $t1,$a0,23 andi $t1,$t1,0xff /* get the e */ li $t2,0x8e subu $t1,$t2,$t1 /* t1=127+15-e */ blez $t1,0f /* t1<=0? */ sll $t2,$a0,8 /* mantissa<<8 */ lui $t3,0x8000 or $t2,$t2,$t3 /* add the missing 1 */ subu $t1,$t1,1 srl $v0,$t2,$t1 sltiu $t3,$t1,32 /* t3=1 if t1<32, else t3=0. t1>=32 means the float value is too small. */ andi $t4,$v0,0x1 srl $v0,$v0,1 /* scale to 16.16 */ addu $v0,$v0,$t4 /* round-to-nearest */ subu $t2,$zero,$v0 movn $v0,$t2,$t0 /* if negative? */ or $t1,$a0,$zero /* a0=0? */ movz $v0,$zero,$t1 movz $v0,$zero,$t3 /* t3=0 then res=0 */ jr $ra 0: lui $t1,0x8000 and $v0,$a0,$t1 /* keep only the sign bit */ li $t1,0x7fffffff movz $v0,$t1,$t0 /* positive, maximum value */ jr $ra .end gglFloatToFixed opengl/libagl/array.cpp0100644 0000000 0000000 00000136233 13077405420 014157 0ustar000000000 0000000 /* ** Copyright 2006, 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 #include #include "context.h" #include "fp.h" #include "state.h" #include "matrix.h" #include "vertex.h" #include "light.h" #include "primitives.h" #include "texture.h" #include "BufferObjectManager.h" // ---------------------------------------------------------------------------- #define VC_CACHE_STATISTICS 0 #define VC_CACHE_TYPE_NONE 0 #define VC_CACHE_TYPE_INDEXED 1 #define VC_CACHE_TYPE_LRU 2 #define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED #if VC_CACHE_STATISTICS #include #endif // ---------------------------------------------------------------------------- namespace android { static void validate_arrays(ogles_context_t* c, GLenum mode); static void compileElements__generic(ogles_context_t*, vertex_t*, GLint, GLsizei); static void compileElement__generic(ogles_context_t*, vertex_t*, GLint); static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei); static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei); static void drawIndexedPrimitivesPoints(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesLineStrip(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesLineLoop(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesLines(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesTriangleFan(ogles_context_t*, GLsizei, const GLvoid*); static void drawIndexedPrimitivesTriangles(ogles_context_t*, GLsizei, const GLvoid*); // ---------------------------------------------------------------------------- typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei); static const arrays_prims_fct_t drawArraysPrims[] = { drawPrimitivesPoints, drawPrimitivesLines, drawPrimitivesLineLoop, drawPrimitivesLineStrip, drawPrimitivesTriangles, drawPrimitivesTriangleStrip, drawPrimitivesTriangleFan }; typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*); static const elements_prims_fct_t drawElementsPrims[] = { drawIndexedPrimitivesPoints, drawIndexedPrimitivesLines, drawIndexedPrimitivesLineLoop, drawIndexedPrimitivesLineStrip, drawIndexedPrimitivesTriangles, drawIndexedPrimitivesTriangleStrip, drawIndexedPrimitivesTriangleFan }; // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void ogles_init_array(ogles_context_t* c) { c->arrays.vertex.size = 4; c->arrays.vertex.type = GL_FLOAT; c->arrays.color.size = 4; c->arrays.color.type = GL_FLOAT; c->arrays.normal.size = 4; c->arrays.normal.type = GL_FLOAT; for (int i=0 ; iarrays.texture[i].size = 4; c->arrays.texture[i].type = GL_FLOAT; } c->vc.init(); if (!c->vc.vBuffer) { // this could have failed ogles_error(c, GL_OUT_OF_MEMORY); } } void ogles_uninit_array(ogles_context_t* c) { c->vc.uninit(); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Array fetchers #endif static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) { memcpy(v, c->current.color.v, sizeof(vec4_t)); } static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) { memcpy(v, c->currentColorClamped.v, sizeof(vec4_t)); } static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) { memcpy(v, c->currentNormal.v, sizeof(vec3_t)); } static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) { memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t)); } static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) { } static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); } static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); } static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) { memcpy(v, p, 2*sizeof(GLfixed)); } static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) { v[0] = gglFloatToFixed(p[0]); v[1] = gglFloatToFixed(p[1]); } static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); v[2] = gglIntToFixed(p[2]); } static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); v[2] = gglIntToFixed(p[2]); } static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { memcpy(v, p, 3*sizeof(GLfixed)); } static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { v[0] = gglFloatToFixed(p[0]); v[1] = gglFloatToFixed(p[1]); v[2] = gglFloatToFixed(p[2]); } static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); v[2] = gglIntToFixed(p[2]); v[3] = gglIntToFixed(p[3]); } static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) { v[0] = gglIntToFixed(p[0]); v[1] = gglIntToFixed(p[1]); v[2] = gglIntToFixed(p[2]); v[3] = gglIntToFixed(p[3]); } static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { memcpy(v, p, 4*sizeof(GLfixed)); } static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { v[0] = gglFloatToFixed(p[0]); v[1] = gglFloatToFixed(p[1]); v[2] = gglFloatToFixed(p[2]); v[3] = gglFloatToFixed(p[3]); } static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { v[0] = GGL_UB_TO_X(p[0]); v[1] = GGL_UB_TO_X(p[1]); v[2] = GGL_UB_TO_X(p[2]); v[3] = GGL_UB_TO_X(p[3]); } static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) { v[0] = gglClampx(p[0]); v[1] = gglClampx(p[1]); v[2] = gglClampx(p[2]); v[3] = gglClampx(p[3]); } static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) { v[0] = gglClampx(gglFloatToFixed(p[0])); v[1] = gglClampx(gglFloatToFixed(p[1])); v[2] = gglClampx(gglFloatToFixed(p[2])); v[3] = gglClampx(gglFloatToFixed(p[3])); } static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) { v[0] = GGL_UB_TO_X(p[0]); v[1] = GGL_UB_TO_X(p[1]); v[2] = GGL_UB_TO_X(p[2]); v[3] = 0x10000; } static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) { v[0] = gglClampx(p[0]); v[1] = gglClampx(p[1]); v[2] = gglClampx(p[2]); v[3] = 0x10000; } static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) { v[0] = gglClampx(gglFloatToFixed(p[0])); v[1] = gglClampx(gglFloatToFixed(p[1])); v[2] = gglClampx(gglFloatToFixed(p[2])); v[3] = 0x10000; } static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) { v[0] = GGL_B_TO_X(p[0]); v[1] = GGL_B_TO_X(p[1]); v[2] = GGL_B_TO_X(p[2]); } static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) { v[0] = GGL_S_TO_X(p[0]); v[1] = GGL_S_TO_X(p[1]); v[2] = GGL_S_TO_X(p[2]); } typedef array_t::fetcher_t fn_t; static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x} { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, (fn_t)fetch3f, 0, 0, 0, 0, 0, (fn_t)fetch3x }, { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, (fn_t)fetch4f, 0, 0, 0, 0, 0, (fn_t)fetch4x }, }; static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x} { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0, (fn_t)fetchClamp3f, 0, 0, 0, 0, 0, (fn_t)fetchClamp3x }, { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0, (fn_t)fetchClamp4f, 0, 0, 0, 0, 0, (fn_t)fetchClamp4x }, }; static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x} { (fn_t)fetchExpand3b, 0, (fn_t)fetchExpand3s, 0, 0, 0, (fn_t)fetch3f, 0, 0, 0, 0, 0, (fn_t)fetch3x }, }; static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} { (fn_t)fetch2b, 0, (fn_t)fetch2s, 0, 0, 0, (fn_t)fetch2f, 0, 0, 0, 0, 0, (fn_t)fetch3x }, { (fn_t)fetch3b, 0, (fn_t)fetch3s, 0, 0, 0, (fn_t)fetch3f, 0, 0, 0, 0, 0, (fn_t)fetch3x }, { (fn_t)fetch4b, 0, (fn_t)fetch4s, 0, 0, 0, (fn_t)fetch4f, 0, 0, 0, 0, 0, (fn_t)fetch4x } }; static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x} { (fn_t)fetch2b, 0, (fn_t)fetch2s, 0, 0, 0, (fn_t)fetch2f, 0, 0, 0, 0, 0, (fn_t)fetch2x }, { (fn_t)fetch3b, 0, (fn_t)fetch3s, 0, 0, 0, (fn_t)fetch3f, 0, 0, 0, 0, 0, (fn_t)fetch3x }, { (fn_t)fetch4b, 0, (fn_t)fetch4s, 0, 0, 0, (fn_t)fetch4f, 0, 0, 0, 0, 0, (fn_t)fetch4x } }; // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark array_t #endif void array_t::init( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, const buffer_t* bo, GLsizei count) { if (!stride) { stride = size; switch (type) { case GL_SHORT: case GL_UNSIGNED_SHORT: stride *= 2; break; case GL_FLOAT: case GL_FIXED: stride *= 4; break; } } this->size = size; this->type = type; this->stride = stride; this->pointer = pointer; this->bo = bo; this->bounds = count; } inline void array_t::resolve() { physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer; } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark vertex_cache_t #endif void vertex_cache_t::init() { // make sure the size of vertex_t allows cache-line alignment CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize; const int align = 32; const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; const size_t size = s*sizeof(vertex_t) + align; base = malloc(size); if (base) { memset(base, 0, size); vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1)); vCache = vBuffer + VERTEX_BUFFER_SIZE; sequence = 0; } } void vertex_cache_t::uninit() { free(base); base = vBuffer = vCache = 0; } void vertex_cache_t::clear() { #if VC_CACHE_STATISTICS startTime = systemTime(SYSTEM_TIME_THREAD); total = 0; misses = 0; #endif #if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU vertex_t* v = vBuffer; size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; do { v->mru = 0; v++; } while (--count); #endif sequence += INDEX_SEQ; if (sequence >= 0x80000000LU) { sequence = INDEX_SEQ; vertex_t* v = vBuffer; size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE; do { v->index = 0; v++; } while (--count); } } #if VC_CACHE_STATISTICS void vertex_cache_t::dump_stats(GLenum mode) { nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime; uint32_t hits = total - misses; uint32_t prim_count; switch (mode) { case GL_POINTS: prim_count = total; break; case GL_LINE_STRIP: prim_count = total - 1; break; case GL_LINE_LOOP: prim_count = total - 1; break; case GL_LINES: prim_count = total / 2; break; case GL_TRIANGLE_STRIP: prim_count = total - 2; break; case GL_TRIANGLE_FAN: prim_count = total - 2; break; case GL_TRIANGLES: prim_count = total / 3; break; default: return; } printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%," " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n", total, hits, misses, (hits*100)/total, prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time), float(misses) / prim_count); } #else void vertex_cache_t::dump_stats(GLenum /*mode*/) { } #endif // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif static __attribute__((noinline)) void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable) { const int tmu = c->arrays.activeTexture; array_t* a; switch (array) { case GL_COLOR_ARRAY: a = &c->arrays.color; break; case GL_NORMAL_ARRAY: a = &c->arrays.normal; break; case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break; case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break; default: ogles_error(c, GL_INVALID_ENUM); return; } a->enable = enable ? GL_TRUE : GL_FALSE; } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Vertex Cache #endif static __attribute__((noinline)) vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index) { #if VC_CACHE_STATISTICS c->vc.misses++; #endif if (ggl_unlikely(v->locked)) { // we're just looking for an entry in the cache that is not locked. // and we know that there cannot be more than 2 locked entries // because a triangle needs at most 3 vertices. // We never use the first and second entries because they might be in // use by the striper or faner. Any other entry will do as long as // it's not locked. // We compute directly the index of a "free" entry from the locked // state of v[2] and v[3]. v = c->vc.vBuffer + 2; v += v[0].locked | (v[1].locked<<1); } // note: compileElement clears v->flags c->arrays.compileElement(c, v, index); v->locked = 1; return v; } static __attribute__((noinline)) vertex_t* fetch_vertex(ogles_context_t* c, size_t index) { index |= c->vc.sequence; #if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED vertex_t* const v = c->vc.vCache + (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1)); if (ggl_likely(v->index == index)) { v->locked = 1; return v; } return cache_vertex(c, v, index); #elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU vertex_t* v = c->vc.vCache + (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2; // always record LRU in v[0] if (ggl_likely(v[0].index == index)) { v[0].locked = 1; v[0].mru = 0; return &v[0]; } if (ggl_likely(v[1].index == index)) { v[1].locked = 1; v[0].mru = 1; return &v[1]; } const int lru = 1 - v[0].mru; v[0].mru = lru; return cache_vertex(c, &v[lru], index); #elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE // just for debugging... vertex_t* v = c->vc.vBuffer + 2; return cache_vertex(c, v, index); #endif } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Primitive Assembly #endif void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count) { if (ggl_unlikely(count < 1)) return; // vertex cache size must be multiple of 1 const GLsizei vcs = (vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE); do { vertex_t* v = c->vc.vBuffer; GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; count -= num; if (!c->arrays.cull) { // quick/trivial reject of the whole batch do { const uint32_t cc = v[0].flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderPoint(c, v); v++; num--; } while (num); } } while (count); } // ---------------------------------------------------------------------------- void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count) { if (ggl_unlikely(count < 2)) return; vertex_t *v, *v0, *v1; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElement(c, c->vc.vBuffer, first); first += 1; count -= 1; // vertex cache size must be multiple of 1 const GLsizei vcs = (vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE - 1); do { v0 = c->vc.vBuffer + 0; v = c->vc.vBuffer + 1; GLsizei num = count > vcs ? vcs : count; c->arrays.compileElements(c, v, first, num); first += num; count -= num; if (!c->arrays.cull) { // quick/trivial reject of the whole batch do { v1 = v++; const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); v0 = v1; num--; } while (num); } // copy back the last processed vertex c->vc.vBuffer[0] = *v0; c->arrays.cull = v0->flags & vertex_t::CLIP_ALL; } while (count); } void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count) { if (ggl_unlikely(count < 2)) return; drawPrimitivesLineStrip(c, first, count); if (ggl_likely(count >= 3)) { vertex_t* v0 = c->vc.vBuffer; vertex_t* v1 = c->vc.vBuffer + 1; c->arrays.compileElement(c, v1, first); const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); } } void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count) { if (ggl_unlikely(count < 2)) return; // vertex cache size must be multiple of 2 const GLsizei vcs = ((vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2; do { vertex_t* v = c->vc.vBuffer; GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; count -= num; if (!c->arrays.cull) { // quick/trivial reject of the whole batch num -= 2; do { const uint32_t cc = v[0].flags & v[1].flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v, v+1); v += 2; num -= 2; } while (num >= 0); } } while (count >= 2); } // ---------------------------------------------------------------------------- static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c, GLint first, GLsizei count, int winding) { // winding == 2 : fan // winding == 1 : strip if (ggl_unlikely(count < 3)) return; vertex_t *v, *v0, *v1, *v2; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, c->vc.vBuffer, first, 2); first += 2; count -= 2; // vertex cache size must be multiple of 2. This is extremely important // because it allows us to preserve the same winding when the whole // batch is culled. We also need 2 extra vertices in the array, because // we always keep the two first ones. const GLsizei vcs = ((vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2; do { v0 = c->vc.vBuffer + 0; v1 = c->vc.vBuffer + 1; v = c->vc.vBuffer + 2; GLsizei num = count > vcs ? vcs : count; c->arrays.compileElements(c, v, first, num); first += num; count -= num; if (!c->arrays.cull) { // quick/trivial reject of the whole batch do { v2 = v++; const uint32_t cc = v0->flags & v1->flags & v2->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderTriangle(c, v0, v1, v2); swap(((winding^=1) ? v1 : v0), v2); num--; } while (num); } if (count) { v0 = c->vc.vBuffer + 2 + vcs - 2; v1 = c->vc.vBuffer + 2 + vcs - 1; if ((winding&2) == 0) { // for strips copy back the two last compiled vertices c->vc.vBuffer[0] = *v0; } c->vc.vBuffer[1] = *v1; c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL; } } while (count > 0); } void drawPrimitivesTriangleStrip(ogles_context_t* c, GLint first, GLsizei count) { drawPrimitivesTriangleFanOrStrip(c, first, count, 1); } void drawPrimitivesTriangleFan(ogles_context_t* c, GLint first, GLsizei count) { drawPrimitivesTriangleFanOrStrip(c, first, count, 2); } void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count) { if (ggl_unlikely(count < 3)) return; // vertex cache size must be multiple of 3 const GLsizei vcs = ((vertex_cache_t::VERTEX_BUFFER_SIZE + vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3; do { vertex_t* v = c->vc.vBuffer; GLsizei num = count > vcs ? vcs : count; c->arrays.cull = vertex_t::CLIP_ALL; c->arrays.compileElements(c, v, first, num); first += num; count -= num; if (!c->arrays.cull) { // quick/trivial reject of the whole batch num -= 3; do { const uint32_t cc = v[0].flags & v[1].flags & v[2].flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderTriangle(c, v, v+1, v+2); v += 3; num -= 3; } while (num >= 0); } } while (count >= 3); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif // this looks goofy, but gcc does a great job with this... static inline unsigned int read_index(int type, const GLvoid*& p) { unsigned int r; if (type) { r = *(const GLubyte*)p; p = (const GLubyte*)p + 1; } else { r = *(const GLushort*)p; p = (const GLushort*)p + 1; } return r; } // ---------------------------------------------------------------------------- void drawIndexedPrimitivesPoints(ogles_context_t* c, GLsizei count, const GLvoid *indices) { if (ggl_unlikely(count < 1)) return; const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); do { vertex_t * v = fetch_vertex(c, read_index(type, indices)); if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL))) c->prims.renderPoint(c, v); v->locked = 0; count--; } while(count); } // ---------------------------------------------------------------------------- void drawIndexedPrimitivesLineStrip(ogles_context_t* c, GLsizei count, const GLvoid *indices) { if (ggl_unlikely(count < 2)) return; vertex_t * const v = c->vc.vBuffer; vertex_t* v0 = v; vertex_t* v1; const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); c->arrays.compileElement(c, v0, read_index(type, indices)); count -= 1; do { v1 = fetch_vertex(c, read_index(type, indices)); const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); v0->locked = 0; v0 = v1; count--; } while (count); v1->locked = 0; } void drawIndexedPrimitivesLineLoop(ogles_context_t* c, GLsizei count, const GLvoid *indices) { if (ggl_unlikely(count <= 2)) { drawIndexedPrimitivesLines(c, count, indices); return; } vertex_t * const v = c->vc.vBuffer; vertex_t* v0 = v; vertex_t* v1; const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); c->arrays.compileElement(c, v0, read_index(type, indices)); count -= 1; do { v1 = fetch_vertex(c, read_index(type, indices)); const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); v0->locked = 0; v0 = v1; count--; } while (count); v1->locked = 0; v1 = c->vc.vBuffer; const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); } void drawIndexedPrimitivesLines(ogles_context_t* c, GLsizei count, const GLvoid *indices) { if (ggl_unlikely(count < 2)) return; count -= 2; const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); do { vertex_t* const v0 = fetch_vertex(c, read_index(type, indices)); vertex_t* const v1 = fetch_vertex(c, read_index(type, indices)); const uint32_t cc = v0->flags & v1->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderLine(c, v0, v1); v0->locked = 0; v1->locked = 0; count -= 2; } while (count >= 0); } // ---------------------------------------------------------------------------- static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c, GLsizei count, const GLvoid *indices, int winding) { // winding == 2 : fan // winding == 1 : strip if (ggl_unlikely(count < 3)) return; vertex_t * const v = c->vc.vBuffer; vertex_t* v0 = v; vertex_t* v1 = v+1; vertex_t* v2; const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE); c->arrays.compileElement(c, v0, read_index(type, indices)); c->arrays.compileElement(c, v1, read_index(type, indices)); count -= 2; // note: GCC 4.1.1 here makes a prety interesting optimization // where it duplicates the loop below based on c->arrays.indicesType do { v2 = fetch_vertex(c, read_index(type, indices)); const uint32_t cc = v0->flags & v1->flags & v2->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderTriangle(c, v0, v1, v2); vertex_t* & consumed = ((winding^=1) ? v1 : v0); consumed->locked = 0; consumed = v2; count--; } while (count); v0->locked = v1->locked = 0; v2->locked = 0; } void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c, GLsizei count, const GLvoid *indices) { drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1); } void drawIndexedPrimitivesTriangleFan(ogles_context_t* c, GLsizei count, const GLvoid *indices) { drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2); } void drawIndexedPrimitivesTriangles(ogles_context_t* c, GLsizei count, const GLvoid *indices) { if (ggl_unlikely(count < 3)) return; count -= 3; if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) { // This case is probably our most common case... uint16_t const * p = (uint16_t const *)indices; do { vertex_t* const v0 = fetch_vertex(c, *p++); vertex_t* const v1 = fetch_vertex(c, *p++); vertex_t* const v2 = fetch_vertex(c, *p++); const uint32_t cc = v0->flags & v1->flags & v2->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderTriangle(c, v0, v1, v2); v0->locked = 0; v1->locked = 0; v2->locked = 0; count -= 3; } while (count >= 0); } else { uint8_t const * p = (uint8_t const *)indices; do { vertex_t* const v0 = fetch_vertex(c, *p++); vertex_t* const v1 = fetch_vertex(c, *p++); vertex_t* const v2 = fetch_vertex(c, *p++); const uint32_t cc = v0->flags & v1->flags & v2->flags; if (ggl_likely(!(cc & vertex_t::CLIP_ALL))) c->prims.renderTriangle(c, v0, v1, v2); v0->locked = 0; v1->locked = 0; v2->locked = 0; count -= 3; } while (count >= 0); } } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Array compilers #endif void compileElement__generic(ogles_context_t* c, vertex_t* v, GLint first) { v->flags = 0; v->index = first; first &= vertex_cache_t::INDEX_MASK; const GLubyte* vp = c->arrays.vertex.element(first); v->obj.z = 0; v->obj.w = 0x10000; c->arrays.vertex.fetch(c, v->obj.v, vp); c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj); c->arrays.perspective(c, v); } void compileElements__generic(ogles_context_t* c, vertex_t* v, GLint first, GLsizei count) { const GLubyte* vp = c->arrays.vertex.element( first & vertex_cache_t::INDEX_MASK); const size_t stride = c->arrays.vertex.stride; transform_t const* const mvp = &c->transforms.mvp; do { v->flags = 0; v->index = first++; v->obj.z = 0; v->obj.w = 0x10000; c->arrays.vertex.fetch(c, v->obj.v, vp); c->arrays.mvp_transform(mvp, &v->clip, &v->obj); c->arrays.perspective(c, v); vp += stride; v++; } while (--count); } /* void compileElements__3x_full(ogles_context_t* c, vertex_t* v, GLint first, GLsizei count) { const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first); const size_t stride = c->arrays.vertex.stride / 4; // const GLfixed* const& m = c->transforms.mvp.matrix.m; GLfixed m[16]; memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m)); do { const GLfixed rx = vp[0]; const GLfixed ry = vp[1]; const GLfixed rz = vp[2]; vp += stride; v->index = first++; v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); const GLfixed w = v->clip.w; uint32_t clip = 0; if (v->clip.x < -w) clip |= vertex_t::CLIP_L; if (v->clip.x > w) clip |= vertex_t::CLIP_R; if (v->clip.y < -w) clip |= vertex_t::CLIP_B; if (v->clip.y > w) clip |= vertex_t::CLIP_T; if (v->clip.z < -w) clip |= vertex_t::CLIP_N; if (v->clip.z > w) clip |= vertex_t::CLIP_F; v->flags = clip; c->arrays.cull &= clip; //c->arrays.perspective(c, v); v++; } while (--count); } */ // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark clippers #endif static void clipVec4(vec4_t& nv, GLfixed t, const vec4_t& s, const vec4_t& p) { for (int i=0; i<4 ; i++) nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28); } static void clipVertex(ogles_context_t* c, vertex_t* nv, GLfixed t, const vertex_t* s, const vertex_t* p) { clipVec4(nv->clip, t, s->clip, p->clip); nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28); ogles_vertex_project(c, nv); nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT; nv->flags &= ~vertex_t::CLIP_ALL; } static void clipVertexC(ogles_context_t* c, vertex_t* nv, GLfixed t, const vertex_t* s, const vertex_t* p) { clipVec4(nv->color, t, s->color, p->color); clipVertex(c, nv, t, s, p); } static void clipVertexT(ogles_context_t* c, vertex_t* nv, GLfixed t, const vertex_t* s, const vertex_t* p) { for (int i=0 ; irasterizer.state.texture[i].enable) clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]); } clipVertex(c, nv, t, s, p); } static void clipVertexAll(ogles_context_t* c, vertex_t* nv, GLfixed t, const vertex_t* s, const vertex_t* p) { clipVec4(nv->color, t, s->color, p->color); clipVertexT(c, nv, t, s, p); } static void clipEye(ogles_context_t* c, vertex_t* nv, GLfixed t, const vertex_t* s, const vertex_t* p) { nv->clear(); c->arrays.clipVertex(c, nv, t, p, s); clipVec4(nv->eye, t, s->eye, p->eye); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void validate_arrays(ogles_context_t* c, GLenum mode) { uint32_t enables = c->rasterizer.state.enables; // Perspective correction is not need if Ortho transform, but // the user can still provide the w coordinate manually, so we can't // automatically turn it off (in fact we could when the 4th coordinate // is not spcified in the vertex array). // W interpolation is never needed for points. GLboolean perspective = c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS); c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective); // set anti-aliasing GLboolean smooth = GL_FALSE; switch (mode) { case GL_POINTS: smooth = c->point.smooth; break; case GL_LINES: case GL_LINE_LOOP: case GL_LINE_STRIP: smooth = c->line.smooth; break; } if (((enables & GGL_ENABLE_AA)?1:0) != smooth) c->rasterizer.procs.enableDisable(c, GGL_AA, smooth); // set the shade model for this primitive c->rasterizer.procs.shadeModel(c, (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel); // compute all the matrices we'll need... uint32_t want = transform_state_t::MVP | transform_state_t::VIEWPORT; if (c->lighting.enable) { // needs normal transforms and eye coords want |= transform_state_t::MVUI; want |= transform_state_t::MODELVIEW; } if (enables & GGL_ENABLE_TMUS) { // needs texture transforms want |= transform_state_t::TEXTURE; } if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { want |= transform_state_t::MODELVIEW; // needs eye coords } ogles_validate_transform(c, want); // textures... if (enables & GGL_ENABLE_TMUS) ogles_validate_texture(c); // vertex compilers c->arrays.compileElement = compileElement__generic; c->arrays.compileElements = compileElements__generic; // vertex transform c->arrays.mvp_transform = c->transforms.mvp.pointv[c->arrays.vertex.size - 2]; c->arrays.mv_transform = c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2]; /* * *********************************************************************** * pick fetchers * *********************************************************************** */ array_machine_t& am = c->arrays; am.vertex.fetch = fetchNop; am.normal.fetch = currentNormal; am.color.fetch = currentColor; if (am.vertex.enable) { am.vertex.resolve(); if (am.vertex.bo || am.vertex.pointer) { am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF]; } } if (am.normal.enable) { am.normal.resolve(); if (am.normal.bo || am.normal.pointer) { am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF]; } } if (am.color.enable) { am.color.resolve(); if (c->lighting.enable) { if (am.color.bo || am.color.pointer) { am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF]; } } else { if (am.color.bo || am.color.pointer) { am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF]; } } } int activeTmuCount = 0; for (int i=0 ; irasterizer.state.texture[i].enable) { // texture fetchers... if (am.texture[i].enable) { am.texture[i].resolve(); if (am.texture[i].bo || am.texture[i].pointer) { am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF]; } } // texture transform... const int index = c->arrays.texture[i].size - 2; c->arrays.tex_transform[i] = c->transforms.texture[i].transform.pointv[index]; am.tmu = i; activeTmuCount++; } } // pick the vertex-clipper uint32_t clipper = 0; // we must reload 'enables' here enables = c->rasterizer.state.enables; if (enables & GGL_ENABLE_SMOOTH) clipper |= 1; // we need to interpolate colors if (enables & GGL_ENABLE_TMUS) clipper |= 2; // we need to interpolate textures switch (clipper) { case 0: c->arrays.clipVertex = clipVertex; break; case 1: c->arrays.clipVertex = clipVertexC; break; case 2: c->arrays.clipVertex = clipVertexT; break; case 3: c->arrays.clipVertex = clipVertexAll; break; } c->arrays.clipEye = clipEye; // pick the primitive rasterizer ogles_validate_primitives(c); } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- using namespace android; #if 0 #pragma mark - #pragma mark array API #endif void glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { ogles_context_t* c = ogles_context_t::get(); if (size<2 || size>4 || stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (type) { case GL_BYTE: case GL_SHORT: case GL_FIXED: case GL_FLOAT: break; default: ogles_error(c, GL_INVALID_ENUM); return; } c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0); } void glColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { ogles_context_t* c = ogles_context_t::get(); if (size!=4 || stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (type) { case GL_UNSIGNED_BYTE: case GL_FIXED: case GL_FLOAT: break; default: ogles_error(c, GL_INVALID_ENUM); return; } c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0); } void glNormalPointer( GLenum type, GLsizei stride, const GLvoid *pointer) { ogles_context_t* c = ogles_context_t::get(); if (stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (type) { case GL_BYTE: case GL_SHORT: case GL_FIXED: case GL_FLOAT: break; default: ogles_error(c, GL_INVALID_ENUM); return; } c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0); } void glTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { ogles_context_t* c = ogles_context_t::get(); if (size<2 || size>4 || stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (type) { case GL_BYTE: case GL_SHORT: case GL_FIXED: case GL_FLOAT: break; default: ogles_error(c, GL_INVALID_ENUM); return; } const int tmu = c->arrays.activeTexture; c->arrays.texture[tmu].init(size, type, stride, pointer, c->arrays.array_buffer, 0); } void glEnableClientState(GLenum array) { ogles_context_t* c = ogles_context_t::get(); enableDisableClientState(c, array, true); } void glDisableClientState(GLenum array) { ogles_context_t* c = ogles_context_t::get(); enableDisableClientState(c, array, false); } void glClientActiveTexture(GLenum texture) { ogles_context_t* c = ogles_context_t::get(); if (texture=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) { ogles_error(c, GL_INVALID_ENUM); return; } c->arrays.activeTexture = texture - GL_TEXTURE0; } void glDrawArrays(GLenum mode, GLint first, GLsizei count) { ogles_context_t* c = ogles_context_t::get(); if (count<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (mode) { case GL_POINTS: case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_LINES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_TRIANGLES: break; default: ogles_error(c, GL_INVALID_ENUM); return; } if (count == 0 || !c->arrays.vertex.enable) return; if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) return; // all triangles are culled validate_arrays(c, mode); const uint32_t enables = c->rasterizer.state.enables; if (enables & GGL_ENABLE_TMUS) ogles_lock_textures(c); drawArraysPrims[mode](c, first, count); if (enables & GGL_ENABLE_TMUS) ogles_unlock_textures(c); #if VC_CACHE_STATISTICS c->vc.total = count; c->vc.dump_stats(mode); #endif } void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { ogles_context_t* c = ogles_context_t::get(); if (count<0) { ogles_error(c, GL_INVALID_VALUE); return; } switch (mode) { case GL_POINTS: case GL_LINE_STRIP: case GL_LINE_LOOP: case GL_LINES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_TRIANGLES: break; default: ogles_error(c, GL_INVALID_ENUM); return; } switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: c->arrays.indicesType = type; break; default: ogles_error(c, GL_INVALID_ENUM); return; } if (count == 0 || !c->arrays.vertex.enable) return; if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK)) return; // all triangles are culled // clear the vertex-cache c->vc.clear(); validate_arrays(c, mode); // if indices are in a buffer object, the pointer is treated as an // offset in that buffer. if (c->arrays.element_array_buffer) { indices = c->arrays.element_array_buffer->data + uintptr_t(indices); } const uint32_t enables = c->rasterizer.state.enables; if (enables & GGL_ENABLE_TMUS) ogles_lock_textures(c); drawElementsPrims[mode](c, count, indices); if (enables & GGL_ENABLE_TMUS) ogles_unlock_textures(c); #if VC_CACHE_STATISTICS c->vc.total = count; c->vc.dump_stats(mode); #endif } // ---------------------------------------------------------------------------- // buffers // ---------------------------------------------------------------------------- void glBindBuffer(GLenum target, GLuint buffer) { ogles_context_t* c = ogles_context_t::get(); if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { ogles_error(c, GL_INVALID_ENUM); return; } // create a buffer object, or bind an existing one buffer_t const* bo = 0; if (buffer) { bo = c->bufferObjectManager->bind(buffer); if (!bo) { ogles_error(c, GL_OUT_OF_MEMORY); return; } } ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer) = bo; } void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { ogles_context_t* c = ogles_context_t::get(); if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { ogles_error(c, GL_INVALID_ENUM); return; } if (size<0) { ogles_error(c, GL_INVALID_VALUE); return; } if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) { ogles_error(c, GL_INVALID_ENUM); return; } buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer); if (bo == 0) { // can't modify buffer 0 ogles_error(c, GL_INVALID_OPERATION); return; } buffer_t* edit_bo = const_cast(bo); if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) { ogles_error(c, GL_OUT_OF_MEMORY); return; } if (data) { memcpy(bo->data, data, size); } } void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { ogles_context_t* c = ogles_context_t::get(); if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) { ogles_error(c, GL_INVALID_ENUM); return; } if (offset<0 || size<0 || data==0) { ogles_error(c, GL_INVALID_VALUE); return; } buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? c->arrays.array_buffer : c->arrays.element_array_buffer); if (bo == 0) { // can't modify buffer 0 ogles_error(c, GL_INVALID_OPERATION); return; } if (offset+size > bo->size) { ogles_error(c, GL_INVALID_VALUE); return; } memcpy(bo->data + offset, data, size); } void glDeleteBuffers(GLsizei n, const GLuint* buffers) { ogles_context_t* c = ogles_context_t::get(); if (n<0) { ogles_error(c, GL_INVALID_VALUE); return; } for (int i=0 ; iarrays.element_array_buffer) { if (c->arrays.element_array_buffer->name == name) { c->arrays.element_array_buffer = 0; } } if (c->arrays.array_buffer) { if (c->arrays.array_buffer->name == name) { c->arrays.array_buffer = 0; } } if (c->arrays.vertex.bo) { if (c->arrays.vertex.bo->name == name) { c->arrays.vertex.bo = 0; } } if (c->arrays.normal.bo) { if (c->arrays.normal.bo->name == name) { c->arrays.normal.bo = 0; } } if (c->arrays.color.bo) { if (c->arrays.color.bo->name == name) { c->arrays.color.bo = 0; } } for (int t=0 ; tarrays.texture[t].bo) { if (c->arrays.texture[t].bo->name == name) { c->arrays.texture[t].bo = 0; } } } } } c->bufferObjectManager->deleteBuffers(n, buffers); c->bufferObjectManager->recycleTokens(n, buffers); } void glGenBuffers(GLsizei n, GLuint* buffers) { ogles_context_t* c = ogles_context_t::get(); if (n<0) { ogles_error(c, GL_INVALID_VALUE); return; } c->bufferObjectManager->getToken(n, buffers); } opengl/libagl/array.h0100644 0000000 0000000 00000001742 13077405420 013620 0ustar000000000 0000000 /* libs/opengles/array.h ** ** Copyright 2006, 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_OPENGLES_ARRAY_H #define ANDROID_OPENGLES_ARRAY_H #include #include #include namespace android { namespace gl { struct ogles_context_t; }; void ogles_init_array(ogles_context_t* c); void ogles_uninit_array(ogles_context_t* c); }; // namespace android #endif // ANDROID_OPENGLES_ARRAY_H opengl/libagl/context.h0100644 0000000 0000000 00000042255 13077405420 014172 0ustar000000000 0000000 /* * Copyright (C) 2006 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_OPENGLES_CONTEXT_H #define ANDROID_OPENGLES_CONTEXT_H #include #include #include #include #ifdef __ANDROID__ #include #endif #include #include #include #include namespace android { const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10 #ifdef GL_OES_compressed_ETC1_RGB8_texture + 1 #endif ; class EGLTextureObject; class EGLSurfaceManager; class EGLBufferObjectManager; namespace gl { struct ogles_context_t; struct matrixx_t; struct transform_t; struct buffer_t; ogles_context_t* getGlContext(); template static inline void swap(T& a, T& b) { T t(a); a = b; b = t; } template inline T max(T a, T b) { return a inline T max(T a, T b, T c) { return max(a, max(b, c)); } template inline T min(T a, T b) { return a inline T min(T a, T b, T c) { return min(a, min(b, c)); } template inline T min(T a, T b, T c, T d) { return min(min(a,b), min(c,d)); } // ---------------------------------------------------------------------------- // vertices // ---------------------------------------------------------------------------- struct vec3_t { union { struct { GLfixed x, y, z; }; struct { GLfixed r, g, b; }; struct { GLfixed S, T, R; }; GLfixed v[3]; }; }; struct vec4_t { union { struct { GLfixed x, y, z, w; }; struct { GLfixed r, g, b, a; }; struct { GLfixed S, T, R, Q; }; GLfixed v[4]; }; }; struct vertex_t { enum { // these constant matter for our clipping CLIP_L = 0x0001, // clipping flags CLIP_R = 0x0002, CLIP_B = 0x0004, CLIP_T = 0x0008, CLIP_N = 0x0010, CLIP_F = 0x0020, EYE = 0x0040, RESERVED = 0x0080, USER_CLIP_0 = 0x0100, // user clipping flags USER_CLIP_1 = 0x0200, USER_CLIP_2 = 0x0400, USER_CLIP_3 = 0x0800, USER_CLIP_4 = 0x1000, USER_CLIP_5 = 0x2000, LIT = 0x4000, // lighting has been applied TT = 0x8000, // texture coords transformed FRUSTUM_CLIP_ALL= 0x003F, USER_CLIP_ALL = 0x3F00, CLIP_ALL = 0x3F3F, }; // the fields below are arranged to minimize d-cache usage // we group together, by cache-line, the fields most likely to be used union { vec4_t obj; vec4_t eye; }; vec4_t clip; uint32_t flags; size_t index; // cache tag, and vertex index GLfixed fog; uint8_t locked; uint8_t mru; uint8_t reserved[2]; vec4_t window; vec4_t color; vec4_t texture[GGL_TEXTURE_UNIT_COUNT]; #ifdef __LP64__ uint32_t reserved1[2]; #else uint32_t reserved1[4]; #endif inline void clear() { flags = index = locked = mru = 0; } }; struct point_size_t { GGLcoord size; GLboolean smooth; }; struct line_width_t { GGLcoord width; GLboolean smooth; }; struct polygon_offset_t { GLfixed factor; GLfixed units; GLboolean enable; }; // ---------------------------------------------------------------------------- // arrays // ---------------------------------------------------------------------------- struct array_t { typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*); fetcher_t fetch; GLvoid const* physical_pointer; GLint size; GLsizei stride; GLvoid const* pointer; buffer_t const* bo; uint16_t type; GLboolean enable; GLboolean pad; GLsizei bounds; void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei); inline void resolve(); inline const GLubyte* element(GLint i) const { return (const GLubyte*)physical_pointer + i * stride; } }; struct array_machine_t { array_t vertex; array_t normal; array_t color; array_t texture[GGL_TEXTURE_UNIT_COUNT]; uint8_t activeTexture; uint8_t tmu; uint16_t cull; uint32_t flags; GLenum indicesType; buffer_t const* array_buffer; buffer_t const* element_array_buffer; void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei); void (*compileElement)(ogles_context_t*, vertex_t*, GLint); void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*); void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*); void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*); void (*perspective)(ogles_context_t*c, vertex_t* v); void (*clipVertex)(ogles_context_t* c, vertex_t* nv, GGLfixed t, const vertex_t* s, const vertex_t* p); void (*clipEye)(ogles_context_t* c, vertex_t* nv, GGLfixed t, const vertex_t* s, const vertex_t* p); }; struct vertex_cache_t { enum { // must be at least 4 // 3 vertice for triangles // or 2 + 2 for indexed triangles w/ cache contention VERTEX_BUFFER_SIZE = 8, // must be a power of two and at least 3 VERTEX_CACHE_SIZE = 64, // 8 KB INDEX_BITS = 16, INDEX_MASK = ((1LU<(__get_tls()[TLS_SLOT_OPENGL]); } #else extern pthread_key_t gGLKey; inline void setGlThreadSpecific(ogles_context_t *value) { pthread_setspecific(gGLKey, value); } inline ogles_context_t* getGlThreadSpecific() { return static_cast(pthread_getspecific(gGLKey)); } #endif struct prims_t { typedef ogles_context_t* GL; void (*renderPoint)(GL, vertex_t*); void (*renderLine)(GL, vertex_t*, vertex_t*); void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*); }; struct ogles_context_t { context_t rasterizer; array_machine_t arrays __attribute__((aligned(32))); texture_state_t textures; transform_state_t transforms; vertex_cache_t vc; prims_t prims; culling_t cull; lighting_t lighting; user_clip_planes_t clipPlanes; compute_iterators_t lerp; __attribute__((aligned(32))); vertex_t current; vec4_t currentColorClamped; vec3_t currentNormal; viewport_t viewport; point_size_t point; line_width_t line; polygon_offset_t polygonOffset; fog_t fog; uint32_t perspective : 1; uint32_t transformTextures : 1; EGLSurfaceManager* surfaceManager; EGLBufferObjectManager* bufferObjectManager; GLenum error; static inline ogles_context_t* get() { return getGlThreadSpecific(); } }; }; // namespace gl }; // namespace android using namespace android::gl; #endif // ANDROID_OPENGLES_CONTEXT_H opengl/libagl/dxt.cpp0100644 0000000 0000000 00000047672 13077405420 013650 0ustar000000000 0000000 /* libs/opengles/dxt.cpp ** ** Copyright 2007, 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. */ #define TIMING 0 #if TIMING #include // for optimization timing #include #include #endif #include #include #include "context.h" #define TIMING 0 namespace android { static uint8_t avg23tab[64*64]; static volatile int tables_initialized = 0; // Definitions below are equivalent to these over the valid range of arguments // #define div5(x) ((x)/5) // #define div7(x) ((x)/7) // Use fixed-point to divide by 5 and 7 // 3277 = 2^14/5 + 1 // 2341 = 2^14/7 + 1 #define div5(x) (((x)*3277) >> 14) #define div7(x) (((x)*2341) >> 14) // Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64 #define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)] // Extract 5/6/5 RGB #define red(x) (((x) >> 11) & 0x1f) #define green(x) (((x) >> 5) & 0x3f) #define blue(x) ( (x) & 0x1f) /* * Convert 5/6/5 RGB (as 3 ints) to 8/8/8 * * Operation count: 8 <<, 0 &, 5 | */ inline static int rgb565SepTo888(int r, int g, int b) { return ((((r << 3) | (r >> 2)) << 16) | (((g << 2) | (g >> 4)) << 8) | ((b << 3) | (b >> 2))); } /* * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8 * * r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0 rgb * r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0 rgb << 3 * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2 desired result * * Construct the 24-bit RGB word as: * * r4r3r2r1 r0------ -------- -------- -------- -------- (rgb << 8) & 0xf80000 * r4r3r2 -------- -------- -------- -------- (rgb << 3) & 0x070000 * g5g4g3g2 g1g0---- -------- -------- (rgb << 5) & 0x00fc00 * g5g4 -------- -------- (rgb >> 1) & 0x000300 * b4b3b2b1 b0------ (rgb << 3) & 0x0000f8 * b4b3b2 (rgb >> 2) & 0x000007 * * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice) */ inline static int rgb565To888(int rgb) { int rgb3 = rgb >> 3; return (((rgb << 8) & 0xf80000) | ( rgb3 & 0x070000) | ((rgb << 5) & 0x00fc00) | ((rgb >> 1) & 0x000300) | ( rgb3 & 0x0000f8) | ((rgb >> 2) & 0x000007)); } #if __BYTE_ORDER == __BIG_ENDIAN static uint32_t swap(uint32_t x) { int b0 = (x >> 24) & 0xff; int b1 = (x >> 16) & 0xff; int b2 = (x >> 8) & 0xff; int b3 = (x ) & 0xff; return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0); } #endif static void init_tables() { if (tables_initialized) { return; } for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { int avg = (2*i + j)/3; avg23tab[(i << 6) | j] = avg; } } asm volatile ("" : : : "memory"); tables_initialized = 1; } /* * Utility to scan a DXT1 compressed texture to determine whether it * contains a transparent pixel (color0 < color1, code == 3). This * may be useful if the application lacks information as to whether * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT. */ bool DXT1HasAlpha(const GLvoid *data, int width, int height) { #if TIMING struct timeval start_t, end_t; struct timezone tz; gettimeofday(&start_t, &tz); #endif bool hasAlpha = false; int xblocks = (width + 3)/4; int yblocks = (height + 3)/4; int numblocks = xblocks*yblocks; uint32_t const *d32 = (uint32_t *)data; for (int b = 0; b < numblocks; b++) { uint32_t colors = *d32++; #if __BYTE_ORDER == __BIG_ENDIAN colors = swap(colors); #endif uint16_t color0 = colors & 0xffff; uint16_t color1 = colors >> 16; if (color0 < color1) { // There's no need to endian-swap within 'bits' // since we don't care which pixel is the transparent one uint32_t bits = *d32++; // Detect if any (odd, even) pair of bits are '11' // bits: b31 b30 b29 ... b3 b2 b1 b0 // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1 // &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0) // & 0x55..: 0 (b31 & b30) 0 ... 0 (b1 & b0) if (((bits & (bits >> 1)) & 0x55555555) != 0) { hasAlpha = true; goto done; } } else { // Skip 4 bytes ++d32; } } done: #if TIMING gettimeofday(&end_t, &tz); long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + (end_t.tv_usec - start_t.tv_usec); printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec); #endif return hasAlpha; } static void decodeDXT1(const GLvoid *data, int width, int height, void *surface, int stride, bool hasAlpha) { init_tables(); uint32_t const *d32 = (uint32_t *)data; // Color table for the current block uint16_t c[4]; c[0] = c[1] = c[2] = c[3] = 0; // Specified colors from the previous block uint16_t prev_color0 = 0x0000; uint16_t prev_color1 = 0x0000; uint16_t* rowPtr = (uint16_t*)surface; for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { uint16_t *blockPtr = rowPtr; for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { uint32_t colors = *d32++; uint32_t bits = *d32++; #if __BYTE_ORDER == __BIG_ENDIAN colors = swap(colors); bits = swap(bits); #endif // Raw colors uint16_t color0 = colors & 0xffff; uint16_t color1 = colors >> 16; // If the new block has the same base colors as the // previous one, we don't need to recompute the color // table c[] if (color0 != prev_color0 || color1 != prev_color1) { // Store raw colors for comparison with next block prev_color0 = color0; prev_color1 = color1; int r0 = red(color0); int g0 = green(color0); int b0 = blue(color0); int r1 = red(color1); int g1 = green(color1); int b1 = blue(color1); if (hasAlpha) { c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1; c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1; } else { c[0] = color0; c[1] = color1; } int r2, g2, b2, r3, g3, b3, a3; int bbits = bits >> 1; bool has2 = ((bbits & ~bits) & 0x55555555) != 0; bool has3 = ((bbits & bits) & 0x55555555) != 0; if (has2 || has3) { if (color0 > color1) { r2 = avg23(r0, r1); g2 = avg23(g0, g1); b2 = avg23(b0, b1); r3 = avg23(r1, r0); g3 = avg23(g1, g0); b3 = avg23(b1, b0); a3 = 1; } else { r2 = (r0 + r1) >> 1; g2 = (g0 + g1) >> 1; b2 = (b0 + b1) >> 1; r3 = g3 = b3 = a3 = 0; } if (hasAlpha) { c[2] = (r2 << 11) | ((g2 >> 1) << 6) | (b2 << 1) | 0x1; c[3] = (r3 << 11) | ((g3 >> 1) << 6) | (b3 << 1) | a3; } else { c[2] = (r2 << 11) | (g2 << 5) | b2; c[3] = (r3 << 11) | (g3 << 5) | b3; } } } uint16_t* blockRowPtr = blockPtr; for (int y = 0; y < 4; y++, blockRowPtr += stride) { // Don't process rows past the botom if (base_y + y >= height) { break; } int w = min(width - base_x, 4); for (int x = 0; x < w; x++) { int code = bits & 0x3; bits >>= 2; blockRowPtr[x] = c[code]; } } } } } // Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE static void decodeDXT3(const GLvoid *data, int width, int height, void *surface, int stride) { init_tables(); uint32_t const *d32 = (uint32_t *)data; // Specified colors from the previous block uint16_t prev_color0 = 0x0000; uint16_t prev_color1 = 0x0000; // Color table for the current block uint32_t c[4]; c[0] = c[1] = c[2] = c[3] = 0; uint32_t* rowPtr = (uint32_t*)surface; for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { uint32_t *blockPtr = rowPtr; for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { #if __BYTE_ORDER == __BIG_ENDIAN uint32_t alphahi = *d32++; uint32_t alphalo = *d32++; alphahi = swap(alphahi); alphalo = swap(alphalo); #else uint32_t alphalo = *d32++; uint32_t alphahi = *d32++; #endif uint32_t colors = *d32++; uint32_t bits = *d32++; #if __BYTE_ORDER == __BIG_ENDIAN colors = swap(colors); bits = swap(bits); #endif uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; // Raw colors uint16_t color0 = colors & 0xffff; uint16_t color1 = colors >> 16; // If the new block has the same base colors as the // previous one, we don't need to recompute the color // table c[] if (color0 != prev_color0 || color1 != prev_color1) { // Store raw colors for comparison with next block prev_color0 = color0; prev_color1 = color1; int bbits = bits >> 1; bool has2 = ((bbits & ~bits) & 0x55555555) != 0; bool has3 = ((bbits & bits) & 0x55555555) != 0; if (has2 || has3) { int r0 = red(color0); int g0 = green(color0); int b0 = blue(color0); int r1 = red(color1); int g1 = green(color1); int b1 = blue(color1); int r2 = avg23(r0, r1); int g2 = avg23(g0, g1); int b2 = avg23(b0, b1); int r3 = avg23(r1, r0); int g3 = avg23(g1, g0); int b3 = avg23(b1, b0); c[0] = rgb565SepTo888(r0, g0, b0); c[1] = rgb565SepTo888(r1, g1, b1); c[2] = rgb565SepTo888(r2, g2, b2); c[3] = rgb565SepTo888(r3, g3, b3); } else { // Convert to 8 bits c[0] = rgb565To888(color0); c[1] = rgb565To888(color1); } } uint32_t* blockRowPtr = blockPtr; for (int y = 0; y < 4; y++, blockRowPtr += stride) { // Don't process rows past the botom if (base_y + y >= height) { break; } int w = min(width - base_x, 4); for (int x = 0; x < w; x++) { int a = alpha & 0xf; alpha >>= 4; int code = bits & 0x3; bits >>= 2; blockRowPtr[x] = c[code] | (a << 28) | (a << 24); } } } } } // Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE static void decodeDXT5(const GLvoid *data, int width, int height, void *surface, int stride) { init_tables(); uint32_t const *d32 = (uint32_t *)data; // Specified alphas from the previous block uint8_t prev_alpha0 = 0x00; uint8_t prev_alpha1 = 0x00; // Specified colors from the previous block uint16_t prev_color0 = 0x0000; uint16_t prev_color1 = 0x0000; // Alpha table for the current block uint8_t a[8]; a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0; // Color table for the current block uint32_t c[4]; c[0] = c[1] = c[2] = c[3] = 0; int good_a5 = 0; int bad_a5 = 0; int good_a6 = 0; int bad_a6 = 0; int good_a7 = 0; int bad_a7 = 0; uint32_t* rowPtr = (uint32_t*)surface; for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { uint32_t *blockPtr = rowPtr; for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { #if __BYTE_ORDER == __BIG_ENDIAN uint32_t alphahi = *d32++; uint32_t alphalo = *d32++; alphahi = swap(alphahi); alphalo = swap(alphalo); #else uint32_t alphalo = *d32++; uint32_t alphahi = *d32++; #endif uint32_t colors = *d32++; uint32_t bits = *d32++; #if __BYTE_ORDER == __BIG_ENDIANx colors = swap(colors); bits = swap(bits); #endif uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; uint64_t alpha0 = alpha & 0xff; alpha >>= 8; uint64_t alpha1 = alpha & 0xff; alpha >>= 8; if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) { prev_alpha0 = alpha0; prev_alpha1 = alpha1; a[0] = alpha0; a[1] = alpha1; int a01 = alpha0 + alpha1 - 1; if (alpha0 > alpha1) { a[2] = div7(6*alpha0 + alpha1); a[4] = div7(4*alpha0 + 3*alpha1); a[6] = div7(2*alpha0 + 5*alpha1); // Use symmetry to derive half of the values // A few values will be off by 1 (~.5%) // Alternate which values are computed directly // and which are derived to try to reduce bias a[3] = a01 - a[6]; a[5] = a01 - a[4]; a[7] = a01 - a[2]; } else { a[2] = div5(4*alpha0 + alpha1); a[4] = div5(2*alpha0 + 3*alpha1); a[3] = a01 - a[4]; a[5] = a01 - a[2]; a[6] = 0x00; a[7] = 0xff; } } // Raw colors uint16_t color0 = colors & 0xffff; uint16_t color1 = colors >> 16; // If the new block has the same base colors as the // previous one, we don't need to recompute the color // table c[] if (color0 != prev_color0 || color1 != prev_color1) { // Store raw colors for comparison with next block prev_color0 = color0; prev_color1 = color1; int bbits = bits >> 1; bool has2 = ((bbits & ~bits) & 0x55555555) != 0; bool has3 = ((bbits & bits) & 0x55555555) != 0; if (has2 || has3) { int r0 = red(color0); int g0 = green(color0); int b0 = blue(color0); int r1 = red(color1); int g1 = green(color1); int b1 = blue(color1); int r2 = avg23(r0, r1); int g2 = avg23(g0, g1); int b2 = avg23(b0, b1); int r3 = avg23(r1, r0); int g3 = avg23(g1, g0); int b3 = avg23(b1, b0); c[0] = rgb565SepTo888(r0, g0, b0); c[1] = rgb565SepTo888(r1, g1, b1); c[2] = rgb565SepTo888(r2, g2, b2); c[3] = rgb565SepTo888(r3, g3, b3); } else { // Convert to 8 bits c[0] = rgb565To888(color0); c[1] = rgb565To888(color1); } } uint32_t* blockRowPtr = blockPtr; for (int y = 0; y < 4; y++, blockRowPtr += stride) { // Don't process rows past the botom if (base_y + y >= height) { break; } int w = min(width - base_x, 4); for (int x = 0; x < w; x++) { int acode = alpha & 0x7; alpha >>= 3; int code = bits & 0x3; bits >>= 2; blockRowPtr[x] = c[code] | (a[acode] << 24); } } } } } /* * Decode a DXT-compressed texture into memory. DXT textures consist of * a series of 4x4 pixel blocks in left-to-right, top-down order. * The number of blocks is given by ceil(width/4)*ceil(height/4). * * 'data' points to the texture data. 'width' and 'height' indicate the * dimensions of the texture. We assume width and height are >= 0 but * do not require them to be powers of 2 or divisible by any factor. * * The output is written to 'surface' with each scanline separated by * 'stride' 2- or 4-byte words. * * 'format' indicates the type of compression and must be one of the following: * * GL_COMPRESSED_RGB_S3TC_DXT1_EXT: * The output is written as 5/6/5 opaque RGB (16 bit words). * 8 bytes are read from 'data' for each block. * * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT * The output is written as 5/5/5/1 RGBA (16 bit words) * 8 bytes are read from 'data' for each block. * * GL_COMPRESSED_RGBA_S3TC_DXT3_EXT * GL_COMPRESSED_RGBA_S3TC_DXT5_EXT * The output is written as 8/8/8/8 ARGB (32 bit words) * 16 bytes are read from 'data' for each block. */ void decodeDXT(const GLvoid *data, int width, int height, void *surface, int stride, int format) { #if TIMING struct timeval start_t, end_t; struct timezone tz; gettimeofday(&start_t, &tz); #endif switch (format) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: decodeDXT1(data, width, height, surface, stride, false); break; case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: decodeDXT1(data, width, height, surface, stride, true); break; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: decodeDXT3(data, width, height, surface, stride); break; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: decodeDXT5(data, width, height, surface, stride); break; } #if TIMING gettimeofday(&end_t, &tz); long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + (end_t.tv_usec - start_t.tv_usec); printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec); #endif } } // namespace android opengl/libagl/dxt.h0100644 0000000 0000000 00000002001 13077405420 013266 0ustar000000000 0000000 /* libs/opengles/dxt.h ** ** Copyright 2007, 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_OPENGLES_TEXTURE_H #define ANDROID_OPENGLES_TEXTURE_H #include #include namespace android { bool DXT1HasAlpha(const GLvoid *data, int width, int height); void decodeDXT(const GLvoid *data, int width, int height, void *surface, int stride, int format); } // namespace android #endif // ANDROID_OPENGLES_TEXTURE_H opengl/libagl/egl.cpp0100644 0000000 0000000 00000223132 13077405420 013603 0ustar000000000 0000000 /* ** ** Copyright 2007 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "context.h" #include "state.h" #include "texture.h" #include "matrix.h" #undef NELEM #define NELEM(x) (sizeof(x)/sizeof(*(x))) // ---------------------------------------------------------------------------- EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- const unsigned int NUM_DISPLAYS = 1; static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t gEGLErrorKey = -1; #ifndef __ANDROID__ namespace gl { pthread_key_t gGLKey = -1; }; // namespace gl #endif template static T setError(GLint error, T returnValue) { if (ggl_unlikely(gEGLErrorKey == -1)) { pthread_mutex_lock(&gErrorKeyMutex); if (gEGLErrorKey == -1) pthread_key_create(&gEGLErrorKey, NULL); pthread_mutex_unlock(&gErrorKeyMutex); } pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)error); return returnValue; } static GLint getError() { if (ggl_unlikely(gEGLErrorKey == -1)) return EGL_SUCCESS; GLint error = (GLint)(uintptr_t)pthread_getspecific(gEGLErrorKey); if (error == 0) { // The TLS key has been created by another thread, but the value for // this thread has not been initialized. return EGL_SUCCESS; } pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)EGL_SUCCESS); return error; } // ---------------------------------------------------------------------------- struct egl_display_t { egl_display_t() : type(0), initialized(0) { } static egl_display_t& get_display(EGLDisplay dpy); static EGLBoolean is_valid(EGLDisplay dpy) { return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE; } NativeDisplayType type; std::atomic_size_t initialized; }; static egl_display_t gDisplays[NUM_DISPLAYS]; egl_display_t& egl_display_t::get_display(EGLDisplay dpy) { return gDisplays[uintptr_t(dpy)-1U]; } struct egl_context_t { enum { IS_CURRENT = 0x00010000, NEVER_CURRENT = 0x00020000 }; uint32_t flags; EGLDisplay dpy; EGLConfig config; EGLSurface read; EGLSurface draw; static inline egl_context_t* context(EGLContext ctx) { ogles_context_t* const gl = static_cast(ctx); return static_cast(gl->rasterizer.base); } }; // ---------------------------------------------------------------------------- struct egl_surface_t { enum { PAGE_FLIP = 0x00000001, MAGIC = 0x31415265 }; uint32_t magic; EGLDisplay dpy; EGLConfig config; EGLContext ctx; bool zombie; egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat); virtual ~egl_surface_t(); bool isValid() const; virtual bool initCheck() const = 0; virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0; virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0; virtual EGLBoolean connect() { return EGL_TRUE; } virtual void disconnect() {} virtual EGLint getWidth() const = 0; virtual EGLint getHeight() const = 0; virtual EGLint getHorizontalResolution() const; virtual EGLint getVerticalResolution() const; virtual EGLint getRefreshRate() const; virtual EGLint getSwapBehavior() const; virtual EGLBoolean swapBuffers(); virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); protected: GGLSurface depth; }; egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat) : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false) { depth.version = sizeof(GGLSurface); depth.data = 0; depth.format = depthFormat; } egl_surface_t::~egl_surface_t() { magic = 0; free(depth.data); } bool egl_surface_t::isValid() const { ALOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this); return magic == MAGIC; } EGLBoolean egl_surface_t::swapBuffers() { return EGL_FALSE; } EGLint egl_surface_t::getHorizontalResolution() const { return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); } EGLint egl_surface_t::getVerticalResolution() const { return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); } EGLint egl_surface_t::getRefreshRate() const { return (60 * EGL_DISPLAY_SCALING); } EGLint egl_surface_t::getSwapBehavior() const { return EGL_BUFFER_PRESERVED; } EGLBoolean egl_surface_t::setSwapRectangle( EGLint /*l*/, EGLint /*t*/, EGLint /*w*/, EGLint /*h*/) { return EGL_FALSE; } // ---------------------------------------------------------------------------- struct egl_window_surface_v2_t : public egl_surface_t { egl_window_surface_v2_t( EGLDisplay dpy, EGLConfig config, int32_t depthFormat, ANativeWindow* window); ~egl_window_surface_v2_t(); virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails virtual EGLBoolean swapBuffers(); virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); virtual EGLBoolean bindReadSurface(ogles_context_t* gl); virtual EGLBoolean connect(); virtual void disconnect(); virtual EGLint getWidth() const { return width; } virtual EGLint getHeight() const { return height; } virtual EGLint getHorizontalResolution() const; virtual EGLint getVerticalResolution() const; virtual EGLint getRefreshRate() const; virtual EGLint getSwapBehavior() const; virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); private: status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr); status_t unlock(ANativeWindowBuffer* buf); ANativeWindow* nativeWindow; ANativeWindowBuffer* buffer; ANativeWindowBuffer* previousBuffer; gralloc_module_t const* module; int width; int height; void* bits; GGLFormat const* pixelFormatTable; struct Rect { inline Rect() { }; inline Rect(int32_t w, int32_t h) : left(0), top(0), right(w), bottom(h) { } inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) : left(l), top(t), right(r), bottom(b) { } Rect& andSelf(const Rect& r) { left = max(left, r.left); top = max(top, r.top); right = min(right, r.right); bottom = min(bottom, r.bottom); return *this; } bool isEmpty() const { return (left>=right || top>=bottom); } void dump(char const* what) { ALOGD("%s { %5d, %5d, w=%5d, h=%5d }", what, left, top, right-left, bottom-top); } int32_t left; int32_t top; int32_t right; int32_t bottom; }; struct Region { inline Region() : count(0) { } typedef Rect const* const_iterator; const_iterator begin() const { return storage; } const_iterator end() const { return storage+count; } static Region subtract(const Rect& lhs, const Rect& rhs) { Region reg; Rect* storage = reg.storage; if (!lhs.isEmpty()) { if (lhs.top < rhs.top) { // top rect storage->left = lhs.left; storage->top = lhs.top; storage->right = lhs.right; storage->bottom = rhs.top; storage++; } const int32_t top = max(lhs.top, rhs.top); const int32_t bot = min(lhs.bottom, rhs.bottom); if (top < bot) { if (lhs.left < rhs.left) { // left-side rect storage->left = lhs.left; storage->top = top; storage->right = rhs.left; storage->bottom = bot; storage++; } if (lhs.right > rhs.right) { // right-side rect storage->left = rhs.right; storage->top = top; storage->right = lhs.right; storage->bottom = bot; storage++; } } if (lhs.bottom > rhs.bottom) { // bottom rect storage->left = lhs.left; storage->top = rhs.bottom; storage->right = lhs.right; storage->bottom = lhs.bottom; storage++; } reg.count = storage - reg.storage; } return reg; } bool isEmpty() const { return count<=0; } private: Rect storage[4]; ssize_t count; }; void copyBlt( ANativeWindowBuffer* dst, void* dst_vaddr, ANativeWindowBuffer* src, void const* src_vaddr, const Region& clip); Rect dirtyRegion; Rect oldDirtyRegion; }; egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat, ANativeWindow* window) : egl_surface_t(dpy, config, depthFormat), nativeWindow(window), buffer(0), previousBuffer(0), module(0), bits(NULL) { hw_module_t const* pModule; hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule); module = reinterpret_cast(pModule); pixelFormatTable = gglGetPixelFormatTable(); // keep a reference on the window nativeWindow->common.incRef(&nativeWindow->common); nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width); nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height); } egl_window_surface_v2_t::~egl_window_surface_v2_t() { if (buffer) { buffer->common.decRef(&buffer->common); } if (previousBuffer) { previousBuffer->common.decRef(&previousBuffer->common); } nativeWindow->common.decRef(&nativeWindow->common); } EGLBoolean egl_window_surface_v2_t::connect() { // we're intending to do software rendering native_window_set_usage(nativeWindow, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); // dequeue a buffer int fenceFd = -1; if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) != NO_ERROR) { return setError(EGL_BAD_ALLOC, EGL_FALSE); } // wait for the buffer sp fence(new Fence(fenceFd)); if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) { nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); return setError(EGL_BAD_ALLOC, EGL_FALSE); } // allocate a corresponding depth-buffer width = buffer->width; height = buffer->height; if (depth.format) { depth.width = width; depth.height = height; depth.stride = depth.width; // use the width here uint64_t allocSize = static_cast(depth.stride) * static_cast(depth.height) * 2; if (depth.stride < 0 || depth.height > INT_MAX || allocSize > UINT32_MAX) { return setError(EGL_BAD_ALLOC, EGL_FALSE); } depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { return setError(EGL_BAD_ALLOC, EGL_FALSE); } } // keep a reference on the buffer buffer->common.incRef(&buffer->common); // pin the buffer down if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { ALOGE("connect() failed to lock buffer %p (%ux%u)", buffer, buffer->width, buffer->height); return setError(EGL_BAD_ACCESS, EGL_FALSE); // FIXME: we should make sure we're not accessing the buffer anymore } return EGL_TRUE; } void egl_window_surface_v2_t::disconnect() { if (buffer && bits) { bits = NULL; unlock(buffer); } if (buffer) { nativeWindow->cancelBuffer(nativeWindow, buffer, -1); buffer->common.decRef(&buffer->common); buffer = 0; } if (previousBuffer) { previousBuffer->common.decRef(&previousBuffer->common); previousBuffer = 0; } } status_t egl_window_surface_v2_t::lock( ANativeWindowBuffer* buf, int usage, void** vaddr) { int err; err = module->lock(module, buf->handle, usage, 0, 0, buf->width, buf->height, vaddr); return err; } status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf) { if (!buf) return BAD_VALUE; int err = NO_ERROR; err = module->unlock(module, buf->handle); return err; } void egl_window_surface_v2_t::copyBlt( ANativeWindowBuffer* dst, void* dst_vaddr, ANativeWindowBuffer* src, void const* src_vaddr, const Region& clip) { // NOTE: dst and src must be the same format Region::const_iterator cur = clip.begin(); Region::const_iterator end = clip.end(); const size_t bpp = pixelFormatTable[src->format].size; const size_t dbpr = dst->stride * bpp; const size_t sbpr = src->stride * bpp; uint8_t const * const src_bits = (uint8_t const *)src_vaddr; uint8_t * const dst_bits = (uint8_t *)dst_vaddr; while (cur != end) { const Rect& r(*cur++); ssize_t w = r.right - r.left; ssize_t h = r.bottom - r.top; if (w <= 0 || h<=0) continue; size_t size = w * bpp; uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; if (dbpr==sbpr && size==sbpr) { size *= h; h = 1; } do { memcpy(d, s, size); d += dbpr; s += sbpr; } while (--h > 0); } } EGLBoolean egl_window_surface_v2_t::swapBuffers() { if (!buffer) { return setError(EGL_BAD_ACCESS, EGL_FALSE); } /* * Handle eglSetSwapRectangleANDROID() * We copyback from the front buffer */ if (!dirtyRegion.isEmpty()) { dirtyRegion.andSelf(Rect(buffer->width, buffer->height)); if (previousBuffer) { // This was const Region copyBack, but that causes an // internal compile error on simulator builds /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion)); if (!copyBack.isEmpty()) { void* prevBits; if (lock(previousBuffer, GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) { // copy from previousBuffer to buffer copyBlt(buffer, bits, previousBuffer, prevBits, copyBack); unlock(previousBuffer); } } } oldDirtyRegion = dirtyRegion; } if (previousBuffer) { previousBuffer->common.decRef(&previousBuffer->common); previousBuffer = 0; } unlock(buffer); previousBuffer = buffer; nativeWindow->queueBuffer(nativeWindow, buffer, -1); buffer = 0; // dequeue a new buffer int fenceFd = -1; if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) { sp fence(new Fence(fenceFd)); if (fence->wait(Fence::TIMEOUT_NEVER)) { nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); return setError(EGL_BAD_ALLOC, EGL_FALSE); } // reallocate the depth-buffer if needed if ((width != buffer->width) || (height != buffer->height)) { // TODO: we probably should reset the swap rect here // if the window size has changed width = buffer->width; height = buffer->height; if (depth.data) { free(depth.data); depth.width = width; depth.height = height; depth.stride = buffer->stride; uint64_t allocSize = static_cast(depth.stride) * static_cast(depth.height) * 2; if (depth.stride < 0 || depth.height > INT_MAX || allocSize > UINT32_MAX) { setError(EGL_BAD_ALLOC, EGL_FALSE); return EGL_FALSE; } depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_FALSE); return EGL_FALSE; } } } // keep a reference on the buffer buffer->common.incRef(&buffer->common); // finally pin the buffer down if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", buffer, buffer->width, buffer->height); return setError(EGL_BAD_ACCESS, EGL_FALSE); // FIXME: we should make sure we're not accessing the buffer anymore } } else { return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE); } return EGL_TRUE; } EGLBoolean egl_window_surface_v2_t::setSwapRectangle( EGLint l, EGLint t, EGLint w, EGLint h) { dirtyRegion = Rect(l, t, l+w, t+h); return EGL_TRUE; } EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl) { GGLSurface buffer; buffer.version = sizeof(GGLSurface); buffer.width = this->buffer->width; buffer.height = this->buffer->height; buffer.stride = this->buffer->stride; buffer.data = (GGLubyte*)bits; buffer.format = this->buffer->format; gl->rasterizer.procs.colorBuffer(gl, &buffer); if (depth.data != gl->rasterizer.state.buffers.depth.data) gl->rasterizer.procs.depthBuffer(gl, &depth); return EGL_TRUE; } EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl) { GGLSurface buffer; buffer.version = sizeof(GGLSurface); buffer.width = this->buffer->width; buffer.height = this->buffer->height; buffer.stride = this->buffer->stride; buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!! buffer.format = this->buffer->format; gl->rasterizer.procs.readBuffer(gl, &buffer); return EGL_TRUE; } EGLint egl_window_surface_v2_t::getHorizontalResolution() const { return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); } EGLint egl_window_surface_v2_t::getVerticalResolution() const { return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); } EGLint egl_window_surface_v2_t::getRefreshRate() const { return (60 * EGL_DISPLAY_SCALING); // FIXME } EGLint egl_window_surface_v2_t::getSwapBehavior() const { /* * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves * the content of the swapped buffer. * * EGL_BUFFER_DESTROYED means that the content of the buffer is lost. * * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED * only applies to the area specified by eglSetSwapRectangleANDROID(), that * is, everything outside of this area is preserved. * * This implementation of EGL assumes the later case. * */ return EGL_BUFFER_DESTROYED; } // ---------------------------------------------------------------------------- struct egl_pixmap_surface_t : public egl_surface_t { egl_pixmap_surface_t( EGLDisplay dpy, EGLConfig config, int32_t depthFormat, egl_native_pixmap_t const * pixmap); virtual ~egl_pixmap_surface_t() { } virtual bool initCheck() const { return !depth.format || depth.data!=0; } virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); virtual EGLBoolean bindReadSurface(ogles_context_t* gl); virtual EGLint getWidth() const { return nativePixmap.width; } virtual EGLint getHeight() const { return nativePixmap.height; } private: egl_native_pixmap_t nativePixmap; }; egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat, egl_native_pixmap_t const * pixmap) : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap) { if (depthFormat) { depth.width = pixmap->width; depth.height = pixmap->height; depth.stride = depth.width; // use the width here uint64_t allocSize = static_cast(depth.stride) * static_cast(depth.height) * 2; if (depth.stride < 0 || depth.height > INT_MAX || allocSize > UINT32_MAX) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); return; } depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } } } EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl) { GGLSurface buffer; buffer.version = sizeof(GGLSurface); buffer.width = nativePixmap.width; buffer.height = nativePixmap.height; buffer.stride = nativePixmap.stride; buffer.data = nativePixmap.data; buffer.format = nativePixmap.format; gl->rasterizer.procs.colorBuffer(gl, &buffer); if (depth.data != gl->rasterizer.state.buffers.depth.data) gl->rasterizer.procs.depthBuffer(gl, &depth); return EGL_TRUE; } EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl) { GGLSurface buffer; buffer.version = sizeof(GGLSurface); buffer.width = nativePixmap.width; buffer.height = nativePixmap.height; buffer.stride = nativePixmap.stride; buffer.data = nativePixmap.data; buffer.format = nativePixmap.format; gl->rasterizer.procs.readBuffer(gl, &buffer); return EGL_TRUE; } // ---------------------------------------------------------------------------- struct egl_pbuffer_surface_t : public egl_surface_t { egl_pbuffer_surface_t( EGLDisplay dpy, EGLConfig config, int32_t depthFormat, int32_t w, int32_t h, int32_t f); virtual ~egl_pbuffer_surface_t(); virtual bool initCheck() const { return pbuffer.data != 0; } virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); virtual EGLBoolean bindReadSurface(ogles_context_t* gl); virtual EGLint getWidth() const { return pbuffer.width; } virtual EGLint getHeight() const { return pbuffer.height; } private: GGLSurface pbuffer; }; egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat, int32_t w, int32_t h, int32_t f) : egl_surface_t(dpy, config, depthFormat) { size_t size = w*h; switch (f) { case GGL_PIXEL_FORMAT_A_8: size *= 1; break; case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break; case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break; case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break; default: ALOGE("incompatible pixel format for pbuffer (format=%d)", f); pbuffer.data = 0; break; } pbuffer.version = sizeof(GGLSurface); pbuffer.width = w; pbuffer.height = h; pbuffer.stride = w; pbuffer.data = (GGLubyte*)malloc(size); pbuffer.format = f; if (depthFormat) { depth.width = pbuffer.width; depth.height = pbuffer.height; depth.stride = depth.width; // use the width here uint64_t allocSize = static_cast(depth.stride) * static_cast(depth.height) * 2; if (depth.stride < 0 || depth.height > INT_MAX || allocSize > UINT32_MAX) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); return; } depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); return; } } } egl_pbuffer_surface_t::~egl_pbuffer_surface_t() { free(pbuffer.data); } EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl) { gl->rasterizer.procs.colorBuffer(gl, &pbuffer); if (depth.data != gl->rasterizer.state.buffers.depth.data) gl->rasterizer.procs.depthBuffer(gl, &depth); return EGL_TRUE; } EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl) { gl->rasterizer.procs.readBuffer(gl, &pbuffer); return EGL_TRUE; } // ---------------------------------------------------------------------------- struct config_pair_t { GLint key; GLint value; }; struct configs_t { const config_pair_t* array; int size; }; struct config_management_t { GLint key; bool (*match)(GLint reqValue, GLint confValue); static bool atLeast(GLint reqValue, GLint confValue) { return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue); } static bool exact(GLint reqValue, GLint confValue) { return (reqValue == EGL_DONT_CARE) || (confValue == reqValue); } static bool mask(GLint reqValue, GLint confValue) { return (confValue & reqValue) == reqValue; } static bool ignore(GLint /*reqValue*/, GLint /*confValue*/) { return true; } }; // ---------------------------------------------------------------------------- #define VERSION_MAJOR 1 #define VERSION_MINOR 2 static char const * const gVendorString = "Google Inc."; static char const * const gVersionString = "1.2 Android Driver 1.2.0"; static char const * const gClientApiString = "OpenGL_ES"; static char const * const gExtensionsString = "EGL_KHR_fence_sync " "EGL_KHR_image_base " // "KHR_image_pixmap " "EGL_ANDROID_image_native_buffer " "EGL_ANDROID_swap_rectangle " ; // ---------------------------------------------------------------------------- struct extention_map_t { const char * const name; __eglMustCastToProperFunctionPointerType address; }; static const extention_map_t gExtentionMap[] = { { "glDrawTexsOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES }, { "glDrawTexiOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES }, { "glDrawTexfOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES }, { "glDrawTexxOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES }, { "glDrawTexsvOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES }, { "glDrawTexivOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES }, { "glDrawTexfvOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES }, { "glDrawTexxvOES", (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES }, { "glQueryMatrixxOES", (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES }, { "glEGLImageTargetTexture2DOES", (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES }, { "glEGLImageTargetRenderbufferStorageOES", (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES }, { "glClipPlanef", (__eglMustCastToProperFunctionPointerType)&glClipPlanef }, { "glClipPlanex", (__eglMustCastToProperFunctionPointerType)&glClipPlanex }, { "glBindBuffer", (__eglMustCastToProperFunctionPointerType)&glBindBuffer }, { "glBufferData", (__eglMustCastToProperFunctionPointerType)&glBufferData }, { "glBufferSubData", (__eglMustCastToProperFunctionPointerType)&glBufferSubData }, { "glDeleteBuffers", (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers }, { "glGenBuffers", (__eglMustCastToProperFunctionPointerType)&glGenBuffers }, { "eglCreateImageKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, { "eglDestroyImageKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, { "eglCreateSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, { "eglDestroySyncKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, { "eglClientWaitSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, { "eglGetSyncAttribKHR", (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, { "eglSetSwapRectangleANDROID", (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, }; /* * In the lists below, attributes names MUST be sorted. * Additionally, all configs must be sorted according to * the EGL specification. */ static config_pair_t const config_base_attribute_list[] = { { EGL_STENCIL_SIZE, 0 }, { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG }, { EGL_LEVEL, 0 }, { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS }, { EGL_MAX_PBUFFER_PIXELS, GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS }, { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS }, { EGL_NATIVE_RENDERABLE, EGL_TRUE }, { EGL_NATIVE_VISUAL_ID, 0 }, { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 }, { EGL_SAMPLES, 0 }, { EGL_SAMPLE_BUFFERS, 0 }, { EGL_TRANSPARENT_TYPE, EGL_NONE }, { EGL_TRANSPARENT_BLUE_VALUE, 0 }, { EGL_TRANSPARENT_GREEN_VALUE, 0 }, { EGL_TRANSPARENT_RED_VALUE, 0 }, { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE }, { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE }, { EGL_MIN_SWAP_INTERVAL, 1 }, { EGL_MAX_SWAP_INTERVAL, 1 }, { EGL_LUMINANCE_SIZE, 0 }, { EGL_ALPHA_MASK_SIZE, 0 }, { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER }, { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT }, { EGL_CONFORMANT, 0 } }; // These configs can override the base attribute list // NOTE: when adding a config here, don't forget to update eglCreate*Surface() // 565 configs static config_pair_t const config_0_attribute_list[] = { { EGL_BUFFER_SIZE, 16 }, { EGL_ALPHA_SIZE, 0 }, { EGL_BLUE_SIZE, 5 }, { EGL_GREEN_SIZE, 6 }, { EGL_RED_SIZE, 5 }, { EGL_DEPTH_SIZE, 0 }, { EGL_CONFIG_ID, 0 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_1_attribute_list[] = { { EGL_BUFFER_SIZE, 16 }, { EGL_ALPHA_SIZE, 0 }, { EGL_BLUE_SIZE, 5 }, { EGL_GREEN_SIZE, 6 }, { EGL_RED_SIZE, 5 }, { EGL_DEPTH_SIZE, 16 }, { EGL_CONFIG_ID, 1 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; // RGB 888 configs static config_pair_t const config_2_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 0 }, { EGL_BLUE_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, { EGL_RED_SIZE, 8 }, { EGL_DEPTH_SIZE, 0 }, { EGL_CONFIG_ID, 6 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_3_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 0 }, { EGL_BLUE_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, { EGL_RED_SIZE, 8 }, { EGL_DEPTH_SIZE, 16 }, { EGL_CONFIG_ID, 7 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; // 8888 configs static config_pair_t const config_4_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, { EGL_RED_SIZE, 8 }, { EGL_DEPTH_SIZE, 0 }, { EGL_CONFIG_ID, 2 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_5_attribute_list[] = { { EGL_BUFFER_SIZE, 32 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, { EGL_RED_SIZE, 8 }, { EGL_DEPTH_SIZE, 16 }, { EGL_CONFIG_ID, 3 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; // A8 configs static config_pair_t const config_6_attribute_list[] = { { EGL_BUFFER_SIZE, 8 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 0 }, { EGL_GREEN_SIZE, 0 }, { EGL_RED_SIZE, 0 }, { EGL_DEPTH_SIZE, 0 }, { EGL_CONFIG_ID, 4 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_7_attribute_list[] = { { EGL_BUFFER_SIZE, 8 }, { EGL_ALPHA_SIZE, 8 }, { EGL_BLUE_SIZE, 0 }, { EGL_GREEN_SIZE, 0 }, { EGL_RED_SIZE, 0 }, { EGL_DEPTH_SIZE, 16 }, { EGL_CONFIG_ID, 5 }, { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static configs_t const gConfigs[] = { { config_0_attribute_list, NELEM(config_0_attribute_list) }, { config_1_attribute_list, NELEM(config_1_attribute_list) }, { config_2_attribute_list, NELEM(config_2_attribute_list) }, { config_3_attribute_list, NELEM(config_3_attribute_list) }, { config_4_attribute_list, NELEM(config_4_attribute_list) }, { config_5_attribute_list, NELEM(config_5_attribute_list) }, { config_6_attribute_list, NELEM(config_6_attribute_list) }, { config_7_attribute_list, NELEM(config_7_attribute_list) }, }; static config_management_t const gConfigManagement[] = { { EGL_BUFFER_SIZE, config_management_t::atLeast }, { EGL_ALPHA_SIZE, config_management_t::atLeast }, { EGL_BLUE_SIZE, config_management_t::atLeast }, { EGL_GREEN_SIZE, config_management_t::atLeast }, { EGL_RED_SIZE, config_management_t::atLeast }, { EGL_DEPTH_SIZE, config_management_t::atLeast }, { EGL_STENCIL_SIZE, config_management_t::atLeast }, { EGL_CONFIG_CAVEAT, config_management_t::exact }, { EGL_CONFIG_ID, config_management_t::exact }, { EGL_LEVEL, config_management_t::exact }, { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore }, { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore }, { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore }, { EGL_NATIVE_RENDERABLE, config_management_t::exact }, { EGL_NATIVE_VISUAL_ID, config_management_t::ignore }, { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact }, { EGL_SAMPLES, config_management_t::exact }, { EGL_SAMPLE_BUFFERS, config_management_t::exact }, { EGL_SURFACE_TYPE, config_management_t::mask }, { EGL_TRANSPARENT_TYPE, config_management_t::exact }, { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact }, { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact }, { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact }, { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact }, { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact }, { EGL_MIN_SWAP_INTERVAL, config_management_t::exact }, { EGL_MAX_SWAP_INTERVAL, config_management_t::exact }, { EGL_LUMINANCE_SIZE, config_management_t::atLeast }, { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast }, { EGL_COLOR_BUFFER_TYPE, config_management_t::exact }, { EGL_RENDERABLE_TYPE, config_management_t::mask }, { EGL_CONFORMANT, config_management_t::mask } }; static config_pair_t const config_defaults[] = { // attributes that are not specified are simply ignored, if a particular // one needs not be ignored, it must be specified here, eg: // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT }, }; // ---------------------------------------------------------------------------- static status_t getConfigFormatInfo(EGLint configID, int32_t& pixelFormat, int32_t& depthFormat) { switch(configID) { case 0: pixelFormat = GGL_PIXEL_FORMAT_RGB_565; depthFormat = 0; break; case 1: pixelFormat = GGL_PIXEL_FORMAT_RGB_565; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; case 2: pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888; depthFormat = 0; break; case 3: pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; case 4: pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; depthFormat = 0; break; case 5: pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; case 6: pixelFormat = GGL_PIXEL_FORMAT_A_8; depthFormat = 0; break; case 7: pixelFormat = GGL_PIXEL_FORMAT_A_8; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; default: return NAME_NOT_FOUND; } return NO_ERROR; } // ---------------------------------------------------------------------------- template static int binarySearch(T const sortedArray[], int first, int last, EGLint key) { while (first <= last) { int mid = (first + last) / 2; if (key > sortedArray[mid].key) { first = mid + 1; } else if (key < sortedArray[mid].key) { last = mid - 1; } else { return mid; } } return -1; } static int isAttributeMatching(int i, EGLint attr, EGLint val) { // look for the attribute in all of our configs config_pair_t const* configFound = gConfigs[i].array; int index = binarySearch( gConfigs[i].array, 0, gConfigs[i].size-1, attr); if (index < 0) { configFound = config_base_attribute_list; index = binarySearch( config_base_attribute_list, 0, NELEM(config_base_attribute_list)-1, attr); } if (index >= 0) { // attribute found, check if this config could match int cfgMgtIndex = binarySearch( gConfigManagement, 0, NELEM(gConfigManagement)-1, attr); if (cfgMgtIndex >= 0) { bool match = gConfigManagement[cfgMgtIndex].match( val, configFound[index].value); if (match) { // this config matches return 1; } } else { // attribute not found. this should NEVER happen. } } else { // error, this attribute doesn't exist } return 0; } static int makeCurrent(ogles_context_t* gl) { ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific(); if (gl) { egl_context_t* c = egl_context_t::context(gl); if (c->flags & egl_context_t::IS_CURRENT) { if (current != gl) { // it is an error to set a context current, if it's already // current to another thread return -1; } } else { if (current) { // mark the current context as not current, and flush glFlush(); egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; } } if (!(c->flags & egl_context_t::IS_CURRENT)) { // The context is not current, make it current! setGlThreadSpecific(gl); c->flags |= egl_context_t::IS_CURRENT; } } else { if (current) { // mark the current context as not current, and flush glFlush(); egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; } // this thread has no context attached to it setGlThreadSpecific(0); } return 0; } static EGLBoolean getConfigAttrib(EGLDisplay /*dpy*/, EGLConfig config, EGLint attribute, EGLint *value) { size_t numConfigs = NELEM(gConfigs); int index = (int)(uintptr_t)config; if (uint32_t(index) >= numConfigs) return setError(EGL_BAD_CONFIG, EGL_FALSE); int attrIndex; attrIndex = binarySearch( gConfigs[index].array, 0, gConfigs[index].size-1, attribute); if (attrIndex>=0) { *value = gConfigs[index].array[attrIndex].value; return EGL_TRUE; } attrIndex = binarySearch( config_base_attribute_list, 0, NELEM(config_base_attribute_list)-1, attribute); if (attrIndex>=0) { *value = config_base_attribute_list[attrIndex].value; return EGL_TRUE; } return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); } static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint* /*attrib_list*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); if (window == 0) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); EGLint surfaceType; if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; if (!(surfaceType & EGL_WINDOW_BIT)) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); if (static_cast(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } EGLint configID; if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) return EGL_FALSE; int32_t depthFormat; int32_t pixelFormat; if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } // FIXME: we don't have access to the pixelFormat here just yet. // (it's possible that the surface is not fully initialized) // maybe this should be done after the page-flip //if (EGLint(info.format) != pixelFormat) // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); egl_surface_t* surface; surface = new egl_window_surface_v2_t(dpy, config, depthFormat, static_cast(window)); if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; surface = 0; } return surface; } static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint* /*attrib_list*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); if (pixmap == 0) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); EGLint surfaceType; if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; if (!(surfaceType & EGL_PIXMAP_BIT)) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); if (static_cast(pixmap)->version != sizeof(egl_native_pixmap_t)) { return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); } EGLint configID; if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) return EGL_FALSE; int32_t depthFormat; int32_t pixelFormat; if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } if (pixmap->format != pixelFormat) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); egl_surface_t* surface = new egl_pixmap_surface_t(dpy, config, depthFormat, static_cast(pixmap)); if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; surface = 0; } return surface; } static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); EGLint surfaceType; if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) return EGL_FALSE; if (!(surfaceType & EGL_PBUFFER_BIT)) return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); EGLint configID; if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) return EGL_FALSE; int32_t depthFormat; int32_t pixelFormat; if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } int32_t w = 0; int32_t h = 0; while (attrib_list[0] != EGL_NONE) { if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1]; if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1]; attrib_list+=2; } egl_surface_t* surface = new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat); if (!surface->initCheck()) { // there was a problem in the ctor, the error // flag has been set. delete surface; surface = 0; } return surface; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- using namespace android; // ---------------------------------------------------------------------------- // Initialization // ---------------------------------------------------------------------------- EGLDisplay eglGetDisplay(NativeDisplayType display) { #ifndef __ANDROID__ // this just needs to be done once if (gGLKey == -1) { pthread_mutex_lock(&gInitMutex); if (gGLKey == -1) pthread_key_create(&gGLKey, NULL); pthread_mutex_unlock(&gInitMutex); } #endif if (display == EGL_DEFAULT_DISPLAY) { EGLDisplay dpy = (EGLDisplay)1; egl_display_t& d = egl_display_t::get_display(dpy); d.type = display; return dpy; } return EGL_NO_DISPLAY; } EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean res = EGL_TRUE; egl_display_t& d = egl_display_t::get_display(dpy); if (d.initialized.fetch_add(1, std::memory_order_acquire) == 0) { // initialize stuff here if needed //pthread_mutex_lock(&gInitMutex); //pthread_mutex_unlock(&gInitMutex); } if (res == EGL_TRUE) { if (major != NULL) *major = VERSION_MAJOR; if (minor != NULL) *minor = VERSION_MINOR; } return res; } EGLBoolean eglTerminate(EGLDisplay dpy) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean res = EGL_TRUE; egl_display_t& d = egl_display_t::get_display(dpy); if (d.initialized.fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); // TODO: destroy all resources (surfaces, contexts, etc...) //pthread_mutex_lock(&gInitMutex); //pthread_mutex_unlock(&gInitMutex); } return res; } // ---------------------------------------------------------------------------- // configuration // ---------------------------------------------------------------------------- EGLBoolean eglGetConfigs( EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); GLint numConfigs = NELEM(gConfigs); if (!configs) { *num_config = numConfigs; return EGL_TRUE; } GLint i; for (i=0 ; i( (config_pair_t const*)attrib_list, 0, numAttributes-1, config_defaults[j].key) < 0) { for (int i=0 ; possibleMatch && i(eglSurface) ); if (!surface->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (surface->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); if (surface->ctx) { // defer disconnect/delete until no longer current surface->zombie = true; } else { surface->disconnect(); delete surface; } } return EGL_TRUE; } EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_surface_t* surface = static_cast(eglSurface); if (!surface->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (surface->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean ret = EGL_TRUE; switch (attribute) { case EGL_CONFIG_ID: ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value); break; case EGL_WIDTH: *value = surface->getWidth(); break; case EGL_HEIGHT: *value = surface->getHeight(); break; case EGL_LARGEST_PBUFFER: // not modified for a window or pixmap surface break; case EGL_TEXTURE_FORMAT: *value = EGL_NO_TEXTURE; break; case EGL_TEXTURE_TARGET: *value = EGL_NO_TEXTURE; break; case EGL_MIPMAP_TEXTURE: *value = EGL_FALSE; break; case EGL_MIPMAP_LEVEL: *value = 0; break; case EGL_RENDER_BUFFER: // TODO: return the real RENDER_BUFFER here *value = EGL_BACK_BUFFER; break; case EGL_HORIZONTAL_RESOLUTION: // pixel/mm * EGL_DISPLAY_SCALING *value = surface->getHorizontalResolution(); break; case EGL_VERTICAL_RESOLUTION: // pixel/mm * EGL_DISPLAY_SCALING *value = surface->getVerticalResolution(); break; case EGL_PIXEL_ASPECT_RATIO: { // w/h * EGL_DISPLAY_SCALING int wr = surface->getHorizontalResolution(); int hr = surface->getVerticalResolution(); *value = (wr * EGL_DISPLAY_SCALING) / hr; } break; case EGL_SWAP_BEHAVIOR: *value = surface->getSwapBehavior(); break; default: ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); } return ret; } EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext /*share_list*/, const EGLint* /*attrib_list*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); ogles_context_t* gl = ogles_init(sizeof(egl_context_t)); if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT); egl_context_t* c = static_cast(gl->rasterizer.base); c->flags = egl_context_t::NEVER_CURRENT; c->dpy = dpy; c->config = config; c->read = 0; c->draw = 0; return (EGLContext)gl; } EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_context_t* c = egl_context_t::context(ctx); if (c->flags & egl_context_t::IS_CURRENT) setGlThreadSpecific(0); ogles_uninit((ogles_context_t*)ctx); return EGL_TRUE; } EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); if (draw) { egl_surface_t* s = (egl_surface_t*)draw; if (!s->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (s->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: check that draw is compatible with the context } if (read && read!=draw) { egl_surface_t* s = (egl_surface_t*)read; if (!s->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (s->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: check that read is compatible with the context } EGLContext current_ctx = EGL_NO_CONTEXT; if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) return setError(EGL_BAD_MATCH, EGL_FALSE); if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) return setError(EGL_BAD_MATCH, EGL_FALSE); if (ctx == EGL_NO_CONTEXT) { // if we're detaching, we need the current context current_ctx = (EGLContext)getGlThreadSpecific(); } else { egl_context_t* c = egl_context_t::context(ctx); egl_surface_t* d = (egl_surface_t*)draw; egl_surface_t* r = (egl_surface_t*)read; if ((d && d->ctx && d->ctx != ctx) || (r && r->ctx && r->ctx != ctx)) { // one of the surface is bound to a context in another thread return setError(EGL_BAD_ACCESS, EGL_FALSE); } } ogles_context_t* gl = (ogles_context_t*)ctx; if (makeCurrent(gl) == 0) { if (ctx) { egl_context_t* c = egl_context_t::context(ctx); egl_surface_t* d = (egl_surface_t*)draw; egl_surface_t* r = (egl_surface_t*)read; if (c->draw) { egl_surface_t* s = reinterpret_cast(c->draw); s->disconnect(); s->ctx = EGL_NO_CONTEXT; if (s->zombie) delete s; } if (c->read) { // FIXME: unlock/disconnect the read surface too } c->draw = draw; c->read = read; if (c->flags & egl_context_t::NEVER_CURRENT) { c->flags &= ~egl_context_t::NEVER_CURRENT; GLint w = 0; GLint h = 0; if (draw) { w = d->getWidth(); h = d->getHeight(); } ogles_surfaceport(gl, 0, 0); ogles_viewport(gl, 0, 0, w, h); ogles_scissor(gl, 0, 0, w, h); } if (d) { if (d->connect() == EGL_FALSE) { return EGL_FALSE; } d->ctx = ctx; d->bindDrawSurface(gl); } if (r) { // FIXME: lock/connect the read surface too r->ctx = ctx; r->bindReadSurface(gl); } } else { // if surfaces were bound to the context bound to this thread // mark then as unbound. if (current_ctx) { egl_context_t* c = egl_context_t::context(current_ctx); egl_surface_t* d = (egl_surface_t*)c->draw; egl_surface_t* r = (egl_surface_t*)c->read; if (d) { c->draw = 0; d->disconnect(); d->ctx = EGL_NO_CONTEXT; if (d->zombie) delete d; } if (r) { c->read = 0; r->ctx = EGL_NO_CONTEXT; // FIXME: unlock/disconnect the read surface too } } } return EGL_TRUE; } return setError(EGL_BAD_ACCESS, EGL_FALSE); } EGLContext eglGetCurrentContext(void) { // eglGetCurrentContext returns the current EGL rendering context, // as specified by eglMakeCurrent. If no context is current, // EGL_NO_CONTEXT is returned. return (EGLContext)getGlThreadSpecific(); } EGLSurface eglGetCurrentSurface(EGLint readdraw) { // eglGetCurrentSurface returns the read or draw surface attached // to the current EGL rendering context, as specified by eglMakeCurrent. // If no context is current, EGL_NO_SURFACE is returned. EGLContext ctx = (EGLContext)getGlThreadSpecific(); if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE; egl_context_t* c = egl_context_t::context(ctx); if (readdraw == EGL_READ) { return c->read; } else if (readdraw == EGL_DRAW) { return c->draw; } return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } EGLDisplay eglGetCurrentDisplay(void) { // eglGetCurrentDisplay returns the current EGL display connection // for the current EGL rendering context, as specified by eglMakeCurrent. // If no context is current, EGL_NO_DISPLAY is returned. EGLContext ctx = (EGLContext)getGlThreadSpecific(); if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY; egl_context_t* c = egl_context_t::context(ctx); return c->dpy; } EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_context_t* c = egl_context_t::context(ctx); switch (attribute) { case EGL_CONFIG_ID: // Returns the ID of the EGL frame buffer configuration with // respect to which the context was created return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value); } return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); } EGLBoolean eglWaitGL(void) { return EGL_TRUE; } EGLBoolean eglWaitNative(EGLint /*engine*/) { return EGL_TRUE; } EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_surface_t* d = static_cast(draw); if (!d->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (d->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // post the surface d->swapBuffers(); // if it's bound to a context, update the buffer if (d->ctx != EGL_NO_CONTEXT) { d->bindDrawSurface((ogles_context_t*)d->ctx); // if this surface is also the read surface of the context // it is bound to, make sure to update the read buffer as well. // The EGL spec is a little unclear about this. egl_context_t* c = egl_context_t::context(d->ctx); if (c->read == draw) { d->bindReadSurface((ogles_context_t*)d->ctx); } } return EGL_TRUE; } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface /*surface*/, NativePixmapType /*target*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglCopyBuffers() return EGL_FALSE; } EGLint eglGetError(void) { return getError(); } const char* eglQueryString(EGLDisplay dpy, EGLint name) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, (const char*)0); switch (name) { case EGL_VENDOR: return gVendorString; case EGL_VERSION: return gVersionString; case EGL_EXTENSIONS: return gExtensionsString; case EGL_CLIENT_APIS: return gClientApiString; } return setError(EGL_BAD_PARAMETER, (const char *)0); } // ---------------------------------------------------------------------------- // EGL 1.1 // ---------------------------------------------------------------------------- EGLBoolean eglSurfaceAttrib( EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*attribute*/, EGLint /*value*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglSurfaceAttrib() return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLBoolean eglBindTexImage( EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglBindTexImage() return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLBoolean eglReleaseTexImage( EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglReleaseTexImage() return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint /*interval*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglSwapInterval() return EGL_TRUE; } // ---------------------------------------------------------------------------- // EGL 1.2 // ---------------------------------------------------------------------------- EGLBoolean eglBindAPI(EGLenum api) { if (api != EGL_OPENGL_ES_API) return setError(EGL_BAD_PARAMETER, EGL_FALSE); return EGL_TRUE; } EGLenum eglQueryAPI(void) { return EGL_OPENGL_ES_API; } EGLBoolean eglWaitClient(void) { glFinish(); return EGL_TRUE; } EGLBoolean eglReleaseThread(void) { // TODO: eglReleaseThread() return EGL_TRUE; } EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, EGLenum /*buftype*/, EGLClientBuffer /*buffer*/, EGLConfig /*config*/, const EGLint* /*attrib_list*/) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); // TODO: eglCreatePbufferFromClientBuffer() return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } // ---------------------------------------------------------------------------- // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- void (*eglGetProcAddress (const char *procname))() { extention_map_t const * const map = gExtentionMap; for (uint32_t i=0 ; icommon.magic != ANDROID_NATIVE_BUFFER_MAGIC) return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); switch (native_buffer->format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_BGRA_8888: break; default: return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); } native_buffer->common.incRef(&native_buffer->common); return (EGLImageKHR)native_buffer; } EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) { return setError(EGL_BAD_DISPLAY, EGL_FALSE); } ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img; if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) return setError(EGL_BAD_PARAMETER, EGL_FALSE); if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) return setError(EGL_BAD_PARAMETER, EGL_FALSE); native_buffer->common.decRef(&native_buffer->common); return EGL_TRUE; } // ---------------------------------------------------------------------------- // EGL_KHR_fence_sync // ---------------------------------------------------------------------------- #define FENCE_SYNC_HANDLE ((EGLSyncKHR)0xFE4CE) EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) { return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR); } if (type != EGL_SYNC_FENCE_KHR || (attrib_list != NULL && attrib_list[0] != EGL_NONE)) { return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); } if (eglGetCurrentContext() == EGL_NO_CONTEXT) { return setError(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); } // AGL is synchronous; nothing to do here. return FENCE_SYNC_HANDLE; } EGLBoolean eglDestroySyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync) { if (sync != FENCE_SYNC_HANDLE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } return EGL_TRUE; } EGLint eglClientWaitSyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint /*flags*/, EGLTimeKHR /*timeout*/) { if (sync != FENCE_SYNC_HANDLE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } return EGL_CONDITION_SATISFIED_KHR; } EGLBoolean eglGetSyncAttribKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint attribute, EGLint *value) { if (sync != FENCE_SYNC_HANDLE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } switch (attribute) { case EGL_SYNC_TYPE_KHR: *value = EGL_SYNC_FENCE_KHR; return EGL_TRUE; case EGL_SYNC_STATUS_KHR: *value = EGL_SIGNALED_KHR; return EGL_TRUE; case EGL_SYNC_CONDITION_KHR: *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; return EGL_TRUE; default: return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); } } // ---------------------------------------------------------------------------- // ANDROID extensions // ---------------------------------------------------------------------------- EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height) { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); egl_surface_t* d = static_cast(draw); if (!d->isValid()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (d->dpy != dpy) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // post the surface d->setSwapRectangle(left, top, width, height); return EGL_TRUE; } opengl/libagl/fixed_asm.S0100644 0000000 0000000 00000004541 13077405420 014414 0ustar000000000 0000000 /* libs/opengles/fixed_asm.S ** ** Copyright 2006, 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. */ .text .align 2 .global gglFloatToFixed .type gglFloatToFixed, %function .global gglFloatToFixedFast .type gglFloatToFixedFast, %function /* * Converts a float to a s15.16 fixed-point number. * this doesn't handle floats out of the [-32768, +32768[ range * and doesn't performs round-to-nearest. * however, it's very fast :-) */ gglFloatToFixedFast: movs r1, r0, lsl #1 /* remove bit sign */ mov r2, #0x8E /* 127 + 15 */ sub r1, r2, r1, lsr #24 /* compute shift */ mov r2, r0, lsl #8 /* mantissa<<8 */ orr r2, r2, #0x80000000 /* add the missing 1 */ mov r0, r2, lsr r1 /* scale to 16.16 */ rsbcs r0, r0, #0 /* negate if needed */ bx lr /* * this version rounds-to-nearest and saturates numbers * outside the range (but not NaNs). */ gglFloatToFixed: mov r1, r0, lsl #1 /* remove bit sign */ mov r2, #0x8E /* 127 + 15 */ subs r1, r2, r1, lsr #24 /* compute shift */ bls 0f /* too big */ mov r2, r0, lsl #8 /* mantissa<<8 */ orr r2, r2, #0x80000000 /* add the missing 1 */ mov r3, r0 movs r0, r2, lsr r1 /* scale to 16.16 */ addcs r0, r0, #1 /* round-to-nearest */ tst r3, #0x80000000 /* negative? */ rsbne r0, r0, #0 /* negate if needed */ bx lr 0: ands r0, r0, #0x80000000 /* keep only the sign bit */ moveq r0, #0x7fffffff /* positive, maximum value */ bx lr opengl/libagl/fp.cpp0100644 0000000 0000000 00000004117 13077405420 013441 0ustar000000000 0000000 /* libs/opengles/fp.cpp ** ** Copyright 2006, 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 "fp.h" // ---------------------------------------------------------------------------- #if !(defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6)) GGLfixed gglFloatToFixed(float v) { return GGLfixed(floorf(v * 65536.0f + 0.5f)); } #endif // ---------------------------------------------------------------------------- namespace android { namespace gl { GLfloat fixedToFloat(GLfixed x) { #if DEBUG_USE_FLOATS return x / 65536.0f; #else if (!x) return 0; const uint32_t s = x & 0x80000000; union { uint32_t i; float f; }; i = s ? -x : x; const int c = gglClz(i) - 8; i = (c>=0) ? (i<>-c); const uint32_t e = 134 - c; i &= ~0x800000; i |= e<<23; i |= s; return f; #endif } float sinef(float x) { const float A = 1.0f / (2.0f*M_PI); const float B = -16.0f; const float C = 8.0f; // scale angle for easy argument reduction x *= A; if (fabsf(x) >= 0.5f) { // Argument reduction x = x - ceilf(x + 0.5f) + 1.0f; } const float y = B*x*fabsf(x) + C*x; return 0.2215f * (y*fabsf(y) - y) + y; } float cosinef(float x) { return sinef(x + float(M_PI/2)); } void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) { *s = sinef(angle); *c = cosinef(angle); } }; // namespace fp_utils // ---------------------------------------------------------------------------- }; // namespace android opengl/libagl/fp.h0100644 0000000 0000000 00000011373 13077405420 013110 0ustar000000000 0000000 /* libs/opengles/fp.h ** ** Copyright 2006, 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_OPENGLES_FP_H #define ANDROID_OPENGLES_FP_H #include #include #include #include #include #include #define DEBUG_USE_FLOATS 0 // ---------------------------------------------------------------------------- extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const)); // ---------------------------------------------------------------------------- namespace android { namespace gl { GLfloat fixedToFloat(GLfixed) CONST; void sincosf(GLfloat angle, GLfloat* s, GLfloat* c); float sinef(GLfloat x) CONST; float cosinef(GLfloat x) CONST; inline bool cmpf(GLfloat a, GLfloat b) CONST; inline bool isZerof(GLfloat) CONST; inline bool isOnef(GLfloat) CONST; inline int isZeroOrNegativef(GLfloat) CONST; inline int exponent(GLfloat) CONST; inline int32_t mantissa(GLfloat) CONST; inline GLfloat clampToZerof(GLfloat) CONST; inline GLfloat reciprocalf(GLfloat) CONST; inline GLfloat rsqrtf(GLfloat) CONST; inline GLfloat sqrf(GLfloat) CONST; inline GLfloat addExpf(GLfloat v, int e) CONST; inline GLfloat mul2f(GLfloat v) CONST; inline GLfloat div2f(GLfloat v) CONST; inline GLfloat absf(GLfloat v) CONST; /* * float fastexpf(float) : a fast approximation of expf(x) * give somewhat accurate results for -88 <= x <= 88 * * exp(x) = 2^(x/ln(2)) * we use the properties of float encoding * to get a fast 2^ and linear interpolation * */ inline float fastexpf(float y) __attribute__((const)); inline float fastexpf(float y) { union { float r; int32_t i; } u; // 127*ln(2) = 88 if (y < -88.0f) { u.r = 0.0f; } else if (y > 88.0f) { u.r = INFINITY; } else { const float kOneOverLogTwo = (1L<<23) / M_LN2; const int32_t kExponentBias = 127L<<23; const int32_t e = int32_t(y*kOneOverLogTwo); u.i = e + kExponentBias; } return u.r; } bool cmpf(GLfloat a, GLfloat b) { #if DEBUG_USE_FLOATS return a == b; #else union { float f; uint32_t i; } ua, ub; ua.f = a; ub.f = b; return ua.i == ub.i; #endif } bool isZerof(GLfloat v) { #if DEBUG_USE_FLOATS return v == 0; #else union { float f; int32_t i; }; f = v; return (i<<1) == 0; #endif } bool isOnef(GLfloat v) { return cmpf(v, 1.0f); } int isZeroOrNegativef(GLfloat v) { #if DEBUG_USE_FLOATS return v <= 0; #else union { float f; int32_t i; }; f = v; return isZerof(v) | (i>>31); #endif } int exponent(GLfloat v) { union { float f; uint32_t i; }; f = v; return ((i << 1) >> 24) - 127; } int32_t mantissa(GLfloat v) { union { float f; uint32_t i; }; f = v; if (!(i&0x7F800000)) return 0; const int s = i >> 31; i |= (1L<<23); i &= ~0xFF000000; return s ? -i : i; } GLfloat clampToZerof(GLfloat v) { #if DEBUG_USE_FLOATS return v<0 ? 0 : (v>1 ? 1 : v); #else union { float f; int32_t i; }; f = v; i &= ~(i>>31); return f; #endif } GLfloat reciprocalf(GLfloat v) { // XXX: do better return 1.0f / v; } GLfloat rsqrtf(GLfloat v) { // XXX: do better return 1.0f / sqrtf(v); } GLfloat sqrf(GLfloat v) { // XXX: do better return v*v; } GLfloat addExpf(GLfloat v, int e) { union { float f; int32_t i; }; f = v; if (i<<1) { // XXX: deal with over/underflow i += int32_t(e)<<23; } return f; } GLfloat mul2f(GLfloat v) { #if DEBUG_USE_FLOATS return v*2; #else return addExpf(v, 1); #endif } GLfloat div2f(GLfloat v) { #if DEBUG_USE_FLOATS return v*0.5f; #else return addExpf(v, -1); #endif } GLfloat absf(GLfloat v) { #if DEBUG_USE_FLOATS return v<0 ? -v : v; #else union { float f; int32_t i; }; f = v; i &= ~0x80000000; return f; #endif } }; // namespace gl // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_OPENGLES_FP_H opengl/libagl/iterators.S0100644 0000000 0000000 00000004254 13077405420 014472 0ustar000000000 0000000 /* libs/opengles/iterators.S ** ** Copyright 2006, 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. */ .text .align 2 .arm .global iterators0032 .type iterators0032, %function /* * iterators0032 * * MUST BE CALLED FROM ARM CODE * * r0: const compute_iterators_t* (this) * r0 + 0: m_dx01 * r0 + 4: m_dy10 * r0 + 8: m_dx20 * r0 +12: m_dy02 * r0 +16: m_x0 * r0 +20: m_y0 * r0 +24: m_area * r0 +28: m_scale * r0 +29: m_area_scale; * r1: int32_t* (out) * r1 + 0: c * r1 + 4: dcdx * r1 + 8: dcdy * r2: c0 * r3: c1 * [sp]: c2 */ iterators0032: stmfd sp!, {r4, r5, r6, r7, r8, lr} ldr r4, [sp, #4*6] ldrb r12, [r0, #29] sub r3, r3, r2 sub r4, r4, r2 sub r12, r12, #16 mov r3, r3, asr r12 mov r4, r4, asr r12 ldr r5, [r0, #0] ldr r12, [r0, #4] smull r8, lr, r4, r5 ldr r5, [r0, #8] smull r6, r7, r4, r12 ldr r12, [r0, #12] smlal r8, lr, r3, r5 smlal r6, r7, r3, r12 ldr r3, [r0, #16] // m_x0 ldr r4, [r0, #20] // m_x1 str r6, [r1, #4] str r8, [r1, #8] umull r6, r5, r3, r6 umull r8, r0, r4, r8 mla r7, r3, r7, r5 mla lr, r4, lr, r0 adds r6, r6, r8 adc r7, r7, lr movs r6, r6, lsr #4 adc r6, r6, r7, lsl #28 rsb r6, r6, r2, lsl #16 str r6, [r1, #0] ldmfd sp!, {r4, r5, r6, r7, r8, pc} opengl/libagl/light.cpp0100644 0000000 0000000 00000064412 13077405420 014147 0ustar000000000 0000000 /* libs/opengles/light.cpp ** ** Copyright 2006, 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 #include "context.h" #include "fp.h" #include "light.h" #include "state.h" #include "matrix.h" #if defined(__arm__) && defined(__thumb__) #warning "light.cpp should not be compiled in thumb on ARM." #endif namespace android { // ---------------------------------------------------------------------------- static void invalidate_lighting(ogles_context_t* c); static void lightVertexValidate(ogles_context_t* c, vertex_t* v); static void lightVertexNop(ogles_context_t* c, vertex_t* v); static void lightVertex(ogles_context_t* c, vertex_t* v); static void lightVertexMaterial(ogles_context_t* c, vertex_t* v); static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s); static __attribute__((noinline)) void vnorm3(GLfixed* d, const GLfixed* a); static inline void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a); static inline void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a); static inline void vmla3(GLfixed* d, const GLfixed* m0, const GLfixed* m1, const GLfixed* a); static inline void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1); static GLfixed fog_linear(ogles_context_t* c, GLfixed z); static GLfixed fog_exp(ogles_context_t* c, GLfixed z); static GLfixed fog_exp2(ogles_context_t* c, GLfixed z); // ---------------------------------------------------------------------------- static void init_white(vec4_t& c) { c.r = c.g = c.b = c.a = 0x10000; } void ogles_init_light(ogles_context_t* c) { for (unsigned int i=0 ; ilighting.lights[i].ambient.a = 0x10000; c->lighting.lights[i].position.z = 0x10000; c->lighting.lights[i].spotDir.z = -0x10000; c->lighting.lights[i].spotCutoff = gglIntToFixed(180); c->lighting.lights[i].attenuation[0] = 0x10000; } init_white(c->lighting.lights[0].diffuse); init_white(c->lighting.lights[0].specular); c->lighting.front.ambient.r = c->lighting.front.ambient.g = c->lighting.front.ambient.b = gglFloatToFixed(0.2f); c->lighting.front.ambient.a = 0x10000; c->lighting.front.diffuse.r = c->lighting.front.diffuse.g = c->lighting.front.diffuse.b = gglFloatToFixed(0.8f); c->lighting.front.diffuse.a = 0x10000; c->lighting.front.specular.a = 0x10000; c->lighting.front.emission.a = 0x10000; c->lighting.lightModel.ambient.r = c->lighting.lightModel.ambient.g = c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f); c->lighting.lightModel.ambient.a = 0x10000; c->lighting.colorMaterial.face = GL_FRONT_AND_BACK; c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE; c->fog.mode = GL_EXP; c->fog.fog = fog_exp; c->fog.density = 0x10000; c->fog.end = 0x10000; c->fog.invEndMinusStart = 0x10000; invalidate_lighting(c); c->rasterizer.procs.shadeModel(c, GL_SMOOTH); c->lighting.shadeModel = GL_SMOOTH; } void ogles_uninit_light(ogles_context_t* /*c*/) { } static inline int32_t clampF(GLfixed f) CONST; int32_t clampF(GLfixed f) { f = (f & ~(f>>31)); if (f >= 0x10000) f = 0x10000; return f; } static GLfixed fog_linear(ogles_context_t* c, GLfixed z) { return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart)); } static GLfixed fog_exp(ogles_context_t* c, GLfixed z) { const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z))); return clampF(gglFloatToFixed(fastexpf(-e))); } static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) { const float e = fixedToFloat(gglMulx(c->fog.density, z)); return clampF(gglFloatToFixed(fastexpf(-e*e))); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark math helpers #endif static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) { d[0] = gglMulx(m[0], s); d[1] = gglMulx(m[1], s); d[2] = gglMulx(m[2], s); } static inline void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) { d[0] = gglMulAddx(m[0], s, a[0]); d[1] = gglMulAddx(m[1], s, a[1]); d[2] = gglMulAddx(m[2], s, a[2]); } static inline void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) { d[0] = gglMulSubx(m[0], s, a[0]); d[1] = gglMulSubx(m[1], s, a[1]); d[2] = gglMulSubx(m[2], s, a[2]); } static inline void vmla3(GLfixed* d, const GLfixed* m0, const GLfixed* m1, const GLfixed* a) { d[0] = gglMulAddx(m0[0], m1[0], a[0]); d[1] = gglMulAddx(m0[1], m1[1], a[1]); d[2] = gglMulAddx(m0[2], m1[2], a[2]); } static inline void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) { d[0] = gglMulx(m0[0], m1[0]); d[1] = gglMulx(m0[1], m1[1]); d[2] = gglMulx(m0[2], m1[2]); } void vnorm3(GLfixed* d, const GLfixed* a) { // we must take care of overflows when normalizing a vector GLfixed n; int32_t x = a[0]; x = x>=0 ? x : -x; int32_t y = a[1]; y = y>=0 ? y : -y; int32_t z = a[2]; z = z>=0 ? z : -z; if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) { // in this case this will all fit on 32 bits n = x*x + y*y + z*z; n = gglSqrtRecipx(n); n <<= 8; } else { // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117) n = vsquare3(x, y, z); n = gglSqrtRecipx(n); } vscale3(d, a, n); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark lighting equations #endif static inline void light_picker(ogles_context_t* c) { if (ggl_likely(!c->lighting.enable)) { c->lighting.lightVertex = lightVertexNop; return; } if (c->lighting.colorMaterial.enable) { c->lighting.lightVertex = lightVertexMaterial; } else { c->lighting.lightVertex = lightVertex; } } static inline void validate_light_mvi(ogles_context_t* c) { uint32_t en = c->lighting.enabledLights; // Vector from object to viewer, in eye coordinates while (en) { const int i = 31 - gglClz(en); en &= ~(1<lighting.lights[i]; #if OBJECT_SPACE_LIGHTING c->transforms.mvui.point4(&c->transforms.mvui, &l.objPosition, &l.position); #else l.objPosition = l.position; #endif vnorm3(l.normalizedObjPosition.v, l.objPosition.v); } const vec4_t eyeViewer = { 0, 0, 0x10000, 0 }; #if OBJECT_SPACE_LIGHTING c->transforms.mvui.point3(&c->transforms.mvui, &c->lighting.objViewer, &eyeViewer); vnorm3(c->lighting.objViewer.v, c->lighting.objViewer.v); #else c->lighting.objViewer = eyeViewer; #endif } static inline void validate_light(ogles_context_t* c) { // if colorMaterial is enabled, we get the color from the vertex if (!c->lighting.colorMaterial.enable) { material_t& material = c->lighting.front; uint32_t en = c->lighting.enabledLights; while (en) { const int i = 31 - gglClz(en); en &= ~(1<lighting.lights[i]; vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v); vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v); vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v); // this is just a flag to tell if we have a specular component l.implicitSpecular.v[3] = l.implicitSpecular.r | l.implicitSpecular.g | l.implicitSpecular.b; l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0; if (l.rConstAttenuation) l.rConstAttenuation = gglRecipFast(l.attenuation[0]); } // emission and ambient for the whole scene vmla3( c->lighting.implicitSceneEmissionAndAmbient.v, c->lighting.lightModel.ambient.v, material.ambient.v, material.emission.v); c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a; } validate_light_mvi(c); } void invalidate_lighting(ogles_context_t* c) { // TODO: pick lightVertexValidate or lightVertexValidateMVI // instead of systematically the heavier lightVertexValidate() c->lighting.lightVertex = lightVertexValidate; } void ogles_invalidate_lighting_mvui(ogles_context_t* c) { invalidate_lighting(c); } void lightVertexNop(ogles_context_t*, vertex_t* /*v*/) { // we should never end-up here } void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v) { validate_light_mvi(c); light_picker(c); c->lighting.lightVertex(c, v); } void lightVertexValidate(ogles_context_t* c, vertex_t* v) { validate_light(c); light_picker(c); c->lighting.lightVertex(c, v); } void lightVertexMaterial(ogles_context_t* c, vertex_t* v) { // fetch the material color const GLvoid* cp = c->arrays.color.element( v->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v->color.v, cp); // acquire the color-material from the vertex material_t& material = c->lighting.front; material.ambient = material.diffuse = v->color; // implicit arguments need to be computed per/vertex uint32_t en = c->lighting.enabledLights; while (en) { const int i = 31 - gglClz(en); en &= ~(1<lighting.lights[i]; vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v); vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v); vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v); // this is just a flag to tell if we have a specular component l.implicitSpecular.v[3] = l.implicitSpecular.r | l.implicitSpecular.g | l.implicitSpecular.b; } // emission and ambient for the whole scene vmla3( c->lighting.implicitSceneEmissionAndAmbient.v, c->lighting.lightModel.ambient.v, material.ambient.v, material.emission.v); c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a; // now we can light our vertex as usual lightVertex(c, v); } void lightVertex(ogles_context_t* c, vertex_t* v) { // emission and ambient for the whole scene vec4_t r = c->lighting.implicitSceneEmissionAndAmbient; const vec4_t objViewer = c->lighting.objViewer; uint32_t en = c->lighting.enabledLights; if (ggl_likely(en)) { // since we do the lighting in object-space, we don't need to // transform each normal. However, we might still have to normalize // it if GL_NORMALIZE is enabled. vec4_t n; c->arrays.normal.fetch(c, n.v, c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK)); #if !OBJECT_SPACE_LIGHTING c->transforms.mvui.point3(&c->transforms.mvui, &n, &n); #endif // TODO: right now we handle GL_RESCALE_NORMALS as if it were // GL_NORMALIZE. We could optimize this by scaling mvui // appropriately instead. if (c->transforms.rescaleNormals) vnorm3(n.v, n.v); const material_t& material = c->lighting.front; const int twoSide = c->lighting.lightModel.twoSide; while (en) { const int i = 31 - gglClz(en); en &= ~(1<lighting.lights[i]; vec4_t d, t; GLfixed s; GLfixed sqDist = 0x10000; // compute vertex-to-light vector if (ggl_unlikely(l.position.w)) { // lightPos/1.0 - vertex/vertex.w == lightPos*vertex.w - vertex #if !OBJECT_SPACE_LIGHTING vec4_t o; const transform_t& mv = c->transforms.modelview.transform; mv.point4(&mv, &o, &v->obj); vss3(d.v, l.objPosition.v, o.w, o.v); #else vss3(d.v, l.objPosition.v, v->obj.w, v->obj.v); #endif sqDist = dot3(d.v, d.v); vscale3(d.v, d.v, gglSqrtRecipx(sqDist)); } else { // TODO: avoid copy here d = l.normalizedObjPosition; } // ambient & diffuse s = dot3(n.v, d.v); s = (s<0) ? (twoSide?(-s):0) : s; vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v); // specular if (ggl_unlikely(s && l.implicitSpecular.v[3])) { vec4_t h; h.x = d.x + objViewer.x; h.y = d.y + objViewer.y; h.z = d.z + objViewer.z; vnorm3(h.v, h.v); s = dot3(n.v, h.v); s = (s<0) ? (twoSide?(-s):0) : s; if (s > 0) { s = gglPowx(s, material.shininess); vsa3(t.v, l.implicitSpecular.v, s, t.v); } } // spot if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) { GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v); if (spotAtt >= l.spotCutoffCosine) { vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp)); } } // attenuation if (ggl_unlikely(l.position.w)) { if (l.rConstAttenuation) { s = l.rConstAttenuation; } else { s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]); if (l.attenuation[1]) s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s); s = gglRecipFast(s); } vscale3(t.v, t.v, s); } r.r += t.r; r.g += t.g; r.b += t.b; } } v->color.r = gglClampx(r.r); v->color.g = gglClampx(r.g); v->color.b = gglClampx(r.b); v->color.a = gglClampx(r.a); v->flags |= vertex_t::LIT; } static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c) { if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) { ogles_error(c, GL_INVALID_ENUM); return; } c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE; invalidate_lighting(c); } static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c) { if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) { ogles_error(c, GL_INVALID_ENUM); return; } light_t& light = c->lighting.lights[i-GL_LIGHT0]; const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f); switch (pname) { case GL_SPOT_EXPONENT: if (GGLfixed(param) >= gglIntToFixed(128)) { ogles_error(c, GL_INVALID_VALUE); return; } light.spotExp = param; break; case GL_SPOT_CUTOFF: if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) { ogles_error(c, GL_INVALID_VALUE); return; } light.spotCutoff = param; light.spotCutoffCosine = gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param)); break; case GL_CONSTANT_ATTENUATION: if (param < 0) { ogles_error(c, GL_INVALID_VALUE); return; } light.attenuation[0] = param; break; case GL_LINEAR_ATTENUATION: if (param < 0) { ogles_error(c, GL_INVALID_VALUE); return; } light.attenuation[1] = param; break; case GL_QUADRATIC_ATTENUATION: if (param < 0) { ogles_error(c, GL_INVALID_VALUE); return; } light.attenuation[2] = param; break; default: ogles_error(c, GL_INVALID_ENUM); return; } invalidate_lighting(c); } static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c) { if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) { ogles_error(c, GL_INVALID_ENUM); return; } GLfixed* what; light_t& light = c->lighting.lights[i-GL_LIGHT0]; switch (pname) { case GL_AMBIENT: what = light.ambient.v; break; case GL_DIFFUSE: what = light.diffuse.v; break; case GL_SPECULAR: what = light.specular.v; break; case GL_POSITION: { ogles_validate_transform(c, transform_state_t::MODELVIEW); transform_t& mv = c->transforms.modelview.transform; mv.point4(&mv, &light.position, reinterpret_cast(params)); invalidate_lighting(c); return; } case GL_SPOT_DIRECTION: { #if OBJECT_SPACE_LIGHTING ogles_validate_transform(c, transform_state_t::MVUI); transform_t& mvui = c->transforms.mvui; mvui.point3(&mvui, &light.spotDir, reinterpret_cast(params)); #else light.spotDir = *reinterpret_cast(params); #endif vnorm3(light.normalizedSpotDir.v, light.spotDir.v); invalidate_lighting(c); return; } default: lightx(i, pname, params[0], c); return; } what[0] = params[0]; what[1] = params[1]; what[2] = params[2]; what[3] = params[3]; invalidate_lighting(c); } static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c) { if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { ogles_error(c, GL_INVALID_ENUM); return; } if (ggl_unlikely(pname != GL_SHININESS)) { ogles_error(c, GL_INVALID_ENUM); return; } c->lighting.front.shininess = param; invalidate_lighting(c); } static void fogx(GLenum pname, GLfixed param, ogles_context_t* c) { switch (pname) { case GL_FOG_DENSITY: if (param >= 0) { c->fog.density = param; break; } ogles_error(c, GL_INVALID_VALUE); break; case GL_FOG_START: c->fog.start = param; c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); break; case GL_FOG_END: c->fog.end = param; c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); break; case GL_FOG_MODE: switch (param) { case GL_LINEAR: c->fog.mode = param; c->fog.fog = fog_linear; break; case GL_EXP: c->fog.mode = param; c->fog.fog = fog_exp; break; case GL_EXP2: c->fog.mode = param; c->fog.fog = fog_exp2; break; default: ogles_error(c, GL_INVALID_ENUM); break; } break; default: ogles_error(c, GL_INVALID_ENUM); break; } } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- using namespace android; #if 0 #pragma mark - #pragma mark lighting APIs #endif void glShadeModel(GLenum mode) { ogles_context_t* c = ogles_context_t::get(); if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) { ogles_error(c, GL_INVALID_ENUM); return; } c->lighting.shadeModel = mode; } void glLightModelf(GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); lightModelx(pname, gglFloatToFixed(param), c); } void glLightModelx(GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); lightModelx(pname, param, c); } void glLightModelfv(GLenum pname, const GLfloat *params) { ogles_context_t* c = ogles_context_t::get(); if (pname == GL_LIGHT_MODEL_TWO_SIDE) { lightModelx(pname, gglFloatToFixed(params[0]), c); return; } if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) { ogles_error(c, GL_INVALID_ENUM); return; } c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]); c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]); c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]); c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]); invalidate_lighting(c); } void glLightModelxv(GLenum pname, const GLfixed *params) { ogles_context_t* c = ogles_context_t::get(); if (pname == GL_LIGHT_MODEL_TWO_SIDE) { lightModelx(pname, params[0], c); return; } if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) { ogles_error(c, GL_INVALID_ENUM); return; } c->lighting.lightModel.ambient.r = params[0]; c->lighting.lightModel.ambient.g = params[1]; c->lighting.lightModel.ambient.b = params[2]; c->lighting.lightModel.ambient.a = params[3]; invalidate_lighting(c); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void glLightf(GLenum i, GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); lightx(i, pname, gglFloatToFixed(param), c); } void glLightx(GLenum i, GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); lightx(i, pname, param, c); } void glLightfv(GLenum i, GLenum pname, const GLfloat *params) { ogles_context_t* c = ogles_context_t::get(); switch (pname) { case GL_SPOT_EXPONENT: case GL_SPOT_CUTOFF: case GL_CONSTANT_ATTENUATION: case GL_LINEAR_ATTENUATION: case GL_QUADRATIC_ATTENUATION: lightx(i, pname, gglFloatToFixed(params[0]), c); return; } GLfixed paramsx[4]; paramsx[0] = gglFloatToFixed(params[0]); paramsx[1] = gglFloatToFixed(params[1]); paramsx[2] = gglFloatToFixed(params[2]); if (pname != GL_SPOT_DIRECTION) paramsx[3] = gglFloatToFixed(params[3]); lightxv(i, pname, paramsx, c); } void glLightxv(GLenum i, GLenum pname, const GLfixed *params) { ogles_context_t* c = ogles_context_t::get(); lightxv(i, pname, params, c); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void glMaterialf(GLenum face, GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); materialx(face, pname, gglFloatToFixed(param), c); } void glMaterialx(GLenum face, GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); materialx(face, pname, param, c); } void glMaterialfv( GLenum face, GLenum pname, const GLfloat *params) { ogles_context_t* c = ogles_context_t::get(); if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { ogles_error(c, GL_INVALID_ENUM); return; } GLfixed* what=0; GLfixed* other=0; switch (pname) { case GL_AMBIENT: what = c->lighting.front.ambient.v; break; case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break; case GL_SPECULAR: what = c->lighting.front.specular.v; break; case GL_EMISSION: what = c->lighting.front.emission.v; break; case GL_AMBIENT_AND_DIFFUSE: what = c->lighting.front.ambient.v; other = c->lighting.front.diffuse.v; break; case GL_SHININESS: c->lighting.front.shininess = gglFloatToFixed(params[0]); invalidate_lighting(c); return; default: ogles_error(c, GL_INVALID_ENUM); return; } what[0] = gglFloatToFixed(params[0]); what[1] = gglFloatToFixed(params[1]); what[2] = gglFloatToFixed(params[2]); what[3] = gglFloatToFixed(params[3]); if (other) { other[0] = what[0]; other[1] = what[1]; other[2] = what[2]; other[3] = what[3]; } invalidate_lighting(c); } void glMaterialxv( GLenum face, GLenum pname, const GLfixed *params) { ogles_context_t* c = ogles_context_t::get(); if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { ogles_error(c, GL_INVALID_ENUM); return; } GLfixed* what=0; GLfixed* other=0; switch (pname) { case GL_AMBIENT: what = c->lighting.front.ambient.v; break; case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break; case GL_SPECULAR: what = c->lighting.front.specular.v; break; case GL_EMISSION: what = c->lighting.front.emission.v; break; case GL_AMBIENT_AND_DIFFUSE: what = c->lighting.front.ambient.v; other = c->lighting.front.diffuse.v; break; case GL_SHININESS: c->lighting.front.shininess = gglFloatToFixed(params[0]); invalidate_lighting(c); return; default: ogles_error(c, GL_INVALID_ENUM); return; } what[0] = params[0]; what[1] = params[1]; what[2] = params[2]; what[3] = params[3]; if (other) { other[0] = what[0]; other[1] = what[1]; other[2] = what[2]; other[3] = what[3]; } invalidate_lighting(c); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark fog #endif void glFogf(GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); GLfixed paramx = (GLfixed)param; if (pname != GL_FOG_MODE) paramx = gglFloatToFixed(param); fogx(pname, paramx, c); } void glFogx(GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); fogx(pname, param, c); } void glFogfv(GLenum pname, const GLfloat *params) { ogles_context_t* c = ogles_context_t::get(); if (pname != GL_FOG_COLOR) { GLfixed paramx = (GLfixed)params[0]; if (pname != GL_FOG_MODE) paramx = gglFloatToFixed(params[0]); fogx(pname, paramx, c); return; } GLfixed paramsx[4]; paramsx[0] = gglFloatToFixed(params[0]); paramsx[1] = gglFloatToFixed(params[1]); paramsx[2] = gglFloatToFixed(params[2]); paramsx[3] = gglFloatToFixed(params[3]); c->rasterizer.procs.fogColor3xv(c, paramsx); } void glFogxv(GLenum pname, const GLfixed *params) { ogles_context_t* c = ogles_context_t::get(); if (pname != GL_FOG_COLOR) { fogx(pname, params[0], c); return; } c->rasterizer.procs.fogColor3xv(c, params); } opengl/libagl/light.h0100644 0000000 0000000 00000002332 13077405420 013605 0ustar000000000 0000000 /* libs/opengles/light.h ** ** Copyright 2006, 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_OPENGLES_LIGHT_H #define ANDROID_OPENGLES_LIGHT_H #include #include #include // Set to 1 for object-space lighting evaluation. // There are still some bugs with object-space lighting, // especially visible in the San Angeles demo. #define OBJECT_SPACE_LIGHTING 0 namespace android { namespace gl { struct ogles_context_t; }; void ogles_init_light(ogles_context_t* c); void ogles_uninit_light(ogles_context_t* c); void ogles_invalidate_lighting_mvui(ogles_context_t* c); }; // namespace android #endif // ANDROID_OPENGLES_LIGHT_H opengl/libagl/matrix.cpp0100644 0000000 0000000 00000076101 13077405420 014342 0ustar000000000 0000000 /* libs/opengles/matrix.cpp ** ** Copyright 2006, 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 #include #include "context.h" #include "fp.h" #include "state.h" #include "matrix.h" #include "vertex.h" #include "light.h" #if defined(__arm__) && defined(__thumb__) #warning "matrix.cpp should not be compiled in thumb on ARM." #endif #define I(_i, _j) ((_j)+ 4*(_i)) namespace android { // ---------------------------------------------------------------------------- static const GLfloat gIdentityf[16] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; static const matrixx_t gIdentityx = { { 0x10000,0,0,0, 0,0x10000,0,0, 0,0,0x10000,0, 0,0,0,0x10000 } }; static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o); static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o); static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o); static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o); static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o); static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o); static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o); static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o); static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o); // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void ogles_init_matrix(ogles_context_t* c) { c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH); c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH); for (int i=0; itransforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH); c->transforms.current = &c->transforms.modelview; c->transforms.matrixMode = GL_MODELVIEW; c->transforms.dirty = transform_state_t::VIEWPORT | transform_state_t::MVUI | transform_state_t::MVIT | transform_state_t::MVP; c->transforms.mvp.loadIdentity(); c->transforms.mvp4.loadIdentity(); c->transforms.mvit4.loadIdentity(); c->transforms.mvui.loadIdentity(); c->transforms.vpt.loadIdentity(); c->transforms.vpt.zNear = 0.0f; c->transforms.vpt.zFar = 1.0f; } void ogles_uninit_matrix(ogles_context_t* c) { c->transforms.modelview.uninit(); c->transforms.projection.uninit(); for (int i=0; itransforms.texture[i].uninit(); } static void validate_perspective(ogles_context_t* c, vertex_t* v) { const uint32_t enables = c->rasterizer.state.enables; c->arrays.perspective = (c->clipPlanes.enable) ? ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D; if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { c->arrays.perspective = ogles_vertex_perspective3DZ; if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG)) c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ; } if ((c->arrays.vertex.size != 4) && (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) { c->arrays.perspective = ogles_vertex_perspective2D; } c->arrays.perspective(c, v); } void ogles_invalidate_perspective(ogles_context_t* c) { c->arrays.perspective = validate_perspective; } void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want) { int dirty = c->transforms.dirty & want; // Validate the modelview if (dirty & transform_state_t::MODELVIEW) { c->transforms.modelview.validate(); } // Validate the projection stack (in fact, it's never needed) if (dirty & transform_state_t::PROJECTION) { c->transforms.projection.validate(); } // Validate the viewport transformation if (dirty & transform_state_t::VIEWPORT) { vp_transform_t& vpt = c->transforms.vpt; vpt.transform.matrix.load(vpt.matrix); vpt.transform.picker(); } // We need to update the mvp (used to transform each vertex) if (dirty & transform_state_t::MVP) { c->transforms.update_mvp(); // invalidate perspective (divide by W) and view volume clipping ogles_invalidate_perspective(c); } // Validate the mvui (for normal transformation) if (dirty & transform_state_t::MVUI) { c->transforms.update_mvui(); ogles_invalidate_lighting_mvui(c); } // Validate the texture stack if (dirty & transform_state_t::TEXTURE) { for (int i=0; itransforms.texture[i].validate(); } // Validate the mvit4 (user-clip planes) if (dirty & transform_state_t::MVIT) { c->transforms.update_mvit(); } c->transforms.dirty &= ~want; } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark transform_t #endif void transform_t::loadIdentity() { matrix = gIdentityx; flags = 0; ops = OP_IDENTITY; point2 = point2__nop; point3 = point3__nop; point4 = point4__nop; } static inline int notZero(GLfixed v) { return abs(v) & ~0x3; } static inline int notOne(GLfixed v) { return notZero(v - 0x10000); } void transform_t::picker() { const GLfixed* const m = matrix.m; // XXX: picker needs to be smarter flags = 0; ops = OP_ALL; point2 = point2__generic; point3 = point3__generic; point4 = point4__generic; // find out if this is a 2D projection if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) { flags |= FLAGS_2D_PROJECTION; } } void mvui_transform_t::picker() { flags = 0; ops = OP_ALL; point3 = point3__mvui; point4 = point4__mvui; } void transform_t::dump(const char* what) { GLfixed const * const m = matrix.m; ALOGD("%s:", what); for (int i=0 ; i<4 ; i++) ALOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n", m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)], fixedToFloat(m[I(0,i)]), fixedToFloat(m[I(1,i)]), fixedToFloat(m[I(2,i)]), fixedToFloat(m[I(3,i)])); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark matrixx_t #endif void matrixx_t::load(const matrixf_t& rhs) { GLfixed* xp = m; GLfloat const* fp = rhs.elements(); unsigned int i = 16; do { const GLfloat f = *fp++; *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f); } while (--i); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark matrixf_t #endif void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs) { GLfloat const* const m = lhs.m; for (int i=0 ; i<4 ; i++) { register const float rhs_i0 = rhs.m[ I(i,0) ]; register float ri0 = m[ I(0,0) ] * rhs_i0; register float ri1 = m[ I(0,1) ] * rhs_i0; register float ri2 = m[ I(0,2) ] * rhs_i0; register float ri3 = m[ I(0,3) ] * rhs_i0; for (int j=1 ; j<4 ; j++) { register const float rhs_ij = rhs.m[ I(i,j) ]; ri0 += m[ I(j,0) ] * rhs_ij; ri1 += m[ I(j,1) ] * rhs_ij; ri2 += m[ I(j,2) ] * rhs_ij; ri3 += m[ I(j,3) ] * rhs_ij; } r.m[ I(i,0) ] = ri0; r.m[ I(i,1) ] = ri1; r.m[ I(i,2) ] = ri2; r.m[ I(i,3) ] = ri3; } } void matrixf_t::dump(const char* what) { ALOGD("%s", what); ALOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]); ALOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]); ALOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]); ALOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]); } void matrixf_t::loadIdentity() { memcpy(m, gIdentityf, sizeof(m)); } void matrixf_t::set(const GLfixed* rhs) { load(rhs); } void matrixf_t::set(const GLfloat* rhs) { load(rhs); } void matrixf_t::load(const GLfixed* rhs) { GLfloat* fp = m; unsigned int i = 16; do { *fp++ = fixedToFloat(*rhs++); } while (--i); } void matrixf_t::load(const GLfloat* rhs) { memcpy(m, rhs, sizeof(m)); } void matrixf_t::load(const matrixf_t& rhs) { operator = (rhs); } void matrixf_t::multiply(const matrixf_t& rhs) { matrixf_t r; multiply(r, *this, rhs); operator = (r); } void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) { for (int i=0 ; i<4 ; i++) { m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z; } } void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) { for (int i=0 ; i<4 ; i++) { m[ i] *= x; m[4+i] *= y; m[8+i] *= z; } } void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) { matrixf_t rotation; GLfloat* r = rotation.m; GLfloat c, s; r[3] = 0; r[7] = 0; r[11]= 0; r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1; a *= GLfloat(M_PI / 180.0f); sincosf(a, &s, &c); if (isOnef(x) && isZerof(y) && isZerof(z)) { r[5] = c; r[10]= c; r[6] = s; r[9] = -s; r[1] = 0; r[2] = 0; r[4] = 0; r[8] = 0; r[0] = 1; } else if (isZerof(x) && isOnef(y) && isZerof(z)) { r[0] = c; r[10]= c; r[8] = s; r[2] = -s; r[1] = 0; r[4] = 0; r[6] = 0; r[9] = 0; r[5] = 1; } else if (isZerof(x) && isZerof(y) && isOnef(z)) { r[0] = c; r[5] = c; r[1] = s; r[4] = -s; r[2] = 0; r[6] = 0; r[8] = 0; r[9] = 0; r[10]= 1; } else { const GLfloat len = sqrtf(x*x + y*y + z*z); if (!isOnef(len)) { const GLfloat recipLen = reciprocalf(len); x *= recipLen; y *= recipLen; z *= recipLen; } const GLfloat nc = 1.0f - c; const GLfloat xy = x * y; const GLfloat yz = y * z; const GLfloat zx = z * x; const GLfloat xs = x * s; const GLfloat ys = y * s; const GLfloat zs = z * s; r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys; r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs; r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c; } multiply(rotation); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark matrix_stack_t #endif void matrix_stack_t::init(int depth) { stack = new matrixf_t[depth]; ops = new uint8_t[depth]; maxDepth = depth; depth = 0; dirty = 0; loadIdentity(); } void matrix_stack_t::uninit() { delete [] stack; delete [] ops; } void matrix_stack_t::loadIdentity() { transform.loadIdentity(); stack[depth].loadIdentity(); ops[depth] = OP_IDENTITY; } void matrix_stack_t::load(const GLfixed* rhs) { memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m)); stack[depth].load(rhs); ops[depth] = OP_ALL; // TODO: we should look at the matrix } void matrix_stack_t::load(const GLfloat* rhs) { stack[depth].load(rhs); ops[depth] = OP_ALL; // TODO: we should look at the matrix } void matrix_stack_t::multiply(const matrixf_t& rhs) { stack[depth].multiply(rhs); ops[depth] = OP_ALL; // TODO: we should look at the matrix } void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z) { stack[depth].translate(x,y,z); ops[depth] |= OP_TRANSLATE; } void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z) { stack[depth].scale(x,y,z); if (x==y && y==z) { ops[depth] |= OP_UNIFORM_SCALE; } else { ops[depth] |= OP_SCALE; } } void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) { stack[depth].rotate(a,x,y,z); ops[depth] |= OP_ROTATE; } void matrix_stack_t::validate() { if (dirty & DO_FLOAT_TO_FIXED) { transform.matrix.load(top()); } if (dirty & DO_PICKER) { transform.picker(); } dirty = 0; } GLint matrix_stack_t::push() { if (depth >= (maxDepth-1)) { return GL_STACK_OVERFLOW; } stack[depth+1] = stack[depth]; ops[depth+1] = ops[depth]; depth++; return 0; } GLint matrix_stack_t::pop() { if (depth == 0) { return GL_STACK_UNDERFLOW; } depth--; return 0; } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark vp_transform_t #endif void vp_transform_t::loadIdentity() { transform.loadIdentity(); matrix.loadIdentity(); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark transform_state_t #endif void transform_state_t::invalidate() { switch (matrixMode) { case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break; case GL_PROJECTION: dirty |= PROJECTION | MVP; break; case GL_TEXTURE: dirty |= TEXTURE | MVP; break; } current->dirty = matrix_stack_t::DO_PICKER | matrix_stack_t::DO_FLOAT_TO_FIXED; } void transform_state_t::update_mvp() { matrixf_t temp_mvp; matrixf_t::multiply(temp_mvp, projection.top(), modelview.top()); mvp4.matrix.load(temp_mvp); mvp4.picker(); if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) { // the mvp matrix doesn't transform W, in this case we can // premultiply it with the viewport transformation. In addition to // being more efficient, this is also much more accurate and in fact // is needed for 2D drawing with a resulting 1:1 mapping. matrixf_t mvpv; matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp); mvp.matrix.load(mvpv); mvp.picker(); } else { mvp = mvp4; } } static inline GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { return a*d - b*c; } static inline GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) { return b*c - a*d; } static __attribute__((noinline)) void invert(GLfloat* inverse, const GLfloat* src) { double t; int i, j, k, swap; GLfloat tmp[4][4]; memcpy(inverse, gIdentityf, sizeof(gIdentityf)); memcpy(tmp, src, sizeof(GLfloat)*16); for (i = 0; i < 4; i++) { // look for largest element in column swap = i; for (j = i + 1; j < 4; j++) { if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { swap = j; } } if (swap != i) { /* swap rows. */ for (k = 0; k < 4; k++) { t = tmp[i][k]; tmp[i][k] = tmp[swap][k]; tmp[swap][k] = t; t = inverse[i*4+k]; inverse[i*4+k] = inverse[swap*4+k]; inverse[swap*4+k] = t; } } t = 1.0f / tmp[i][i]; for (k = 0; k < 4; k++) { tmp[i][k] *= t; inverse[i*4+k] *= t; } for (j = 0; j < 4; j++) { if (j != i) { t = tmp[j][i]; for (k = 0; k < 4; k++) { tmp[j][k] -= tmp[i][k]*t; inverse[j*4+k] -= inverse[i*4+k]*t; } } } } } void transform_state_t::update_mvit() { GLfloat r[16]; const GLfloat* const mv = modelview.top().elements(); invert(r, mv); // convert to fixed-point and transpose GLfixed* const x = mvit4.matrix.m; for (int i=0 ; i<4 ; i++) for (int j=0 ; j<4 ; j++) x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); mvit4.picker(); } void transform_state_t::update_mvui() { GLfloat r[16]; const GLfloat* const mv = modelview.top().elements(); /* When evaluating the lighting equation in eye-space, normals are transformed by the upper 3x3 modelview inverse-transpose. http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html (note that inverse-transpose is distributive). Also note that: l(obj) = inv(modelview).l(eye) for local light l(obj) = tr(modelview).l(eye) for infinite light */ invert(r, mv); GLfixed* const x = mvui.matrix.m; #if OBJECT_SPACE_LIGHTING for (int i=0 ; i<4 ; i++) for (int j=0 ; j<4 ; j++) x[I(i,j)] = gglFloatToFixed(r[I(i,j)]); #else for (int i=0 ; i<4 ; i++) for (int j=0 ; j<4 ; j++) x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); #endif mvui.picker(); } // ---------------------------------------------------------------------------- // transformation and matrices API // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark transformation and matrices API #endif int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y) { c->viewport.surfaceport.x = x; c->viewport.surfaceport.y = y; ogles_viewport(c, c->viewport.x, c->viewport.y, c->viewport.w, c->viewport.h); ogles_scissor(c, c->viewport.scissor.x, c->viewport.scissor.y, c->viewport.scissor.w, c->viewport.scissor.h); return 0; } void ogles_scissor(ogles_context_t* c, GLint x, GLint y, GLsizei w, GLsizei h) { if ((w|h) < 0) { ogles_error(c, GL_INVALID_VALUE); return; } c->viewport.scissor.x = x; c->viewport.scissor.y = y; c->viewport.scissor.w = w; c->viewport.scissor.h = h; x += c->viewport.surfaceport.x; y += c->viewport.surfaceport.y; y = c->rasterizer.state.buffers.color.height - (y + h); c->rasterizer.procs.scissor(c, x, y, w, h); } void ogles_viewport(ogles_context_t* c, GLint x, GLint y, GLsizei w, GLsizei h) { if ((w|h)<0) { ogles_error(c, GL_INVALID_VALUE); return; } c->viewport.x = x; c->viewport.y = y; c->viewport.w = w; c->viewport.h = h; x += c->viewport.surfaceport.x; y += c->viewport.surfaceport.y; GLint H = c->rasterizer.state.buffers.color.height; GLfloat sx = div2f(w); GLfloat ox = sx + x; GLfloat sy = div2f(h); GLfloat oy = sy - y + (H - h); GLfloat near = c->transforms.vpt.zNear; GLfloat far = c->transforms.vpt.zFar; GLfloat A = div2f(far - near); GLfloat B = div2f(far + near); // compute viewport matrix GLfloat* const f = c->transforms.vpt.matrix.editElements(); f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox; f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy; f[2] = 0; f[6] = 0; f[10] = A; f[14] = B; f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1; c->transforms.dirty |= transform_state_t::VIEWPORT; if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) c->transforms.dirty |= transform_state_t::MVP; } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark matrix * vertex #endif void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { const GLfixed* const m = mx->matrix.m; const GLfixed rx = rhs->x; const GLfixed ry = rhs->y; lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]); lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]); lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]); lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]); } void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { const GLfixed* const m = mx->matrix.m; const GLfixed rx = rhs->x; const GLfixed ry = rhs->y; const GLfixed rz = rhs->z; lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); } void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { const GLfixed* const m = mx->matrix.m; const GLfixed rx = rhs->x; const GLfixed ry = rhs->y; const GLfixed rz = rhs->z; const GLfixed rw = rhs->w; lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]); } void point3__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { // this is used for transforming light positions back to object space. // w is used as a switch for directional lights, so we need // to preserve it. const GLfixed* const m = mx->matrix.m; const GLfixed rx = rhs->x; const GLfixed ry = rhs->y; const GLfixed rz = rhs->z; lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]); lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]); lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]); lhs->w = 0; } void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { // this is used for transforming light positions back to object space. // w is used as a switch for directional lights, so we need // to preserve it. const GLfixed* const m = mx->matrix.m; const GLfixed rx = rhs->x; const GLfixed ry = rhs->y; const GLfixed rz = rhs->z; const GLfixed rw = rhs->w; lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); lhs->w = rw; } void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { lhs->z = 0; lhs->w = 0x10000; if (lhs != rhs) { lhs->x = rhs->x; lhs->y = rhs->y; } } void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { lhs->w = 0x10000; if (lhs != rhs) { lhs->x = rhs->x; lhs->y = rhs->y; lhs->z = rhs->z; } } void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { if (lhs != rhs) *lhs = *rhs; } static void frustumf( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar, ogles_context_t* c) { if (cmpf(left,right) || cmpf(top, bottom) || cmpf(zNear, zFar) || isZeroOrNegativef(zNear) || isZeroOrNegativef(zFar)) { ogles_error(c, GL_INVALID_VALUE); return; } const GLfloat r_width = reciprocalf(right - left); const GLfloat r_height = reciprocalf(top - bottom); const GLfloat r_depth = reciprocalf(zNear - zFar); const GLfloat x = mul2f(zNear * r_width); const GLfloat y = mul2f(zNear * r_height); const GLfloat A = mul2f((right + left) * r_width); const GLfloat B = (top + bottom) * r_height; const GLfloat C = (zFar + zNear) * r_depth; const GLfloat D = mul2f(zFar * zNear * r_depth); GLfloat f[16]; f[ 0] = x; f[ 5] = y; f[ 8] = A; f[ 9] = B; f[10] = C; f[14] = D; f[11] = -1.0f; f[ 1] = f[ 2] = f[ 3] = f[ 4] = f[ 6] = f[ 7] = f[12] = f[13] = f[15] = 0.0f; matrixf_t rhs; rhs.set(f); c->transforms.current->multiply(rhs); c->transforms.invalidate(); } static void orthof( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar, ogles_context_t* c) { if (cmpf(left,right) || cmpf(top, bottom) || cmpf(zNear, zFar)) { ogles_error(c, GL_INVALID_VALUE); return; } const GLfloat r_width = reciprocalf(right - left); const GLfloat r_height = reciprocalf(top - bottom); const GLfloat r_depth = reciprocalf(zFar - zNear); const GLfloat x = mul2f(r_width); const GLfloat y = mul2f(r_height); const GLfloat z = -mul2f(r_depth); const GLfloat tx = -(right + left) * r_width; const GLfloat ty = -(top + bottom) * r_height; const GLfloat tz = -(zFar + zNear) * r_depth; GLfloat f[16]; f[ 0] = x; f[ 5] = y; f[10] = z; f[12] = tx; f[13] = ty; f[14] = tz; f[15] = 1.0f; f[ 1] = f[ 2] = f[ 3] = f[ 4] = f[ 6] = f[ 7] = f[ 8] = f[ 9] = f[11] = 0.0f; matrixf_t rhs; rhs.set(f); c->transforms.current->multiply(rhs); c->transforms.invalidate(); } static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c) { zNear = clampToZerof(zNear > 1 ? 1 : zNear); zFar = clampToZerof(zFar > 1 ? 1 : zFar); GLfloat* const f = c->transforms.vpt.matrix.editElements(); f[10] = div2f(zFar - zNear); f[14] = div2f(zFar + zNear); c->transforms.dirty |= transform_state_t::VIEWPORT; c->transforms.vpt.zNear = zNear; c->transforms.vpt.zFar = zFar; } // ---------------------------------------------------------------------------- }; // namespace android using namespace android; void glMatrixMode(GLenum mode) { ogles_context_t* c = ogles_context_t::get(); matrix_stack_t* stack = 0; switch (mode) { case GL_MODELVIEW: stack = &c->transforms.modelview; break; case GL_PROJECTION: stack = &c->transforms.projection; break; case GL_TEXTURE: stack = &c->transforms.texture[c->textures.active]; break; default: ogles_error(c, GL_INVALID_ENUM); return; } c->transforms.matrixMode = mode; c->transforms.current = stack; } void glLoadIdentity() { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->loadIdentity(); // also loads the GLfixed transform c->transforms.invalidate(); c->transforms.current->dirty = 0; } void glLoadMatrixf(const GLfloat* m) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->load(m); c->transforms.invalidate(); } void glLoadMatrixx(const GLfixed* m) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->load(m); // also loads the GLfixed transform c->transforms.invalidate(); c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED; } void glMultMatrixf(const GLfloat* m) { ogles_context_t* c = ogles_context_t::get(); matrixf_t rhs; rhs.set(m); c->transforms.current->multiply(rhs); c->transforms.invalidate(); } void glMultMatrixx(const GLfixed* m) { ogles_context_t* c = ogles_context_t::get(); matrixf_t rhs; rhs.set(m); c->transforms.current->multiply(rhs); c->transforms.invalidate(); } void glPopMatrix() { ogles_context_t* c = ogles_context_t::get(); GLint err = c->transforms.current->pop(); if (ggl_unlikely(err)) { ogles_error(c, err); return; } c->transforms.invalidate(); } void glPushMatrix() { ogles_context_t* c = ogles_context_t::get(); GLint err = c->transforms.current->push(); if (ggl_unlikely(err)) { ogles_error(c, err); return; } c->transforms.invalidate(); } void glFrustumf( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { ogles_context_t* c = ogles_context_t::get(); frustumf(left, right, bottom, top, zNear, zFar, c); } void glFrustumx( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { ogles_context_t* c = ogles_context_t::get(); frustumf( fixedToFloat(left), fixedToFloat(right), fixedToFloat(bottom), fixedToFloat(top), fixedToFloat(zNear), fixedToFloat(zFar), c); } void glOrthof( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { ogles_context_t* c = ogles_context_t::get(); orthof(left, right, bottom, top, zNear, zFar, c); } void glOrthox( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { ogles_context_t* c = ogles_context_t::get(); orthof( fixedToFloat(left), fixedToFloat(right), fixedToFloat(bottom), fixedToFloat(top), fixedToFloat(zNear), fixedToFloat(zFar), c); } void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->rotate(a, x, y, z); c->transforms.invalidate(); } void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->rotate( fixedToFloat(a), fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); c->transforms.invalidate(); } void glScalef(GLfloat x, GLfloat y, GLfloat z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->scale(x, y, z); c->transforms.invalidate(); } void glScalex(GLfixed x, GLfixed y, GLfixed z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->scale( fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); c->transforms.invalidate(); } void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->translate(x, y, z); c->transforms.invalidate(); } void glTranslatex(GLfixed x, GLfixed y, GLfixed z) { ogles_context_t* c = ogles_context_t::get(); c->transforms.current->translate( fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); c->transforms.invalidate(); } void glScissor(GLint x, GLint y, GLsizei w, GLsizei h) { ogles_context_t* c = ogles_context_t::get(); ogles_scissor(c, x, y, w, h); } void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) { ogles_context_t* c = ogles_context_t::get(); ogles_viewport(c, x, y, w, h); } void glDepthRangef(GLclampf zNear, GLclampf zFar) { ogles_context_t* c = ogles_context_t::get(); depthRangef(zNear, zFar, c); } void glDepthRangex(GLclampx zNear, GLclampx zFar) { ogles_context_t* c = ogles_context_t::get(); depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c); } void glPolygonOffsetx(GLfixed factor, GLfixed units) { ogles_context_t* c = ogles_context_t::get(); c->polygonOffset.factor = factor; c->polygonOffset.units = units; } void glPolygonOffset(GLfloat factor, GLfloat units) { ogles_context_t* c = ogles_context_t::get(); c->polygonOffset.factor = gglFloatToFixed(factor); c->polygonOffset.units = gglFloatToFixed(units); } GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e) { ogles_context_t* c = ogles_context_t::get(); GLbitfield status = 0; GLfloat const* f = c->transforms.current->top().elements(); for (int i=0 ; i<16 ; i++) { if (isnan(f[i]) || isinf(f[i])) { status |= 1< #include #include #include #include #include namespace android { const int OGLES_MODELVIEW_STACK_DEPTH = 16; const int OGLES_PROJECTION_STACK_DEPTH = 2; const int OGLES_TEXTURE_STACK_DEPTH = 2; void ogles_init_matrix(ogles_context_t*); void ogles_uninit_matrix(ogles_context_t*); void ogles_invalidate_perspective(ogles_context_t* c); void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want); int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y); void ogles_scissor(ogles_context_t* c, GLint x, GLint y, GLsizei w, GLsizei h); void ogles_viewport(ogles_context_t* c, GLint x, GLint y, GLsizei w, GLsizei h); inline void ogles_validate_transform( ogles_context_t* c, uint32_t want) { if (c->transforms.dirty & want) ogles_validate_transform_impl(c, want); } // ---------------------------------------------------------------------------- inline GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; int32_t t; asm( "smull %0, %1, %2, %2 \n" "smlal %0, %1, %3, %3 \n" "smlal %0, %1, %4, %4 \n" "movs %0, %0, lsr #16 \n" "adc %0, %0, %1, lsl #16 \n" : "=&r"(r), "=&r"(t) : "%r"(a), "r"(b), "r"(c) : "cc" ); return r; #elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GLfixed res; int32_t t1,t2,t3; asm( "mult %[a], %[a] \r\n" "li %[res],0x8000 \r\n" "madd %[b],%[b] \r\n" "move %[t3],$zero \r\n" "madd %[c],%[c] \r\n" "mflo %[t1]\r\n" "mfhi %[t2]\r\n" "addu %[t1],%[res],%[t1]\r\n" /*add 0x8000*/ "sltu %[t3],%[t1],%[res]\r\n" "addu %[t2],%[t2],%[t3]\r\n" "srl %[res],%[t1],16\r\n" "sll %[t2],%[t2],16\r\n" "or %[res],%[res],%[t2]\r\n" : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2),[t3]"=&r"(t3) : [a] "r" (a),[b] "r" (b),[c] "r" (c) : "%hi","%lo" ); return res; #else return (( int64_t(a)*a + int64_t(b)*b + int64_t(c)*c + 0x8000)>>16); #endif } static inline GLfixed mla2a( GLfixed a0, GLfixed b0, GLfixed a1, GLfixed b1, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; int32_t t; asm( "smull %0, %1, %2, %3 \n" "smlal %0, %1, %4, %5 \n" "add %0, %6, %0, lsr #16 \n" "add %0, %0, %1, lsl #16 \n" : "=&r"(r), "=&r"(t) : "%r"(a0), "r"(b0), "%r"(a1), "r"(b1), "r"(c) : ); return r; #else return (( int64_t(a0)*b0 + int64_t(a1)*b1)>>16) + c; #endif } static inline GLfixed mla3a( GLfixed a0, GLfixed b0, GLfixed a1, GLfixed b1, GLfixed a2, GLfixed b2, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; int32_t t; asm( "smull %0, %1, %2, %3 \n" "smlal %0, %1, %4, %5 \n" "smlal %0, %1, %6, %7 \n" "add %0, %8, %0, lsr #16 \n" "add %0, %0, %1, lsl #16 \n" : "=&r"(r), "=&r"(t) : "%r"(a0), "r"(b0), "%r"(a1), "r"(b1), "%r"(a2), "r"(b2), "r"(c) : ); return r; #elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GLfixed res; int32_t t1,t2; asm( "mult %[a0],%[b0] \r\n" "madd %[a1],%[b1] \r\n" "madd %[a2],%[b2] \r\n" "mflo %[t2]\r\n" "mfhi %[t1]\r\n" "srl %[t2],%[t2],16\r\n" "sll %[t1],%[t1],16\r\n" "or %[t2],%[t2],%[t1]\r\n" "addu %[res],%[t2],%[c]" : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2) : [a0] "r" (a0),[b0] "r" (b0),[a1] "r" (a1),[b1] "r" (b1),[a2] "r" (a2),[b2] "r" (b2),[c] "r" (c) : "%hi","%lo" ); return res; #else return (( int64_t(a0)*b0 + int64_t(a1)*b1 + int64_t(a2)*b2)>>16) + c; #endif } // b0, b1, b2 are signed 16-bit quanities // that have been shifted right by 'shift' bits relative to normal // S16.16 fixed point static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0, GLfixed a1, GLfixed a2, int32_t b2, GLint shift, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; asm( "smulwb %0, %1, %2 \n" "smlawt %0, %3, %2, %0 \n" "smlawb %0, %4, %5, %0 \n" "add %0, %7, %0, lsl %6 \n" : "=&r"(r) : "r"(a0), "r"(b1b0), "r"(a1), "r"(a2), "r"(b2), "r"(shift), "r"(c) : ); return r; #else int32_t accum; int16_t b0 = b1b0 & 0xffff; int16_t b1 = (b1b0 >> 16) & 0xffff; accum = int64_t(a0)*int16_t(b0) >> 16; accum += int64_t(a1)*int16_t(b1) >> 16; accum += int64_t(a2)*int16_t(b2) >> 16; accum = (accum << shift) + c; return accum; #endif } static inline GLfixed mla3a16_btb( GLfixed a0, GLfixed a1, GLfixed a2, int32_t b1b0, int32_t xxb2, GLint shift, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; asm( "smulwb %0, %1, %4 \n" "smlawt %0, %2, %4, %0 \n" "smlawb %0, %3, %5, %0 \n" "add %0, %7, %0, lsl %6 \n" : "=&r"(r) : "r"(a0), "r"(a1), "r"(a2), "r"(b1b0), "r"(xxb2), "r"(shift), "r"(c) : ); return r; #else int32_t accum; int16_t b0 = b1b0 & 0xffff; int16_t b1 = (b1b0 >> 16) & 0xffff; int16_t b2 = xxb2 & 0xffff; accum = int64_t(a0)*int16_t(b0) >> 16; accum += int64_t(a1)*int16_t(b1) >> 16; accum += int64_t(a2)*int16_t(b2) >> 16; accum = (accum << shift) + c; return accum; #endif } static inline GLfixed mla3a16_btt( GLfixed a0, GLfixed a1, GLfixed a2, int32_t b1b0, int32_t b2xx, GLint shift, GLfixed c) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; asm( "smulwb %0, %1, %4 \n" "smlawt %0, %2, %4, %0 \n" "smlawt %0, %3, %5, %0 \n" "add %0, %7, %0, lsl %6 \n" : "=&r"(r) : "r"(a0), "r"(a1), "r"(a2), "r"(b1b0), "r"(b2xx), "r"(shift), "r"(c) : ); return r; #else int32_t accum; int16_t b0 = b1b0 & 0xffff; int16_t b1 = (b1b0 >> 16) & 0xffff; int16_t b2 = (b2xx >> 16) & 0xffff; accum = int64_t(a0)*int16_t(b0) >> 16; accum += int64_t(a1)*int16_t(b1) >> 16; accum += int64_t(a2)*int16_t(b2) >> 16; accum = (accum << shift) + c; return accum; #endif } static inline GLfixed mla3( GLfixed a0, GLfixed b0, GLfixed a1, GLfixed b1, GLfixed a2, GLfixed b2) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; int32_t t; asm( "smull %0, %1, %2, %3 \n" "smlal %0, %1, %4, %5 \n" "smlal %0, %1, %6, %7 \n" "movs %0, %0, lsr #16 \n" "adc %0, %0, %1, lsl #16 \n" : "=&r"(r), "=&r"(t) : "%r"(a0), "r"(b0), "%r"(a1), "r"(b1), "%r"(a2), "r"(b2) : "cc" ); return r; #else return (( int64_t(a0)*b0 + int64_t(a1)*b1 + int64_t(a2)*b2 + 0x8000)>>16); #endif } static inline GLfixed mla4( GLfixed a0, GLfixed b0, GLfixed a1, GLfixed b1, GLfixed a2, GLfixed b2, GLfixed a3, GLfixed b3) { #if defined(__arm__) && !defined(__thumb__) GLfixed r; int32_t t; asm( "smull %0, %1, %2, %3 \n" "smlal %0, %1, %4, %5 \n" "smlal %0, %1, %6, %7 \n" "smlal %0, %1, %8, %9 \n" "movs %0, %0, lsr #16 \n" "adc %0, %0, %1, lsl #16 \n" : "=&r"(r), "=&r"(t) : "%r"(a0), "r"(b0), "%r"(a1), "r"(b1), "%r"(a2), "r"(b2), "%r"(a3), "r"(b3) : "cc" ); return r; #else return (( int64_t(a0)*b0 + int64_t(a1)*b1 + int64_t(a2)*b2 + int64_t(a3)*b3 + 0x8000)>>16); #endif } inline GLfixed dot4(const GLfixed* a, const GLfixed* b) { return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]); } inline GLfixed dot3(const GLfixed* a, const GLfixed* b) { return mla3(a[0], b[0], a[1], b[1], a[2], b[2]); } }; // namespace android #endif // ANDROID_OPENGLES_MATRIX_H opengl/libagl/mipmap.cpp0100644 0000000 0000000 00000016630 13077405420 014322 0ustar000000000 0000000 /* libs/opengles/mipmap.cpp ** ** Copyright 2006, 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 #include #include "context.h" #include "state.h" #include "texture.h" #include "TextureObjectManager.h" namespace android { // ---------------------------------------------------------------------------- status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex) { int level = 0; const GGLSurface* base = &tex->surface; const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]); int w = base->width; int h = base->height; if ((w&h) == 1) return NO_ERROR; w = (w>>1) ? : 1; h = (h>>1) ? : 1; while(true) { ++level; const int bpr = w * pixelFormat.size; if (tex->reallocate(level, w, h, w, base->format, base->compressedFormat, bpr) != NO_ERROR) { return NO_MEMORY; } int stride = w; int bs = base->stride; GGLSurface& cur = tex->editMip(level); if (base->format == GGL_PIXEL_FORMAT_RGB_565) { uint16_t const * src = (uint16_t const *)base->data; uint16_t* dst = (uint16_t*)cur.data; const uint32_t mask = 0x07E0F81F; for (int y=0 ; y> 2) & mask; uint32_t rgb = (grb & 0xFFFF) | (grb >> 16); dst[x + y*stride] = rgb; offset += 2; } } } else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551) { uint16_t const * src = (uint16_t const *)base->data; uint16_t* dst = (uint16_t*)cur.data; for (int y=0 ; y>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2; uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F; uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3; uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2; dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a; offset += 2; } } } else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888) { uint32_t const * src = (uint32_t const *)base->data; uint32_t* dst = (uint32_t*)cur.data; for (int y=0 ; y> 8) & 0x00FF00FF; uint32_t ga01 = (p01 >> 8) & 0x00FF00FF; uint32_t ga10 = (p10 >> 8) & 0x00FF00FF; uint32_t ga11 = (p11 >> 8) & 0x00FF00FF; uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2; uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2; uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8); dst[x + y*stride] = rgba; offset += 2; } } } else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) || (base->format == GGL_PIXEL_FORMAT_LA_88) || (base->format == GGL_PIXEL_FORMAT_A_8) || (base->format == GGL_PIXEL_FORMAT_L_8)) { int skip; switch (base->format) { case GGL_PIXEL_FORMAT_RGB_888: skip = 3; break; case GGL_PIXEL_FORMAT_LA_88: skip = 2; break; default: skip = 1; break; } uint8_t const * src = (uint8_t const *)base->data; uint8_t* dst = (uint8_t*)cur.data; bs *= skip; stride *= skip; for (int y=0 ; y> 2; } offset += 2*skip; } } } else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444) { uint16_t const * src = (uint16_t const *)base->data; uint16_t* dst = (uint16_t*)cur.data; for (int y=0 ; y> 2; uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0); dst[x + y*stride] = rgba; offset += 2; } } } else { ALOGE("Unsupported format (%d)", base->format); return BAD_TYPE; } // exit condition: we just processed the 1x1 LODs if ((w&h) == 1) break; base = &cur; w = (w>>1) ? : 1; h = (h>>1) ? : 1; } return NO_ERROR; } }; // namespace android opengl/libagl/primitives.cpp0100644 0000000 0000000 00000111352 13077405420 015227 0ustar000000000 0000000 /* libs/opengles/primitives.cpp ** ** Copyright 2006, 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 #include #include #include "context.h" #include "primitives.h" #include "light.h" #include "matrix.h" #include "vertex.h" #include "fp.h" #include "TextureObjectManager.h" extern "C" void iterators0032(const void* that, int32_t* it, int32_t c0, int32_t c1, int32_t c2); namespace android { // ---------------------------------------------------------------------------- static void primitive_point(ogles_context_t* c, vertex_t* v); static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1); static void primitive_clip_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void primitive_nop_point(ogles_context_t* c, vertex_t* v); static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1); static void primitive_nop_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static inline bool cull_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void lerp_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void lerp_texcoords(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void lerp_texcoords_w(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static void clip_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2); static unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p); // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif static void lightTriangleDarkSmooth(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { if (!(v0->flags & vertex_t::LIT)) { v0->flags |= vertex_t::LIT; const GLvoid* cp = c->arrays.color.element( v0->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v0->color.v, cp); } if (!(v1->flags & vertex_t::LIT)) { v1->flags |= vertex_t::LIT; const GLvoid* cp = c->arrays.color.element( v1->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v1->color.v, cp); } if(!(v2->flags & vertex_t::LIT)) { v2->flags |= vertex_t::LIT; const GLvoid* cp = c->arrays.color.element( v2->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v2->color.v, cp); } } static void lightTriangleDarkFlat(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2) { if (!(v2->flags & vertex_t::LIT)) { v2->flags |= vertex_t::LIT; const GLvoid* cp = c->arrays.color.element( v2->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v2->color.v, cp); } // configure the rasterizer here, before we clip c->rasterizer.procs.color4xv(c, v2->color.v); } static void lightTriangleSmooth(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { if (!(v0->flags & vertex_t::LIT)) c->lighting.lightVertex(c, v0); if (!(v1->flags & vertex_t::LIT)) c->lighting.lightVertex(c, v1); if(!(v2->flags & vertex_t::LIT)) c->lighting.lightVertex(c, v2); } static void lightTriangleFlat(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2) { if (!(v2->flags & vertex_t::LIT)) c->lighting.lightVertex(c, v2); // configure the rasterizer here, before we clip c->rasterizer.procs.color4xv(c, v2->color.v); } // The fog versions... static inline void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { v->flags |= vertex_t::LIT; v->fog = c->fog.fog(c, v->eye.z); const GLvoid* cp = c->arrays.color.element( v->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v->color.v, cp); } } static inline void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { v->flags |= vertex_t::LIT; v->fog = c->fog.fog(c, v->eye.z); } } static inline void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { v->fog = c->fog.fog(c, v->eye.z); c->lighting.lightVertex(c, v); } } static void lightTriangleDarkSmoothFog(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { lightVertexDarkSmoothFog(c, v0); lightVertexDarkSmoothFog(c, v1); lightVertexDarkSmoothFog(c, v2); } static void lightTriangleDarkFlatFog(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { lightVertexDarkFlatFog(c, v0); lightVertexDarkFlatFog(c, v1); lightVertexDarkSmoothFog(c, v2); // configure the rasterizer here, before we clip c->rasterizer.procs.color4xv(c, v2->color.v); } static void lightTriangleSmoothFog(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { lightVertexSmoothFog(c, v0); lightVertexSmoothFog(c, v1); lightVertexSmoothFog(c, v2); } static void lightTriangleFlatFog(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { lightVertexDarkFlatFog(c, v0); lightVertexDarkFlatFog(c, v1); lightVertexSmoothFog(c, v2); // configure the rasterizer here, before we clip c->rasterizer.procs.color4xv(c, v2->color.v); } typedef void (*light_primitive_t)(ogles_context_t*, vertex_t*, vertex_t*, vertex_t*); // fog 0x4, light 0x2, smooth 0x1 static const light_primitive_t lightPrimitive[8] = { lightTriangleDarkFlat, // no fog | dark | flat lightTriangleDarkSmooth, // no fog | dark | smooth lightTriangleFlat, // no fog | light | flat lightTriangleSmooth, // no fog | light | smooth lightTriangleDarkFlatFog, // fog | dark | flat lightTriangleDarkSmoothFog, // fog | dark | smooth lightTriangleFlatFog, // fog | light | flat lightTriangleSmoothFog // fog | light | smooth }; void ogles_validate_primitives(ogles_context_t* c) { const uint32_t enables = c->rasterizer.state.enables; // set up the lighting/shading/smoothing/fogging function int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0; index |= c->lighting.enable ? 0x2 : 0; index |= enables & GGL_ENABLE_FOG ? 0x4 : 0; c->lighting.lightTriangle = lightPrimitive[index]; // set up the primitive renderers if (ggl_likely(c->arrays.vertex.enable)) { c->prims.renderPoint = primitive_point; c->prims.renderLine = primitive_line; c->prims.renderTriangle = primitive_clip_triangle; } else { c->prims.renderPoint = primitive_nop_point; c->prims.renderLine = primitive_nop_line; c->prims.renderTriangle = primitive_nop_triangle; } } // ---------------------------------------------------------------------------- void compute_iterators_t::initTriangle( vertex_t const* v0, vertex_t const* v1, vertex_t const* v2) { m_dx01 = v1->window.x - v0->window.x; m_dy10 = v0->window.y - v1->window.y; m_dx20 = v0->window.x - v2->window.x; m_dy02 = v2->window.y - v0->window.y; m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; } void compute_iterators_t::initLine( vertex_t const* v0, vertex_t const* v1) { m_dx01 = m_dy02 = v1->window.x - v0->window.x; m_dy10 = m_dx20 = v0->window.y - v1->window.y; m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; } void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables) { m_x0 = v0->window.x; m_y0 = v0->window.y; const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS; const GGLcoord minArea = 2; // cannot be inverted // triangles with an area smaller than 1.0 are not smooth-shaded int q=0, s=0, d=0; if (abs(area) >= minArea) { // Here we do some voodoo magic, to compute a suitable scale // factor for deltas/area: // First compute the 1/area with full 32-bits precision, // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent. d = gglRecipQNormalized(area, &q); // Then compute the minimum left-shift to not overflow the muls // below. s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20)); // We'll keep 16-bits of precision for deltas/area. So we need // to shift everything left an extra 15 bits. s += 15; // make sure all final shifts are not > 32, because gglMulx // can't handle it. if (s < q) s = q; if (s > 32) { d >>= 32-s; s = 32; } } m_dx01 = gglMulx(m_dx01, d, s); m_dy10 = gglMulx(m_dy10, d, s); m_dx20 = gglMulx(m_dx20, d, s); m_dy02 = gglMulx(m_dy02, d, s); m_area_scale = 32 + q - s; m_scale = 0; if (enables & GGL_ENABLE_TMUS) { const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20)); const int B = gglClz(abs(m_x0)|abs(m_y0)); m_scale = max(0, 32 - (A + 16)) + max(0, 32 - (B + TRI_FRACTION_BITS)) + 1; } } int compute_iterators_t::iteratorsScale(GGLfixed* it, int32_t c0, int32_t c1, int32_t c2) const { int32_t dc01 = c1 - c0; int32_t dc02 = c2 - c0; const int A = gglClz(abs(c0)); const int B = gglClz(abs(dc01)|abs(dc02)); const int scale = min(A, B - m_scale) - 2; if (scale >= 0) { c0 <<= scale; dc01 <<= scale; dc02 <<= scale; } else { c0 >>= -scale; dc01 >>= -scale; dc02 >>= -scale; } const int s = m_area_scale; int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s); int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s); int32_t c = c0 - (gglMulAddx(dcdx, m_x0, gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS)); it[0] = c; it[1] = dcdx; it[2] = dcdy; return scale; } void compute_iterators_t::iterators1616(GGLfixed* it, GGLfixed c0, GGLfixed c1, GGLfixed c2) const { const GGLfixed dc01 = c1 - c0; const GGLfixed dc02 = c2 - c0; // 16.16 x 16.16 == 32.32 --> 16.16 const int s = m_area_scale; int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s); int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s); int32_t c = c0 - (gglMulAddx(dcdx, m_x0, gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS)); it[0] = c; it[1] = dcdx; it[2] = dcdy; } void compute_iterators_t::iterators0032(int64_t* it, int32_t c0, int32_t c1, int32_t c2) const { const int s = m_area_scale - 16; int32_t dc01 = (c1 - c0)>>s; int32_t dc02 = (c2 - c0)>>s; // 16.16 x 16.16 == 32.32 int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10); int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20); it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4); it[ 1] = dcdx; it[ 2] = dcdy; } #if defined(__arm__) && !defined(__thumb__) inline void compute_iterators_t::iterators0032(int32_t* it, int32_t c0, int32_t c1, int32_t c2) const { ::iterators0032(this, it, c0, c1, c2); } #else void compute_iterators_t::iterators0032(int32_t* it, int32_t c0, int32_t c1, int32_t c2) const { int64_t it64[3]; iterators0032(it64, c0, c1, c2); it[0] = it64[0]; it[1] = it64[1]; it[2] = it64[2]; } #endif // ---------------------------------------------------------------------------- static inline int32_t clampZ(GLfixed z) CONST; int32_t clampZ(GLfixed z) { z = (z & ~(z>>31)); if (z >= 0x10000) z = 0xFFFF; return z; } static __attribute__((noinline)) void fetch_texcoord_impl(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { vertex_t* const vtx[3] = { v0, v1, v2 }; array_t const * const texcoordArray = c->arrays.texture; for (int i=0 ; irasterizer.state.texture[i].enable)) continue; for (int j=0 ; j<3 ; j++) { vertex_t* const v = vtx[j]; if (v->flags & vertex_t::TT) continue; // NOTE: here we could compute automatic texgen // such as sphere/cube maps, instead of fetching them // from the textcoord array. vec4_t& coords = v->texture[i]; const GLubyte* tp = texcoordArray[i].element( v->index & vertex_cache_t::INDEX_MASK); texcoordArray[i].fetch(c, coords.v, tp); // transform texture coordinates... coords.Q = 0x10000; const transform_t& tr = c->transforms.texture[i].transform; if (ggl_unlikely(tr.ops)) { c->arrays.tex_transform[i](&tr, &coords, &coords); } // divide by Q const GGLfixed q = coords.Q; if (ggl_unlikely(q != 0x10000)) { const int32_t qinv = gglRecip28(q); coords.S = gglMulx(coords.S, qinv, 28); coords.T = gglMulx(coords.T, qinv, 28); } } } v0->flags |= vertex_t::TT; v1->flags |= vertex_t::TT; v2->flags |= vertex_t::TT; } inline void fetch_texcoord(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { const uint32_t enables = c->rasterizer.state.enables; if (!(enables & GGL_ENABLE_TMUS)) return; // Fetch & transform texture coordinates... if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) { // already done for all three vertices, bail... return; } fetch_texcoord_impl(c, v0, v1, v2); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Point #endif void primitive_nop_point(ogles_context_t*, vertex_t*) { } void primitive_point(ogles_context_t* c, vertex_t* v) { // lighting & clamping... const uint32_t enables = c->rasterizer.state.enables; if (ggl_unlikely(!(v->flags & vertex_t::LIT))) { if (c->lighting.enable) { c->lighting.lightVertex(c, v); } else { v->flags |= vertex_t::LIT; const GLvoid* cp = c->arrays.color.element( v->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v->color.v, cp); } if (enables & GGL_ENABLE_FOG) { v->fog = c->fog.fog(c, v->eye.z); } } // XXX: we don't need to do that each-time // if color array and lighting not enabled c->rasterizer.procs.color4xv(c, v->color.v); // XXX: look into ES point-sprite extension if (enables & GGL_ENABLE_TMUS) { fetch_texcoord(c, v,v,v); for (int i=0 ; irasterizer.state.texture[i].enable) continue; int32_t itt[8]; itt[1] = itt[2] = itt[4] = itt[5] = 0; itt[6] = itt[7] = 16; // XXX: check that if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) { int width = c->textures.tmu[i].texture->surface.width; itt[0] = v->texture[i].S * width; itt[6] = 0; } if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) { int height = c->textures.tmu[i].texture->surface.height; itt[3] = v->texture[i].T * height; itt[7] = 0; } c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); } } if (enables & GGL_ENABLE_DEPTH_TEST) { int32_t itz[3]; itz[0] = clampZ(v->window.z) * 0x00010001; itz[1] = itz[2] = 0; c->rasterizer.procs.zGrad3xv(c, itz); } if (enables & GGL_ENABLE_FOG) { GLfixed itf[3]; itf[0] = v->fog; itf[1] = itf[2] = 0; c->rasterizer.procs.fogGrad3xv(c, itf); } // Render our point... c->rasterizer.procs.pointx(c, v->window.v, c->point.size); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Line #endif void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) { } void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1) { // get texture coordinates fetch_texcoord(c, v0, v1, v1); // light/shade the vertices first (they're copied below) c->lighting.lightTriangle(c, v0, v1, v1); // clip the line if needed if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) { unsigned int count = clip_line(c, v0, v1); if (ggl_unlikely(count == 0)) return; } // compute iterators... const uint32_t enables = c->rasterizer.state.enables; const uint32_t mask = GGL_ENABLE_TMUS | GGL_ENABLE_SMOOTH | GGL_ENABLE_W | GGL_ENABLE_FOG | GGL_ENABLE_DEPTH_TEST; if (ggl_unlikely(enables & mask)) { c->lerp.initLine(v0, v1); lerp_triangle(c, v0, v1, v0); } // render our line c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Triangle #endif void primitive_nop_triangle(ogles_context_t* /*c*/, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) { } void primitive_clip_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL; if (ggl_likely(!cc)) { // code below must be as optimized as possible, this is the // common code path. // This triangle is not clipped, test if it's culled // unclipped triangle... c->lerp.initTriangle(v0, v1, v2); if (cull_triangle(c, v0, v1, v2)) return; // culled! // Fetch all texture coordinates if needed fetch_texcoord(c, v0, v1, v2); // light (or shade) our triangle! c->lighting.lightTriangle(c, v0, v1, v2); triangle(c, v0, v1, v2); return; } // The assumption here is that we're not going to clip very often, // and even more rarely will we clip a triangle that ends up // being culled out. So it's okay to light the vertices here, even though // in a few cases we won't render the triangle (if culled). // Fetch texture coordinates... fetch_texcoord(c, v0, v1, v2); // light (or shade) our triangle! c->lighting.lightTriangle(c, v0, v1, v2); clip_triangle(c, v0, v1, v2); } // ----------------------------------------------------------------------- void triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { // compute iterators... const uint32_t enables = c->rasterizer.state.enables; const uint32_t mask = GGL_ENABLE_TMUS | GGL_ENABLE_SMOOTH | GGL_ENABLE_W | GGL_ENABLE_FOG | GGL_ENABLE_DEPTH_TEST; if (ggl_likely(enables & mask)) lerp_triangle(c, v0, v1, v2); c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v); } void lerp_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { const uint32_t enables = c->rasterizer.state.enables; c->lerp.initLerp(v0, enables); // set up texture iterators if (enables & GGL_ENABLE_TMUS) { if (enables & GGL_ENABLE_W) { lerp_texcoords_w(c, v0, v1, v2); } else { lerp_texcoords(c, v0, v1, v2); } } // set up the color iterators const compute_iterators_t& lerp = c->lerp; if (enables & GGL_ENABLE_SMOOTH) { GLfixed itc[12]; for (int i=0 ; i<4 ; i++) { const GGLcolor c0 = v0->color.v[i] * 255; const GGLcolor c1 = v1->color.v[i] * 255; const GGLcolor c2 = v2->color.v[i] * 255; lerp.iterators1616(&itc[i*3], c0, c1, c2); } c->rasterizer.procs.colorGrad12xv(c, itc); } if (enables & GGL_ENABLE_DEPTH_TEST) { int32_t itz[3]; const int32_t v0z = clampZ(v0->window.z); const int32_t v1z = clampZ(v1->window.z); const int32_t v2z = clampZ(v2->window.z); if (ggl_unlikely(c->polygonOffset.enable)) { const int32_t units = (c->polygonOffset.units << 16); const GLfixed factor = c->polygonOffset.factor; if (factor) { int64_t itz64[3]; lerp.iterators0032(itz64, v0z, v1z, v2z); int64_t maxDepthSlope = max(itz64[1], itz64[2]); itz[0] = uint32_t(itz64[0]) + uint32_t((maxDepthSlope*factor)>>16) + units; itz[1] = uint32_t(itz64[1]); itz[2] = uint32_t(itz64[2]); } else { lerp.iterators0032(itz, v0z, v1z, v2z); itz[0] += units; } } else { lerp.iterators0032(itz, v0z, v1z, v2z); } c->rasterizer.procs.zGrad3xv(c, itz); } if (ggl_unlikely(enables & GGL_ENABLE_FOG)) { GLfixed itf[3]; lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog); c->rasterizer.procs.fogGrad3xv(c, itf); } } static inline int compute_lod(ogles_context_t* c, int i, int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2) { // Compute mipmap level / primitive // rho = sqrt( texelArea / area ) // lod = log2( rho ) // lod = log2( texelArea / area ) / 2 // lod = (log2( texelArea ) - log2( area )) / 2 const compute_iterators_t& lerp = c->lerp; const GGLcoord area = abs(lerp.area()); const int w = c->textures.tmu[i].texture->surface.width; const int h = c->textures.tmu[i].texture->surface.height; const int shift = 16 + (16 - TRI_FRACTION_BITS); int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) - gglMulx(s2-s0, t1-t0, shift) )*w*h; int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea); int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area); int lod = (log2TArea - log2Area + 1) >> 1; return lod; } void lerp_texcoords(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { const compute_iterators_t& lerp = c->lerp; int32_t itt[8] __attribute__((aligned(16))); for (int i=0 ; irasterizer.state.texture[i]; if (!tmu.enable) continue; // compute the jacobians using block floating-point int32_t s0 = v0->texture[i].S; int32_t t0 = v0->texture[i].T; int32_t s1 = v1->texture[i].S; int32_t t1 = v1->texture[i].T; int32_t s2 = v2->texture[i].S; int32_t t2 = v2->texture[i].T; const GLenum min_filter = c->textures.tmu[i].texture->min_filter; if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) { int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2); c->rasterizer.procs.bindTextureLod(c, i, &c->textures.tmu[i].texture->mip(lod)); } // premultiply (s,t) when clampling if (tmu.s_wrap == GGL_CLAMP) { const int width = tmu.surface.width; s0 *= width; s1 *= width; s2 *= width; } if (tmu.t_wrap == GGL_CLAMP) { const int height = tmu.surface.height; t0 *= height; t1 *= height; t2 *= height; } itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2); itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2); c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); } } void lerp_texcoords_w(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { const compute_iterators_t& lerp = c->lerp; int32_t itt[8] __attribute__((aligned(16))); int32_t itw[3]; // compute W's scale to 2.30 int32_t w0 = v0->window.w; int32_t w1 = v1->window.w; int32_t w2 = v2->window.w; int wscale = 32 - gglClz(w0|w1|w2); // compute the jacobian using block floating-point int sc = lerp.iteratorsScale(itw, w0, w1, w2); sc += wscale - 16; c->rasterizer.procs.wGrad3xv(c, itw); for (int i=0 ; irasterizer.state.texture[i]; if (!tmu.enable) continue; // compute the jacobians using block floating-point int32_t s0 = v0->texture[i].S; int32_t t0 = v0->texture[i].T; int32_t s1 = v1->texture[i].S; int32_t t1 = v1->texture[i].T; int32_t s2 = v2->texture[i].S; int32_t t2 = v2->texture[i].T; const GLenum min_filter = c->textures.tmu[i].texture->min_filter; if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) { int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2); c->rasterizer.procs.bindTextureLod(c, i, &c->textures.tmu[i].texture->mip(lod)); } // premultiply (s,t) when clampling if (tmu.s_wrap == GGL_CLAMP) { const int width = tmu.surface.width; s0 *= width; s1 *= width; s2 *= width; } if (tmu.t_wrap == GGL_CLAMP) { const int height = tmu.surface.height; t0 *= height; t1 *= height; t2 *= height; } s0 = gglMulx(s0, w0, wscale); t0 = gglMulx(t0, w0, wscale); s1 = gglMulx(s1, w1, wscale); t1 = gglMulx(t1, w1, wscale); s2 = gglMulx(s2, w2, wscale); t2 = gglMulx(t2, w2, wscale); itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2); itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2); c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); } } static inline bool cull_triangle(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) { if (ggl_likely(c->cull.enable)) { const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW; const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK; if (face == c->cull.cullFace) return true; // culled! } return false; } static inline GLfixed frustumPlaneDist(int plane, const vec4_t& s) { const GLfixed d = s.v[ plane >> 1 ]; return ((plane & 1) ? (s.w - d) : (s.w + d)); } static inline int32_t clipDivide(GLfixed a, GLfixed b) { // returns a 4.28 fixed-point return gglMulDivi(1LU<<28, a, b); } void clip_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2) { uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL; vertex_t *p0, *p1, *p2; const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES; const int MAX_VERTICES = 3; // Temporary buffer to hold the new vertices. Each plane can add up to // two new vertices (because the polygon is convex). // We need one extra element, to handle an overflow case when // the polygon degenerates into something non convex. vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB vertex_t* buf = buffer; // original list of vertices (polygon to clip, in fact this // function works with an arbitrary polygon). vertex_t* in[3] = { v0, v1, v2 }; // output lists (we need 2, which we use back and forth) // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES) // 2 more elements for overflow when non convex polygons. vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2]; unsigned int outi = 0; // current input list vertex_t** ivl = in; // 3 input vertices, 0 in the output list, first plane unsigned int ic = 3; // User clip-planes first, the clipping is always done in eye-coordinate // this is basically the same algorithm than for the view-volume // clipping, except for the computation of the distance (vertex, plane) // and the fact that we need to compute the eye-coordinates of each // new vertex we create. if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL)) { unsigned int plane = 0; uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8; do { if (cc & 1) { // pointers to our output list (head and current) vertex_t** const ovl = &out[outi][0]; vertex_t** output = ovl; unsigned int oc = 0; unsigned int sentinel = 0; // previous vertex, compute distance to the plane vertex_t* s = ivl[ic-1]; const vec4_t& equation = c->clipPlanes.plane[plane].equation; GLfixed sd = dot4(equation.v, s->eye.v); // clip each vertex against this plane... for (unsigned int i=0 ; ieye.v); if (sd >= 0) { if (pd >= 0) { // both inside *output++ = p; oc++; } else { // s inside, p outside (exiting) const GLfixed t = clipDivide(sd, sd-pd); c->arrays.clipEye(c, buf, t, p, s); *output++ = buf++; oc++; if (++sentinel >= 3) return; // non-convex polygon! } } else { if (pd >= 0) { // s outside (entering) if (pd) { const GLfixed t = clipDivide(pd, pd-sd); c->arrays.clipEye(c, buf, t, s, p); *output++ = buf++; oc++; if (++sentinel >= 3) return; // non-convex polygon! } *output++ = p; oc++; } else { // both outside } } s = p; sd = pd; } // output list become the new input list if (oc<3) return; // less than 3 vertices left? we're done! ivl = ovl; ic = oc; outi = 1-outi; } cc >>= 1; plane++; } while (cc); } // frustum clip-planes if (all_cc & vertex_t::FRUSTUM_CLIP_ALL) { unsigned int plane = 0; uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL; do { if (cc & 1) { // pointers to our output list (head and current) vertex_t** const ovl = &out[outi][0]; vertex_t** output = ovl; unsigned int oc = 0; unsigned int sentinel = 0; // previous vertex, compute distance to the plane vertex_t* s = ivl[ic-1]; GLfixed sd = frustumPlaneDist(plane, s->clip); // clip each vertex against this plane... for (unsigned int i=0 ; iclip); if (sd >= 0) { if (pd >= 0) { // both inside *output++ = p; oc++; } else { // s inside, p outside (exiting) const GLfixed t = clipDivide(sd, sd-pd); c->arrays.clipVertex(c, buf, t, p, s); *output++ = buf++; oc++; if (++sentinel >= 3) return; // non-convex polygon! } } else { if (pd >= 0) { // s outside (entering) if (pd) { const GLfixed t = clipDivide(pd, pd-sd); c->arrays.clipVertex(c, buf, t, s, p); *output++ = buf++; oc++; if (++sentinel >= 3) return; // non-convex polygon! } *output++ = p; oc++; } else { // both outside } } s = p; sd = pd; } // output list become the new input list if (oc<3) return; // less than 3 vertices left? we're done! ivl = ovl; ic = oc; outi = 1-outi; } cc >>= 1; plane++; } while (cc); } // finally we can render our triangles... p0 = ivl[0]; p1 = ivl[1]; for (unsigned int i=2 ; ilerp.initTriangle(p0, p1, p2); if (cull_triangle(c, p0, p1, p2)) { p1 = p2; continue; // culled! } triangle(c, p0, p1, p2); p1 = p2; } } unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p) { const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL; if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL)) { unsigned int plane = 0; uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8; do { if (cc & 1) { const vec4_t& equation = c->clipPlanes.plane[plane].equation; const GLfixed sd = dot4(equation.v, s->eye.v); const GLfixed pd = dot4(equation.v, p->eye.v); if (sd >= 0) { if (pd >= 0) { // both inside } else { // s inside, p outside (exiting) const GLfixed t = clipDivide(sd, sd-pd); c->arrays.clipEye(c, p, t, p, s); } } else { if (pd >= 0) { // s outside (entering) if (pd) { const GLfixed t = clipDivide(pd, pd-sd); c->arrays.clipEye(c, s, t, s, p); } } else { // both outside return 0; } } } cc >>= 1; plane++; } while (cc); } // frustum clip-planes if (all_cc & vertex_t::FRUSTUM_CLIP_ALL) { unsigned int plane = 0; uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL; do { if (cc & 1) { const GLfixed sd = frustumPlaneDist(plane, s->clip); const GLfixed pd = frustumPlaneDist(plane, p->clip); if (sd >= 0) { if (pd >= 0) { // both inside } else { // s inside, p outside (exiting) const GLfixed t = clipDivide(sd, sd-pd); c->arrays.clipVertex(c, p, t, p, s); } } else { if (pd >= 0) { // s outside (entering) if (pd) { const GLfixed t = clipDivide(pd, pd-sd); c->arrays.clipVertex(c, s, t, s, p); } } else { // both outside return 0; } } } cc >>= 1; plane++; } while (cc); } return 2; } }; // namespace android opengl/libagl/primitives.h0100644 0000000 0000000 00000001723 13077405420 014674 0ustar000000000 0000000 /* libs/opengles/primitives.h ** ** Copyright 2006, 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_OPENGLES_PRIMITIVES_H #define ANDROID_OPENGLES_PRIMITIVES_H #include #include #include namespace android { namespace gl { struct ogles_context_t; }; void ogles_validate_primitives(ogles_context_t* c); }; // namespace android #endif // ANDROID_OPENGLES_PRIMITIVES_H opengl/libagl/state.cpp0100644 0000000 0000000 00000041724 13077405420 014161 0ustar000000000 0000000 /* libs/opengles/state.cpp ** ** Copyright 2006, 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 #include "context.h" #include "fp.h" #include "state.h" #include "array.h" #include "matrix.h" #include "vertex.h" #include "light.h" #include "texture.h" #include "BufferObjectManager.h" #include "TextureObjectManager.h" namespace android { // ---------------------------------------------------------------------------- static char const * const gVendorString = "Android"; static char const * const gRendererString = "Android PixelFlinger 1.4"; static char const * const gVersionString = "OpenGL ES-CM 1.0"; static char const * const gExtensionsString = "GL_OES_byte_coordinates " // OK "GL_OES_fixed_point " // OK "GL_OES_single_precision " // OK "GL_OES_read_format " // OK "GL_OES_compressed_paletted_texture " // OK "GL_OES_draw_texture " // OK "GL_OES_matrix_get " // OK "GL_OES_query_matrix " // OK // "GL_OES_point_size_array " // TODO // "GL_OES_point_sprite " // TODO "GL_OES_EGL_image " // OK "GL_OES_EGL_sync " // OK #ifdef GL_OES_compressed_ETC1_RGB8_texture "GL_OES_compressed_ETC1_RGB8_texture " // OK #endif "GL_ARB_texture_compression " // OK "GL_ARB_texture_non_power_of_two " // OK "GL_ANDROID_user_clip_plane " // OK "GL_ANDROID_vertex_buffer_object " // OK "GL_ANDROID_generate_mipmap " // OK ; // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif ogles_context_t *ogles_init(size_t extra) { void* const base = malloc(extra + sizeof(ogles_context_t) + 32); if (!base) return 0; ogles_context_t *c = (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL); memset(c, 0, sizeof(ogles_context_t)); ggl_init_context(&(c->rasterizer)); // XXX: this should be passed as an argument sp smgr(new EGLSurfaceManager()); c->surfaceManager = smgr.get(); c->surfaceManager->incStrong(c); sp bomgr(new EGLBufferObjectManager()); c->bufferObjectManager = bomgr.get(); c->bufferObjectManager->incStrong(c); ogles_init_array(c); ogles_init_matrix(c); ogles_init_vertex(c); ogles_init_light(c); ogles_init_texture(c); c->rasterizer.base = base; c->point.size = TRI_ONE; c->line.width = TRI_ONE; // in OpenGL, writing to the depth buffer is enabled by default. c->rasterizer.procs.depthMask(c, 1); // OpenGL enables dithering by default c->rasterizer.procs.enable(c, GL_DITHER); return c; } void ogles_uninit(ogles_context_t* c) { ogles_uninit_array(c); ogles_uninit_matrix(c); ogles_uninit_vertex(c); ogles_uninit_light(c); ogles_uninit_texture(c); c->surfaceManager->decStrong(c); c->bufferObjectManager->decStrong(c); ggl_uninit_context(&(c->rasterizer)); free(c->rasterizer.base); } void _ogles_error(ogles_context_t* c, GLenum error) { if (c->error == GL_NO_ERROR) c->error = error; } static bool stencilop_valid(GLenum op) { switch (op) { case GL_KEEP: case GL_ZERO: case GL_REPLACE: case GL_INCR: case GL_DECR: case GL_INVERT: return true; } return false; } static void enable_disable(ogles_context_t* c, GLenum cap, int enabled) { if ((cap >= GL_LIGHT0) && (caplighting.lights[cap-GL_LIGHT0].enable = enabled; c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0)); c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0)); return; } switch (cap) { case GL_POINT_SMOOTH: c->point.smooth = enabled; break; case GL_LINE_SMOOTH: c->line.smooth = enabled; break; case GL_POLYGON_OFFSET_FILL: c->polygonOffset.enable = enabled; break; case GL_CULL_FACE: c->cull.enable = enabled; break; case GL_LIGHTING: c->lighting.enable = enabled; break; case GL_COLOR_MATERIAL: c->lighting.colorMaterial.enable = enabled; break; case GL_NORMALIZE: case GL_RESCALE_NORMAL: c->transforms.rescaleNormals = enabled ? cap : 0; // XXX: invalidate mvit break; case GL_CLIP_PLANE0: case GL_CLIP_PLANE1: case GL_CLIP_PLANE2: case GL_CLIP_PLANE3: case GL_CLIP_PLANE4: case GL_CLIP_PLANE5: c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0)); c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0)); ogles_invalidate_perspective(c); break; case GL_FOG: case GL_DEPTH_TEST: ogles_invalidate_perspective(c); // fall-through... case GL_BLEND: case GL_SCISSOR_TEST: case GL_ALPHA_TEST: case GL_COLOR_LOGIC_OP: case GL_DITHER: case GL_STENCIL_TEST: case GL_TEXTURE_2D: // these need to fall through into the rasterizer c->rasterizer.procs.enableDisable(c, cap, enabled); break; case GL_TEXTURE_EXTERNAL_OES: c->rasterizer.procs.enableDisable(c, GL_TEXTURE_2D, enabled); break; case GL_MULTISAMPLE: case GL_SAMPLE_ALPHA_TO_COVERAGE: case GL_SAMPLE_ALPHA_TO_ONE: case GL_SAMPLE_COVERAGE: // not supported in this implementation break; default: ogles_error(c, GL_INVALID_ENUM); return; } } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- using namespace android; #if 0 #pragma mark - #endif // These ones are super-easy, we're not supporting those features! void glSampleCoverage(GLclampf /*value*/, GLboolean /*invert*/) { } void glSampleCoveragex(GLclampx /*value*/, GLboolean /*invert*/) { } void glStencilFunc(GLenum func, GLint /*ref*/, GLuint /*mask*/) { ogles_context_t* c = ogles_context_t::get(); if (func < GL_NEVER || func > GL_ALWAYS) { ogles_error(c, GL_INVALID_ENUM); return; } // from OpenGL|ES 1.0 sepcification: // If there is no stencil buffer, no stencil modification can occur // and it is as if the stencil test always passes. } void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { ogles_context_t* c = ogles_context_t::get(); if ((stencilop_valid(fail) & stencilop_valid(zfail) & stencilop_valid(zpass)) == 0) { ogles_error(c, GL_INVALID_ENUM); return; } } // ---------------------------------------------------------------------------- void glAlphaFunc(GLenum func, GLclampf ref) { glAlphaFuncx(func, gglFloatToFixed(ref)); } void glCullFace(GLenum mode) { ogles_context_t* c = ogles_context_t::get(); switch (mode) { case GL_FRONT: case GL_BACK: case GL_FRONT_AND_BACK: break; default: ogles_error(c, GL_INVALID_ENUM); } c->cull.cullFace = mode; } void glFrontFace(GLenum mode) { ogles_context_t* c = ogles_context_t::get(); switch (mode) { case GL_CW: case GL_CCW: break; default: ogles_error(c, GL_INVALID_ENUM); return; } c->cull.frontFace = mode; } void glHint(GLenum target, GLenum mode) { ogles_context_t* c = ogles_context_t::get(); switch (target) { case GL_FOG_HINT: case GL_GENERATE_MIPMAP_HINT: case GL_LINE_SMOOTH_HINT: break; case GL_POINT_SMOOTH_HINT: c->rasterizer.procs.enableDisable(c, GGL_POINT_SMOOTH_NICE, mode==GL_NICEST); break; case GL_PERSPECTIVE_CORRECTION_HINT: c->perspective = (mode == GL_NICEST) ? 1 : 0; break; default: ogles_error(c, GL_INVALID_ENUM); } } void glEnable(GLenum cap) { ogles_context_t* c = ogles_context_t::get(); enable_disable(c, cap, 1); } void glDisable(GLenum cap) { ogles_context_t* c = ogles_context_t::get(); enable_disable(c, cap, 0); } void glFinish() { // nothing to do for our software implementation } void glFlush() { // nothing to do for our software implementation } GLenum glGetError() { // From OpenGL|ES 1.0 specification: // If more than one flag has recorded an error, glGetError returns // and clears an arbitrary error flag value. Thus, glGetError should // always be called in a loop, until it returns GL_NO_ERROR, // if all error flags are to be reset. ogles_context_t* c = ogles_context_t::get(); if (c->error) { const GLenum ret(c->error); c->error = 0; return ret; } if (c->rasterizer.error) { const GLenum ret(c->rasterizer.error); c->rasterizer.error = 0; return ret; } return GL_NO_ERROR; } const GLubyte* glGetString(GLenum string) { switch (string) { case GL_VENDOR: return (const GLubyte*)gVendorString; case GL_RENDERER: return (const GLubyte*)gRendererString; case GL_VERSION: return (const GLubyte*)gVersionString; case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString; } ogles_context_t* c = ogles_context_t::get(); ogles_error(c, GL_INVALID_ENUM); return 0; } void glGetIntegerv(GLenum pname, GLint *params) { int i; ogles_context_t* c = ogles_context_t::get(); switch (pname) { case GL_ALIASED_POINT_SIZE_RANGE: params[0] = 0; params[1] = GGL_MAX_ALIASED_POINT_SIZE; break; case GL_ALIASED_LINE_WIDTH_RANGE: params[0] = 0; params[1] = GGL_MAX_ALIASED_POINT_SIZE; break; case GL_ALPHA_BITS: { int index = c->rasterizer.state.buffers.color.format; GGLFormat const * formats = gglGetPixelFormatTable(); params[0] = formats[index].ah - formats[index].al; break; } case GL_RED_BITS: { int index = c->rasterizer.state.buffers.color.format; GGLFormat const * formats = gglGetPixelFormatTable(); params[0] = formats[index].rh - formats[index].rl; break; } case GL_GREEN_BITS: { int index = c->rasterizer.state.buffers.color.format; GGLFormat const * formats = gglGetPixelFormatTable(); params[0] = formats[index].gh - formats[index].gl; break; } case GL_BLUE_BITS: { int index = c->rasterizer.state.buffers.color.format; GGLFormat const * formats = gglGetPixelFormatTable(); params[0] = formats[index].bh - formats[index].bl; break; } case GL_COMPRESSED_TEXTURE_FORMATS: params[ 0] = GL_PALETTE4_RGB8_OES; params[ 1] = GL_PALETTE4_RGBA8_OES; params[ 2] = GL_PALETTE4_R5_G6_B5_OES; params[ 3] = GL_PALETTE4_RGBA4_OES; params[ 4] = GL_PALETTE4_RGB5_A1_OES; params[ 5] = GL_PALETTE8_RGB8_OES; params[ 6] = GL_PALETTE8_RGBA8_OES; params[ 7] = GL_PALETTE8_R5_G6_B5_OES; params[ 8] = GL_PALETTE8_RGBA4_OES; params[ 9] = GL_PALETTE8_RGB5_A1_OES; i = 10; #ifdef GL_OES_compressed_ETC1_RGB8_texture params[i++] = GL_ETC1_RGB8_OES; #endif break; case GL_DEPTH_BITS: params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16; break; case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: params[0] = GL_RGB; break; case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: params[0] = GL_UNSIGNED_SHORT_5_6_5; break; case GL_MAX_LIGHTS: params[0] = OGLES_MAX_LIGHTS; break; case GL_MAX_CLIP_PLANES: params[0] = OGLES_MAX_CLIP_PLANES; break; case GL_MAX_MODELVIEW_STACK_DEPTH: params[0] = OGLES_MODELVIEW_STACK_DEPTH; break; case GL_MAX_PROJECTION_STACK_DEPTH: params[0] = OGLES_PROJECTION_STACK_DEPTH; break; case GL_MAX_TEXTURE_STACK_DEPTH: params[0] = OGLES_TEXTURE_STACK_DEPTH; break; case GL_MAX_TEXTURE_SIZE: params[0] = GGL_MAX_TEXTURE_SIZE; break; case GL_MAX_TEXTURE_UNITS: params[0] = GGL_TEXTURE_UNIT_COUNT; break; case GL_MAX_VIEWPORT_DIMS: params[0] = GGL_MAX_VIEWPORT_DIMS; params[1] = GGL_MAX_VIEWPORT_DIMS; break; case GL_NUM_COMPRESSED_TEXTURE_FORMATS: params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS; break; case GL_SMOOTH_LINE_WIDTH_RANGE: params[0] = 0; params[1] = GGL_MAX_SMOOTH_LINE_WIDTH; break; case GL_SMOOTH_POINT_SIZE_RANGE: params[0] = 0; params[1] = GGL_MAX_SMOOTH_POINT_SIZE; break; case GL_STENCIL_BITS: params[0] = 0; break; case GL_SUBPIXEL_BITS: params[0] = GGL_SUBPIXEL_BITS; break; case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES: memcpy( params, c->transforms.modelview.top().elements(), 16*sizeof(GLint)); break; case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES: memcpy( params, c->transforms.projection.top().elements(), 16*sizeof(GLint)); break; case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES: memcpy( params, c->transforms.texture[c->textures.active].top().elements(), 16*sizeof(GLint)); break; default: ogles_error(c, GL_INVALID_ENUM); break; } } // ---------------------------------------------------------------------------- void glPointSize(GLfloat size) { ogles_context_t* c = ogles_context_t::get(); if (size <= 0) { ogles_error(c, GL_INVALID_ENUM); return; } c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size)); } void glPointSizex(GLfixed size) { ogles_context_t* c = ogles_context_t::get(); if (size <= 0) { ogles_error(c, GL_INVALID_ENUM); return; } c->point.size = TRI_FROM_FIXED(size); } // ---------------------------------------------------------------------------- void glLineWidth(GLfloat width) { ogles_context_t* c = ogles_context_t::get(); if (width <= 0) { ogles_error(c, GL_INVALID_ENUM); return; } c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width)); } void glLineWidthx(GLfixed width) { ogles_context_t* c = ogles_context_t::get(); if (width <= 0) { ogles_error(c, GL_INVALID_ENUM); return; } c->line.width = TRI_FROM_FIXED(width); } // ---------------------------------------------------------------------------- void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.colorMask(c, r, g, b, a); } void glDepthMask(GLboolean flag) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.depthMask(c, flag); } void glStencilMask(GLuint mask) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.stencilMask(c, mask); } void glDepthFunc(GLenum func) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.depthFunc(c, func); } void glLogicOp(GLenum opcode) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.logicOp(c, opcode); } void glAlphaFuncx(GLenum func, GLclampx ref) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.alphaFuncx(c, func, ref); } void glBlendFunc(GLenum sfactor, GLenum dfactor) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.blendFunc(c, sfactor, dfactor); } void glClear(GLbitfield mask) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clear(c, mask); } void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clearColorx(c, red, green, blue, alpha); } void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clearColorx(c, gglFloatToFixed(r), gglFloatToFixed(g), gglFloatToFixed(b), gglFloatToFixed(a)); } void glClearDepthx(GLclampx depth) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clearDepthx(c, depth); } void glClearDepthf(GLclampf depth) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth)); } void glClearStencil(GLint s) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.clearStencil(c, s); } opengl/libagl/state.h0100644 0000000 0000000 00000002576 13077405420 013630 0ustar000000000 0000000 /* libs/opengles/state.h ** ** Copyright 2006, 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_OPENGLES_STATE_H #define ANDROID_OPENGLES_STATE_H #include #include #include #include #include #include namespace android { ogles_context_t *ogles_init(size_t extra); void ogles_uninit(ogles_context_t* c); void _ogles_error(ogles_context_t* c, GLenum error); #ifndef TRACE_GL_ERRORS #define TRACE_GL_ERRORS 0 #endif #if TRACE_GL_ERRORS #define ogles_error(c, error) \ do { \ printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \ _ogles_error(c, error); \ } while (0) #else /* !TRACE_GL_ERRORS */ #define ogles_error(c, error) _ogles_error((c), (error)) #endif }; // namespace android #endif // ANDROID_OPENGLES_STATE_H opengl/libagl/texture.cpp0100644 0000000 0000000 00000146422 13077405420 014542 0ustar000000000 0000000 /* libs/opengles/texture.cpp ** ** Copyright 2006, 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 #include #include "context.h" #include "fp.h" #include "state.h" #include "texture.h" #include "TextureObjectManager.h" #include namespace android { // ---------------------------------------------------------------------------- static void bindTextureTmu( ogles_context_t* c, int tmu, GLuint texture, const sp& tex); static __attribute__((noinline)) void generateMipmap(ogles_context_t* c, GLint level); // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Init #endif void ogles_init_texture(ogles_context_t* c) { c->textures.packAlignment = 4; c->textures.unpackAlignment = 4; // each context has a default named (0) texture (not shared) c->textures.defaultTexture = new EGLTextureObject(); c->textures.defaultTexture->incStrong(c); // bind the default texture to each texture unit for (int i=0; itextures.defaultTexture); memset(c->current.texture[i].v, 0, sizeof(vec4_t)); c->current.texture[i].Q = 0x10000; } } void ogles_uninit_texture(ogles_context_t* c) { if (c->textures.ggl) gglUninit(c->textures.ggl); c->textures.defaultTexture->decStrong(c); for (int i=0; itextures.tmu[i].texture) c->textures.tmu[i].texture->decStrong(c); } } static __attribute__((noinline)) void validate_tmu(ogles_context_t* c, int i) { texture_unit_t& u(c->textures.tmu[i]); if (u.dirty) { u.dirty = 0; c->rasterizer.procs.activeTexture(c, i); c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); c->rasterizer.procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); c->rasterizer.procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, u.texture->wraps); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, u.texture->wrapt); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_MIN_FILTER, u.texture->min_filter); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter); // disable this texture unit if it's not complete if (!u.texture->isComplete()) { c->rasterizer.procs.disable(c, GGL_TEXTURE_2D); } } } void ogles_validate_texture(ogles_context_t* c) { for (int i=0 ; irasterizer.state.texture[i].enable) validate_tmu(c, i); } c->rasterizer.procs.activeTexture(c, c->textures.active); } static void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) { c->textures.tmu[tmu].dirty = flags; } /* * If the active textures are EGLImage, they need to be locked before * they can be used. * * FIXME: code below is far from being optimal * */ void ogles_lock_textures(ogles_context_t* c) { for (int i=0 ; irasterizer.state.texture[i].enable) { texture_unit_t& u(c->textures.tmu[i]); ANativeWindowBuffer* native_buffer = u.texture->buffer; if (native_buffer) { c->rasterizer.procs.activeTexture(c, i); hw_module_t const* pModule; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule)) continue; gralloc_module_t const* module = reinterpret_cast(pModule); void* vaddr; int err = module->lock(module, native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0, native_buffer->width, native_buffer->height, &vaddr); u.texture->setImageBits(vaddr); c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); } } } } void ogles_unlock_textures(ogles_context_t* c) { for (int i=0 ; irasterizer.state.texture[i].enable) { texture_unit_t& u(c->textures.tmu[i]); ANativeWindowBuffer* native_buffer = u.texture->buffer; if (native_buffer) { c->rasterizer.procs.activeTexture(c, i); hw_module_t const* pModule; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule)) continue; gralloc_module_t const* module = reinterpret_cast(pModule); module->unlock(module, native_buffer->handle); u.texture->setImageBits(NULL); c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); } } } c->rasterizer.procs.activeTexture(c, c->textures.active); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Format conversion #endif static uint32_t gl2format_table[6][4] = { // BYTE, 565, 4444, 5551 { GGL_PIXEL_FORMAT_A_8, 0, 0, 0 }, // GL_ALPHA { GGL_PIXEL_FORMAT_RGB_888, GGL_PIXEL_FORMAT_RGB_565, 0, 0 }, // GL_RGB { GGL_PIXEL_FORMAT_RGBA_8888, 0, GGL_PIXEL_FORMAT_RGBA_4444, GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA { GGL_PIXEL_FORMAT_L_8, 0, 0, 0 }, // GL_LUMINANCE { GGL_PIXEL_FORMAT_LA_88, 0, 0, 0 }, // GL_LUMINANCE_ALPHA }; static int32_t convertGLPixelFormat(GLint format, GLenum type) { int32_t fi = -1; int32_t ti = -1; switch (format) { case GL_ALPHA: fi = 0; break; case GL_RGB: fi = 1; break; case GL_RGBA: fi = 2; break; case GL_LUMINANCE: fi = 3; break; case GL_LUMINANCE_ALPHA: fi = 4; break; } switch (type) { case GL_UNSIGNED_BYTE: ti = 0; break; case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break; case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break; case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break; } if (fi==-1 || ti==-1) return 0; return gl2format_table[fi][ti]; } // ---------------------------------------------------------------------------- static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type) { GLenum error = 0; if (formatGL_LUMINANCE_ALPHA) { error = GL_INVALID_ENUM; } if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 && type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) { error = GL_INVALID_ENUM; } if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) { error = GL_INVALID_OPERATION; } if ((type == GL_UNSIGNED_SHORT_4_4_4_4 || type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) { error = GL_INVALID_OPERATION; } if (error) { ogles_error(c, error); } return error; } // ---------------------------------------------------------------------------- GGLContext* getRasterizer(ogles_context_t* c) { GGLContext* ggl = c->textures.ggl; if (ggl_unlikely(!ggl)) { // this is quite heavy the first time... gglInit(&ggl); if (!ggl) { return 0; } GGLfixed colors[4] = { 0, 0, 0, 0x10000 }; c->textures.ggl = ggl; ggl->activeTexture(ggl, 0); ggl->enable(ggl, GGL_TEXTURE_2D); ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE); ggl->disable(ggl, GGL_DITHER); ggl->shadeModel(ggl, GGL_FLAT); ggl->color4xv(ggl, colors); } return ggl; } static __attribute__((noinline)) int copyPixels( ogles_context_t* c, const GGLSurface& dst, GLint xoffset, GLint yoffset, const GGLSurface& src, GLint x, GLint y, GLsizei w, GLsizei h) { if ((dst.format == src.format) && (dst.stride == src.stride) && (dst.width == src.width) && (dst.height == src.height) && (dst.stride > 0) && ((x|y) == 0) && ((xoffset|yoffset) == 0)) { // this is a common case... const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]); const size_t size = src.height * src.stride * pixelFormat.size; memcpy(dst.data, src.data, size); return 0; } // use pixel-flinger to handle all the conversions GGLContext* ggl = getRasterizer(c); if (!ggl) { // the only reason this would fail is because we ran out of memory return GL_OUT_OF_MEMORY; } ggl->colorBuffer(ggl, &dst); ggl->bindTexture(ggl, &src); ggl->texCoord2i(ggl, x-xoffset, y-yoffset); ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h); return 0; } // ---------------------------------------------------------------------------- static __attribute__((noinline)) sp getAndBindActiveTextureObject(ogles_context_t* c) { sp tex; const int active = c->textures.active; const GLuint name = c->textures.tmu[active].name; // free the reference to the previously bound object texture_unit_t& u(c->textures.tmu[active]); if (u.texture) u.texture->decStrong(c); if (name == 0) { // 0 is our local texture object, not shared with anyone. // But it affects all bound TMUs immediately. // (we need to invalidate all units bound to this texture object) tex = c->textures.defaultTexture; for (int i=0 ; itextures.tmu[i].texture == tex.get()) invalidate_texture(c, i); } } else { // get a new texture object for that name tex = c->surfaceManager->replaceTexture(name); } // bind this texture to the current active texture unit // and add a reference to this texture object u.texture = tex.get(); u.texture->incStrong(c); u.name = name; invalidate_texture(c, active); return tex; } void bindTextureTmu( ogles_context_t* c, int tmu, GLuint texture, const sp& tex) { if (tex.get() == c->textures.tmu[tmu].texture) return; // free the reference to the previously bound object texture_unit_t& u(c->textures.tmu[tmu]); if (u.texture) u.texture->decStrong(c); // bind this texture to the current active texture unit // and add a reference to this texture object u.texture = tex.get(); u.texture->incStrong(c); u.name = texture; invalidate_texture(c, tmu); } int createTextureSurface(ogles_context_t* c, GGLSurface** outSurface, int32_t* outSize, GLint level, GLenum format, GLenum type, GLsizei width, GLsizei height, GLenum compressedFormat = 0) { // find out which texture is bound to the current unit const int active = c->textures.active; const GLuint name = c->textures.tmu[active].name; // convert the pixelformat to one we can handle const int32_t formatIdx = convertGLPixelFormat(format, type); if (formatIdx == 0) { // we don't know what to do with this return GL_INVALID_OPERATION; } // figure out the size we need as well as the stride const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); const int32_t align = c->textures.unpackAlignment-1; const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; const size_t size = bpr * height; const int32_t stride = bpr / pixelFormat.size; if (level > 0) { const int active = c->textures.active; EGLTextureObject* tex = c->textures.tmu[active].texture; status_t err = tex->reallocate(level, width, height, stride, formatIdx, compressedFormat, bpr); if (err != NO_ERROR) return GL_OUT_OF_MEMORY; GGLSurface& surface = tex->editMip(level); *outSurface = &surface; *outSize = size; return 0; } sp tex = getAndBindActiveTextureObject(c); status_t err = tex->reallocate(level, width, height, stride, formatIdx, compressedFormat, bpr); if (err != NO_ERROR) return GL_OUT_OF_MEMORY; tex->internalformat = format; *outSurface = &tex->surface; *outSize = size; return 0; } static size_t dataSizePalette4(int numLevels, int width, int height, int format) { int indexBits = 8; int entrySize = 0; switch (format) { case GL_PALETTE4_RGB8_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_RGB8_OES: entrySize = 3; break; case GL_PALETTE4_RGBA8_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_RGBA8_OES: entrySize = 4; break; case GL_PALETTE4_R5_G6_B5_OES: case GL_PALETTE4_RGBA4_OES: case GL_PALETTE4_RGB5_A1_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_R5_G6_B5_OES: case GL_PALETTE8_RGBA4_OES: case GL_PALETTE8_RGB5_A1_OES: entrySize = 2; break; } size_t size = (1 << indexBits) * entrySize; // palette size for (int i=0 ; i< numLevels ; i++) { int w = (width >> i) ? : 1; int h = (height >> i) ? : 1; int levelSize = h * ((w * indexBits) / 8) ? : 1; size += levelSize; } return size; } static void decodePalette4(const GLvoid *data, int level, int width, int height, void *surface, int stride, int format) { int indexBits = 8; int entrySize = 0; switch (format) { case GL_PALETTE4_RGB8_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_RGB8_OES: entrySize = 3; break; case GL_PALETTE4_RGBA8_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_RGBA8_OES: entrySize = 4; break; case GL_PALETTE4_R5_G6_B5_OES: case GL_PALETTE4_RGBA4_OES: case GL_PALETTE4_RGB5_A1_OES: indexBits = 4; /* FALLTHROUGH */ case GL_PALETTE8_R5_G6_B5_OES: case GL_PALETTE8_RGBA4_OES: case GL_PALETTE8_RGB5_A1_OES: entrySize = 2; break; } const int paletteSize = (1 << indexBits) * entrySize; uint8_t const* pixels = (uint8_t *)data + paletteSize; for (int i=0 ; i> i) ? : 1; int h = (height >> i) ? : 1; pixels += h * ((w * indexBits) / 8); } width = (width >> level) ? : 1; height = (height >> level) ? : 1; if (entrySize == 2) { uint8_t const* const palette = (uint8_t*)data; for (int y=0 ; y> 4); *p++ = palette[index + 0]; *p++ = palette[index + 1]; if (x+1 < width) { index = 2 * (v & 0xF); *p++ = palette[index + 0]; *p++ = palette[index + 1]; } } } } } else if (entrySize == 3) { uint8_t const* const palette = (uint8_t*)data; for (int y=0 ; y> 4); *p++ = palette[index + 0]; *p++ = palette[index + 1]; *p++ = palette[index + 2]; if (x+1 < width) { index = 3 * (v & 0xF); *p++ = palette[index + 0]; *p++ = palette[index + 1]; *p++ = palette[index + 2]; } } } } } else if (entrySize == 4) { uint8_t const* const palette = (uint8_t*)data; for (int y=0 ; y> 4); *p++ = palette[index + 0]; *p++ = palette[index + 1]; *p++ = palette[index + 2]; *p++ = palette[index + 3]; if (x+1 < width) { index = 4 * (v & 0xF); *p++ = palette[index + 0]; *p++ = palette[index + 1]; *p++ = palette[index + 2]; *p++ = palette[index + 3]; } } } } } } static __attribute__((noinline)) void set_depth_and_fog(ogles_context_t* c, GGLfixed z) { const uint32_t enables = c->rasterizer.state.enables; // we need to compute Zw int32_t iterators[3]; iterators[1] = iterators[2] = 0; GGLfixed Zw; GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear); GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar); if (z<=0) Zw = n; else if (z>=0x10000) Zw = f; else Zw = gglMulAddx(z, (f-n), n); if (enables & GGL_ENABLE_FOG) { // set up fog if needed... iterators[0] = c->fog.fog(c, Zw); c->rasterizer.procs.fogGrad3xv(c, iterators); } if (enables & GGL_ENABLE_DEPTH_TEST) { // set up z-test if needed... int32_t z = (Zw & ~(Zw>>31)); if (z >= 0x10000) z = 0xFFFF; iterators[0] = (z << 16) | z; c->rasterizer.procs.zGrad3xv(c, iterators); } } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark Generate mimaps #endif extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex); void generateMipmap(ogles_context_t* c, GLint level) { if (level == 0) { const int active = c->textures.active; EGLTextureObject* tex = c->textures.tmu[active].texture; if (tex->generate_mipmap) { if (buildAPyramid(c, tex) != NO_ERROR) { ogles_error(c, GL_OUT_OF_MEMORY); return; } } } } static void texParameterx( GLenum target, GLenum pname, GLfixed param, ogles_context_t* c) { if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { ogles_error(c, GL_INVALID_ENUM); return; } EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; switch (pname) { case GL_TEXTURE_WRAP_S: if ((param == GL_REPEAT) || (param == GL_CLAMP_TO_EDGE)) { textureObject->wraps = param; } else { goto invalid_enum; } break; case GL_TEXTURE_WRAP_T: if ((param == GL_REPEAT) || (param == GL_CLAMP_TO_EDGE)) { textureObject->wrapt = param; } else { goto invalid_enum; } break; case GL_TEXTURE_MIN_FILTER: if ((param == GL_NEAREST) || (param == GL_LINEAR) || (param == GL_NEAREST_MIPMAP_NEAREST) || (param == GL_LINEAR_MIPMAP_NEAREST) || (param == GL_NEAREST_MIPMAP_LINEAR) || (param == GL_LINEAR_MIPMAP_LINEAR)) { textureObject->min_filter = param; } else { goto invalid_enum; } break; case GL_TEXTURE_MAG_FILTER: if ((param == GL_NEAREST) || (param == GL_LINEAR)) { textureObject->mag_filter = param; } else { goto invalid_enum; } break; case GL_GENERATE_MIPMAP: textureObject->generate_mipmap = param; break; default: invalid_enum: ogles_error(c, GL_INVALID_ENUM); return; } invalidate_texture(c, c->textures.active); } static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, ogles_context_t* c) { ogles_lock_textures(c); const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; y = gglIntToFixed(cbSurface.height) - (y + h); w >>= FIXED_BITS; h >>= FIXED_BITS; // set up all texture units for (int i=0 ; irasterizer.state.texture[i].enable) continue; int32_t texcoords[8]; texture_unit_t& u(c->textures.tmu[i]); // validate this tmu (bind, wrap, filter) validate_tmu(c, i); // we CLAMP here, which works with premultiplied (s,t) c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP); u.dirty = 0xFF; // XXX: should be more subtle EGLTextureObject* textureObject = u.texture; const GLint Ucr = textureObject->crop_rect[0] << 16; const GLint Vcr = textureObject->crop_rect[1] << 16; const GLint Wcr = textureObject->crop_rect[2] << 16; const GLint Hcr = textureObject->crop_rect[3] << 16; // computes texture coordinates (pre-multiplied) int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy texcoords[0] = s0; texcoords[1] = dsdx; texcoords[2] = 0; texcoords[3] = t0; texcoords[4] = 0; texcoords[5] = dtdy; texcoords[6] = 0; texcoords[7] = 0; c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords); } const uint32_t enables = c->rasterizer.state.enables; if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) set_depth_and_fog(c, z); c->rasterizer.procs.activeTexture(c, c->textures.active); c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); c->rasterizer.procs.disable(c, GGL_W_LERP); c->rasterizer.procs.disable(c, GGL_AA); c->rasterizer.procs.shadeModel(c, GL_FLAT); c->rasterizer.procs.recti(c, gglFixedToIntRound(x), gglFixedToIntRound(y), gglFixedToIntRound(x)+w, gglFixedToIntRound(y)+h); ogles_unlock_textures(c); } static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, ogles_context_t* c) { // quickly reject empty rects if ((w|h) <= 0) return; drawTexxOESImp(x, y, z, w, h, c); } static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c) { // All coordinates are integer, so if we have only one // texture unit active and no scaling is required // THEN, we can use our special 1:1 mapping // which is a lot faster. if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) { const int tmu = 0; texture_unit_t& u(c->textures.tmu[tmu]); EGLTextureObject* textureObject = u.texture; const GLint Wcr = textureObject->crop_rect[2]; const GLint Hcr = textureObject->crop_rect[3]; if ((w == Wcr) && (h == -Hcr)) { if ((w|h) <= 0) return; // quickly reject empty rects if (u.dirty) { c->rasterizer.procs.activeTexture(c, tmu); c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_MIN_FILTER, u.texture->min_filter); c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter); } c->rasterizer.procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); c->rasterizer.procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); u.dirty = 0xFF; // XXX: should be more subtle c->rasterizer.procs.activeTexture(c, c->textures.active); const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; y = cbSurface.height - (y + h); const GLint Ucr = textureObject->crop_rect[0]; const GLint Vcr = textureObject->crop_rect[1]; const GLint s0 = Ucr - x; const GLint t0 = (Vcr + Hcr) - y; const GLuint tw = textureObject->surface.width; const GLuint th = textureObject->surface.height; if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) { // The GL spec is unclear about what should happen // in this case, so we just use the slow case, which // at least won't crash goto slow_case; } ogles_lock_textures(c); c->rasterizer.procs.texCoord2i(c, s0, t0); const uint32_t enables = c->rasterizer.state.enables; if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) set_depth_and_fog(c, gglIntToFixed(z)); c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); c->rasterizer.procs.disable(c, GGL_W_LERP); c->rasterizer.procs.disable(c, GGL_AA); c->rasterizer.procs.shadeModel(c, GL_FLAT); c->rasterizer.procs.recti(c, x, y, x+w, y+h); ogles_unlock_textures(c); return; } } slow_case: drawTexxOESImp( gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z), gglIntToFixed(w), gglIntToFixed(h), c); } }; // namespace android // ---------------------------------------------------------------------------- using namespace android; #if 0 #pragma mark - #pragma mark Texture API #endif void glActiveTexture(GLenum texture) { ogles_context_t* c = ogles_context_t::get(); if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { ogles_error(c, GL_INVALID_ENUM); return; } c->textures.active = texture - GL_TEXTURE0; c->rasterizer.procs.activeTexture(c, c->textures.active); } void glBindTexture(GLenum target, GLuint texture) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { ogles_error(c, GL_INVALID_ENUM); return; } // Bind or create a texture sp tex; if (texture == 0) { // 0 is our local texture object tex = c->textures.defaultTexture; } else { tex = c->surfaceManager->texture(texture); if (ggl_unlikely(tex == 0)) { tex = c->surfaceManager->createTexture(texture); if (tex == 0) { ogles_error(c, GL_OUT_OF_MEMORY); return; } } } bindTextureTmu(c, c->textures.active, texture, tex); } void glGenTextures(GLsizei n, GLuint *textures) { ogles_context_t* c = ogles_context_t::get(); if (n<0) { ogles_error(c, GL_INVALID_VALUE); return; } // generate unique (shared) texture names c->surfaceManager->getToken(n, textures); } void glDeleteTextures(GLsizei n, const GLuint *textures) { ogles_context_t* c = ogles_context_t::get(); if (n<0) { ogles_error(c, GL_INVALID_VALUE); return; } // If deleting a bound texture, bind this unit to 0 for (int t=0 ; ttextures.tmu[t].name == 0) continue; for (int i=0 ; itextures.tmu[t].name)) { // bind this tmu to texture 0 sp tex(c->textures.defaultTexture); bindTextureTmu(c, t, 0, tex); } } } c->surfaceManager->deleteTextures(n, textures); c->surfaceManager->recycleTokens(n, textures); } void glMultiTexCoord4f( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { ogles_context_t* c = ogles_context_t::get(); if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { ogles_error(c, GL_INVALID_ENUM); return; } const int tmu = target-GL_TEXTURE0; c->current.texture[tmu].S = gglFloatToFixed(s); c->current.texture[tmu].T = gglFloatToFixed(t); c->current.texture[tmu].R = gglFloatToFixed(r); c->current.texture[tmu].Q = gglFloatToFixed(q); } void glMultiTexCoord4x( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { ogles_context_t* c = ogles_context_t::get(); if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { ogles_error(c, GL_INVALID_ENUM); return; } const int tmu = target-GL_TEXTURE0; c->current.texture[tmu].S = s; c->current.texture[tmu].T = t; c->current.texture[tmu].R = r; c->current.texture[tmu].Q = q; } void glPixelStorei(GLenum pname, GLint param) { ogles_context_t* c = ogles_context_t::get(); if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) { ogles_error(c, GL_INVALID_ENUM); return; } if ((param<=0 || param>8) || (param & (param-1))) { ogles_error(c, GL_INVALID_VALUE); return; } if (pname == GL_PACK_ALIGNMENT) c->textures.packAlignment = param; if (pname == GL_UNPACK_ALIGNMENT) c->textures.unpackAlignment = param; } void glTexEnvf(GLenum target, GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.texEnvi(c, target, pname, GLint(param)); } void glTexEnvfv( GLenum target, GLenum pname, const GLfloat *params) { ogles_context_t* c = ogles_context_t::get(); if (pname == GL_TEXTURE_ENV_MODE) { c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params)); return; } if (pname == GL_TEXTURE_ENV_COLOR) { GGLfixed fixed[4]; for (int i=0 ; i<4 ; i++) fixed[i] = gglFloatToFixed(params[i]); c->rasterizer.procs.texEnvxv(c, target, pname, fixed); return; } ogles_error(c, GL_INVALID_ENUM); } void glTexEnvx(GLenum target, GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.texEnvi(c, target, pname, param); } void glTexEnvxv( GLenum target, GLenum pname, const GLfixed *params) { ogles_context_t* c = ogles_context_t::get(); c->rasterizer.procs.texEnvxv(c, target, pname, params); } void glTexParameteriv( GLenum target, GLenum pname, const GLint* params) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { ogles_error(c, GL_INVALID_ENUM); return; } EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; switch (pname) { case GL_TEXTURE_CROP_RECT_OES: memcpy(textureObject->crop_rect, params, 4*sizeof(GLint)); break; default: texParameterx(target, pname, GLfixed(params[0]), c); return; } } void glTexParameterf( GLenum target, GLenum pname, GLfloat param) { ogles_context_t* c = ogles_context_t::get(); texParameterx(target, pname, GLfixed(param), c); } void glTexParameterx( GLenum target, GLenum pname, GLfixed param) { ogles_context_t* c = ogles_context_t::get(); texParameterx(target, pname, param, c); } void glTexParameteri( GLenum target, GLenum pname, GLint param) { ogles_context_t* c = ogles_context_t::get(); texParameterx(target, pname, GLfixed(param), c); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #endif void glCompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } if (width<0 || height<0 || border!=0) { ogles_error(c, GL_INVALID_VALUE); return; } // "uncompress" the texture since pixelflinger doesn't support // any compressed texture format natively. GLenum format; GLenum type; switch (internalformat) { case GL_PALETTE8_RGB8_OES: case GL_PALETTE4_RGB8_OES: format = GL_RGB; type = GL_UNSIGNED_BYTE; break; case GL_PALETTE8_RGBA8_OES: case GL_PALETTE4_RGBA8_OES: format = GL_RGBA; type = GL_UNSIGNED_BYTE; break; case GL_PALETTE8_R5_G6_B5_OES: case GL_PALETTE4_R5_G6_B5_OES: format = GL_RGB; type = GL_UNSIGNED_SHORT_5_6_5; break; case GL_PALETTE8_RGBA4_OES: case GL_PALETTE4_RGBA4_OES: format = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; break; case GL_PALETTE8_RGB5_A1_OES: case GL_PALETTE4_RGB5_A1_OES: format = GL_RGBA; type = GL_UNSIGNED_SHORT_5_5_5_1; break; #ifdef GL_OES_compressed_ETC1_RGB8_texture case GL_ETC1_RGB8_OES: format = GL_RGB; type = GL_UNSIGNED_BYTE; break; #endif default: ogles_error(c, GL_INVALID_ENUM); return; } if (!data || !width || !height) { // unclear if this is an error or not... return; } int32_t size; GGLSurface* surface; #ifdef GL_OES_compressed_ETC1_RGB8_texture if (internalformat == GL_ETC1_RGB8_OES) { GLsizei compressedSize = etc1_get_encoded_data_size(width, height); if (compressedSize > imageSize) { ogles_error(c, GL_INVALID_VALUE); return; } int error = createTextureSurface(c, &surface, &size, level, format, type, width, height); if (error) { ogles_error(c, error); return; } if (etc1_decode_image( (const etc1_byte*)data, (etc1_byte*)surface->data, width, height, 3, surface->stride*3) != 0) { ogles_error(c, GL_INVALID_OPERATION); } return; } #endif // all mipmap levels are specified at once. const int numLevels = level<0 ? -level : 1; if (dataSizePalette4(numLevels, width, height, format) > imageSize) { ogles_error(c, GL_INVALID_VALUE); return; } for (int i=0 ; i> i) ? : 1; int lod_h = (height >> i) ? : 1; int error = createTextureSurface(c, &surface, &size, i, format, type, lod_w, lod_h); if (error) { ogles_error(c, error); return; } decodePalette4(data, i, width, height, surface->data, surface->stride, internalformat); } } void glTexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } if (width<0 || height<0 || border!=0 || level < 0) { ogles_error(c, GL_INVALID_VALUE); return; } if (format != (GLenum)internalformat) { ogles_error(c, GL_INVALID_OPERATION); return; } if (validFormatType(c, format, type)) { return; } int32_t size = 0; GGLSurface* surface = 0; int error = createTextureSurface(c, &surface, &size, level, format, type, width, height); if (error) { ogles_error(c, error); return; } if (pixels) { const int32_t formatIdx = convertGLPixelFormat(format, type); const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); const int32_t align = c->textures.unpackAlignment-1; const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; const size_t size = bpr * height; const int32_t stride = bpr / pixelFormat.size; GGLSurface userSurface; userSurface.version = sizeof(userSurface); userSurface.width = width; userSurface.height = height; userSurface.stride = stride; userSurface.format = formatIdx; userSurface.compressedFormat = 0; userSurface.data = (GLubyte*)pixels; int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height); if (err) { ogles_error(c, err); return; } generateMipmap(c, level); } } // ---------------------------------------------------------------------------- void glCompressedTexSubImage2D( GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/, GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/, GLenum /*format*/, GLsizei /*imageSize*/, const GLvoid* /*data*/) { ogles_context_t* c = ogles_context_t::get(); ogles_error(c, GL_INVALID_ENUM); } void glTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { ogles_error(c, GL_INVALID_VALUE); return; } if (validFormatType(c, format, type)) { return; } // find out which texture is bound to the current unit const int active = c->textures.active; EGLTextureObject* tex = c->textures.tmu[active].texture; const GGLSurface& surface(tex->mip(level)); if (!tex->internalformat || tex->direct) { ogles_error(c, GL_INVALID_OPERATION); return; } if (format != tex->internalformat) { ogles_error(c, GL_INVALID_OPERATION); return; } if ((xoffset + width > GLsizei(surface.width)) || (yoffset + height > GLsizei(surface.height))) { ogles_error(c, GL_INVALID_VALUE); return; } if (!width || !height) { return; // okay, but no-op. } // figure out the size we need as well as the stride const int32_t formatIdx = convertGLPixelFormat(format, type); if (formatIdx == 0) { // we don't know what to do with this ogles_error(c, GL_INVALID_OPERATION); return; } const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); const int32_t align = c->textures.unpackAlignment-1; const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; const size_t size = bpr * height; const int32_t stride = bpr / pixelFormat.size; GGLSurface userSurface; userSurface.version = sizeof(userSurface); userSurface.width = width; userSurface.height = height; userSurface.stride = stride; userSurface.format = formatIdx; userSurface.compressedFormat = 0; userSurface.data = (GLubyte*)pixels; int err = copyPixels(c, surface, xoffset, yoffset, userSurface, 0, 0, width, height); if (err) { ogles_error(c, err); return; } generateMipmap(c, level); // since we only changed the content of the texture, we don't need // to call bindTexture on the main rasterizer. } // ---------------------------------------------------------------------------- void glCopyTexImage2D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } if (internalformatGL_LUMINANCE_ALPHA) { ogles_error(c, GL_INVALID_ENUM); return; } if (width<0 || height<0 || border!=0 || level<0) { ogles_error(c, GL_INVALID_VALUE); return; } GLenum format = 0; GLenum type = GL_UNSIGNED_BYTE; const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; const int cbFormatIdx = cbSurface.format; switch (cbFormatIdx) { case GGL_PIXEL_FORMAT_RGB_565: type = GL_UNSIGNED_SHORT_5_6_5; break; case GGL_PIXEL_FORMAT_RGBA_5551: type = GL_UNSIGNED_SHORT_5_5_5_1; break; case GGL_PIXEL_FORMAT_RGBA_4444: type = GL_UNSIGNED_SHORT_4_4_4_4; break; } switch (internalformat) { case GL_ALPHA: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE: type = GL_UNSIGNED_BYTE; break; } // figure out the format to use for the new texture switch (cbFormatIdx) { case GGL_PIXEL_FORMAT_RGBA_8888: case GGL_PIXEL_FORMAT_A_8: case GGL_PIXEL_FORMAT_RGBA_5551: case GGL_PIXEL_FORMAT_RGBA_4444: format = internalformat; break; case GGL_PIXEL_FORMAT_RGBX_8888: case GGL_PIXEL_FORMAT_RGB_888: case GGL_PIXEL_FORMAT_RGB_565: case GGL_PIXEL_FORMAT_L_8: switch (internalformat) { case GL_LUMINANCE: case GL_RGB: format = internalformat; break; } break; } if (format == 0) { // invalid combination ogles_error(c, GL_INVALID_ENUM); return; } // create the new texture... int32_t size; GGLSurface* surface; int error = createTextureSurface(c, &surface, &size, level, format, type, width, height); if (error) { ogles_error(c, error); return; } // The bottom row is stored first in textures GGLSurface txSurface(*surface); txSurface.stride = -txSurface.stride; // (x,y) is the lower-left corner of colorBuffer y = cbSurface.height - (y + height); /* The GLES spec says: * If any of the pixels within the specified rectangle are outside * the framebuffer associated with the current rendering context, * then the values obtained for those pixels are undefined. */ if (x+width > GLint(cbSurface.width)) width = cbSurface.width - x; if (y+height > GLint(cbSurface.height)) height = cbSurface.height - y; int err = copyPixels(c, txSurface, 0, 0, cbSurface, x, y, width, height); if (err) { ogles_error(c, err); } generateMipmap(c, level); } void glCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D) { ogles_error(c, GL_INVALID_ENUM); return; } if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { ogles_error(c, GL_INVALID_VALUE); return; } if (!width || !height) { return; // okay, but no-op. } // find out which texture is bound to the current unit const int active = c->textures.active; EGLTextureObject* tex = c->textures.tmu[active].texture; const GGLSurface& surface(tex->mip(level)); if (!tex->internalformat) { ogles_error(c, GL_INVALID_OPERATION); return; } if ((xoffset + width > GLsizei(surface.width)) || (yoffset + height > GLsizei(surface.height))) { ogles_error(c, GL_INVALID_VALUE); return; } // The bottom row is stored first in textures GGLSurface txSurface(surface); txSurface.stride = -txSurface.stride; // (x,y) is the lower-left corner of colorBuffer const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; y = cbSurface.height - (y + height); /* The GLES spec says: * If any of the pixels within the specified rectangle are outside * the framebuffer associated with the current rendering context, * then the values obtained for those pixels are undefined. */ if (x+width > GLint(cbSurface.width)) width = cbSurface.width - x; if (y+height > GLint(cbSurface.height)) height = cbSurface.height - y; int err = copyPixels(c, txSurface, xoffset, yoffset, cbSurface, x, y, width, height); if (err) { ogles_error(c, err); return; } generateMipmap(c, level); } void glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { ogles_context_t* c = ogles_context_t::get(); if ((format != GL_RGBA) && (format != GL_RGB)) { ogles_error(c, GL_INVALID_ENUM); return; } if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) { ogles_error(c, GL_INVALID_ENUM); return; } if (width<0 || height<0) { ogles_error(c, GL_INVALID_VALUE); return; } if (x<0 || y<0) { ogles_error(c, GL_INVALID_VALUE); return; } int32_t formatIdx = GGL_PIXEL_FORMAT_NONE; if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) { formatIdx = GGL_PIXEL_FORMAT_RGBA_8888; } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) { formatIdx = GGL_PIXEL_FORMAT_RGB_565; } else { ogles_error(c, GL_INVALID_OPERATION); return; } const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s; if ((x+width > GLint(readSurface.width)) || (y+height > GLint(readSurface.height))) { ogles_error(c, GL_INVALID_VALUE); return; } const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); const int32_t align = c->textures.packAlignment-1; const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; const int32_t stride = bpr / pixelFormat.size; GGLSurface userSurface; userSurface.version = sizeof(userSurface); userSurface.width = width; userSurface.height = height; userSurface.stride = -stride; // bottom row is transfered first userSurface.format = formatIdx; userSurface.compressedFormat = 0; userSurface.data = (GLubyte*)pixels; // use pixel-flinger to handle all the conversions GGLContext* ggl = getRasterizer(c); if (!ggl) { // the only reason this would fail is because we ran out of memory ogles_error(c, GL_OUT_OF_MEMORY); return; } ggl->colorBuffer(ggl, &userSurface); // destination is user buffer ggl->bindTexture(ggl, &readSurface); // source is read-buffer ggl->texCoord2i(ggl, x, readSurface.height - (y + height)); ggl->recti(ggl, 0, 0, width, height); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark DrawTexture Extension #endif void glDrawTexsvOES(const GLshort* coords) { ogles_context_t* c = ogles_context_t::get(); drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); } void glDrawTexivOES(const GLint* coords) { ogles_context_t* c = ogles_context_t::get(); drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); } void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) { ogles_context_t* c = ogles_context_t::get(); drawTexiOES(x, y, z, w, h, c); } void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) { ogles_context_t* c = ogles_context_t::get(); drawTexiOES(x, y, z, w, h, c); } void glDrawTexfvOES(const GLfloat* coords) { ogles_context_t* c = ogles_context_t::get(); drawTexxOES( gglFloatToFixed(coords[0]), gglFloatToFixed(coords[1]), gglFloatToFixed(coords[2]), gglFloatToFixed(coords[3]), gglFloatToFixed(coords[4]), c); } void glDrawTexxvOES(const GLfixed* coords) { ogles_context_t* c = ogles_context_t::get(); drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); } void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){ ogles_context_t* c = ogles_context_t::get(); drawTexxOES( gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z), gglFloatToFixed(w), gglFloatToFixed(h), c); } void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) { ogles_context_t* c = ogles_context_t::get(); drawTexxOES(x, y, z, w, h, c); } // ---------------------------------------------------------------------------- #if 0 #pragma mark - #pragma mark EGL Image Extension #endif void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { ogles_error(c, GL_INVALID_ENUM); return; } if (image == EGL_NO_IMAGE_KHR) { ogles_error(c, GL_INVALID_VALUE); return; } ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image; if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { ogles_error(c, GL_INVALID_VALUE); return; } if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) { ogles_error(c, GL_INVALID_VALUE); return; } // bind it to the texture unit sp tex = getAndBindActiveTextureObject(c); tex->setImage(native_buffer); } void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) { ogles_context_t* c = ogles_context_t::get(); if (target != GL_RENDERBUFFER_OES) { ogles_error(c, GL_INVALID_ENUM); return; } if (image == EGL_NO_IMAGE_KHR) { ogles_error(c, GL_INVALID_VALUE); return; } ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image; if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { ogles_error(c, GL_INVALID_VALUE); return; } if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) { ogles_error(c, GL_INVALID_VALUE); return; } // well, we're not supporting this extension anyways } opengl/libagl/texture.h0100644 0000000 0000000 00000002254 13077405420 014201 0ustar000000000 0000000 /* libs/opengles/texture.h ** ** Copyright 2006, 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_OPENGLES_TEXTURE_H #define ANDROID_OPENGLES_TEXTURE_H #include #include #include #include #include #include "context.h" namespace android { void ogles_init_texture(ogles_context_t* c); void ogles_uninit_texture(ogles_context_t* c); void ogles_validate_texture(ogles_context_t* c); void ogles_lock_textures(ogles_context_t* c); void ogles_unlock_textures(ogles_context_t* c); }; // namespace android #endif // ANDROID_OPENGLES_TEXTURE_H opengl/libagl/vertex.cpp0100644 0000000 0000000 00000017457 13077405420 014364 0ustar000000000 0000000 /* libs/opengles/vertex.cpp ** ** Copyright 2006, 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 #include #include "context.h" #include "fp.h" #include "vertex.h" #include "state.h" #include "matrix.h" namespace android { // ---------------------------------------------------------------------------- void ogles_init_vertex(ogles_context_t* c) { c->cull.enable = GL_FALSE; c->cull.cullFace = GL_BACK; c->cull.frontFace = GL_CCW; c->current.color.r = 0x10000; c->current.color.g = 0x10000; c->current.color.b = 0x10000; c->current.color.a = 0x10000; c->currentNormal.z = 0x10000; } void ogles_uninit_vertex(ogles_context_t* /*c*/) { } // ---------------------------------------------------------------------------- // vertex processing // ---------------------------------------------------------------------------- // Divides a vertex clip coordinates by W static inline void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables) { // [x,y,z]window = vpt * ([x,y,z]clip / clip.w) // [w]window = 1/w // With a regular projection generated by glFrustum(), // we have w=-z, therefore, w is in [zNear, zFar]. // Also, zNear and zFar are stricly positive, // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this // means ]0, +inf[ -- however, it is always recommended // to use as large values as possible for zNear. // All in all, w is usually smaller than 1.0 (assuming // zNear is at least 1.0); and even if zNear is smaller than 1.0 // values of w won't be too big. const int32_t rw = gglRecip28(v->clip.w); const GLfixed* const m = c->transforms.vpt.transform.matrix.m; v->window.w = rw; v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28); v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28); v->window.x = TRI_FROM_FIXED(v->window.x); v->window.y = TRI_FROM_FIXED(v->window.y); if (enables & GGL_ENABLE_DEPTH_TEST) { v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28); } } // frustum clipping and W-divide static inline void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) { // ndc = clip / W // window = ncd * viewport // clip to the view-volume uint32_t clip = v->flags & vertex_t::CLIP_ALL; const GLfixed w = v->clip.w; if (v->clip.x < -w) clip |= vertex_t::CLIP_L; if (v->clip.x > w) clip |= vertex_t::CLIP_R; if (v->clip.y < -w) clip |= vertex_t::CLIP_B; if (v->clip.y > w) clip |= vertex_t::CLIP_T; if (v->clip.z < -w) clip |= vertex_t::CLIP_N; if (v->clip.z > w) clip |= vertex_t::CLIP_F; v->flags |= clip; c->arrays.cull &= clip; if (ggl_likely(!clip)) { // if the vertex is clipped, we don't do the perspective // divide, since we don't need its window coordinates. perspective(c, v, enables); } } // frustum clipping, user clipping and W-divide static inline void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) { // compute eye coordinates c->arrays.mv_transform( &c->transforms.modelview.transform, &v->eye, &v->obj); v->flags |= vertex_t::EYE; // clip this vertex against each user clip plane uint32_t clip = 0; int planes = c->clipPlanes.enable; while (planes) { const int i = 31 - gglClz(planes); planes &= ~(1<clipPlanes.plane[i].equation.v, v->eye.v); if (d < 0) { clip |= 0x100<flags |= clip; clipFrustumPerspective(c, v, enables); } // ---------------------------------------------------------------------------- void ogles_vertex_project(ogles_context_t* c, vertex_t* v) { perspective(c, v, c->rasterizer.state.enables); } void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v) { // here we assume w=1.0 and the viewport transformation // has been applied already. c->arrays.cull = 0; v->window.x = TRI_FROM_FIXED(v->clip.x); v->window.y = TRI_FROM_FIXED(v->clip.y); v->window.z = v->clip.z; v->window.w = v->clip.w << 12; } void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) { clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST); } void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) { clipFrustumPerspective(c, v, 0); } void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) { clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST); } void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) { clipAllPerspective(c, v, 0); } static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c) { const int p = plane - GL_CLIP_PLANE0; if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) { ogles_error(c, GL_INVALID_ENUM); return; } vec4_t& equation = c->clipPlanes.plane[p].equation; memcpy(equation.v, equ, sizeof(vec4_t)); ogles_validate_transform(c, transform_state_t::MVIT); transform_t& mvit = c->transforms.mvit4; mvit.point4(&mvit, &equation, &equation); } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- using namespace android; void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { ogles_context_t* c = ogles_context_t::get(); c->current.color.r = gglFloatToFixed(r); c->currentColorClamped.r = gglClampx(c->current.color.r); c->current.color.g = gglFloatToFixed(g); c->currentColorClamped.g = gglClampx(c->current.color.g); c->current.color.b = gglFloatToFixed(b); c->currentColorClamped.b = gglClampx(c->current.color.b); c->current.color.a = gglFloatToFixed(a); c->currentColorClamped.a = gglClampx(c->current.color.a); } void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a) { ogles_context_t* c = ogles_context_t::get(); c->current.color.r = r; c->current.color.g = g; c->current.color.b = b; c->current.color.a = a; c->currentColorClamped.r = gglClampx(r); c->currentColorClamped.g = gglClampx(g); c->currentColorClamped.b = gglClampx(b); c->currentColorClamped.a = gglClampx(a); } void glNormal3f(GLfloat x, GLfloat y, GLfloat z) { ogles_context_t* c = ogles_context_t::get(); c->currentNormal.x = gglFloatToFixed(x); c->currentNormal.y = gglFloatToFixed(y); c->currentNormal.z = gglFloatToFixed(z); } void glNormal3x(GLfixed x, GLfixed y, GLfixed z) { ogles_context_t* c = ogles_context_t::get(); c->currentNormal.x = x; c->currentNormal.y = y; c->currentNormal.z = z; } // ---------------------------------------------------------------------------- void glClipPlanef(GLenum plane, const GLfloat* equ) { const GLfixed equx[4] = { gglFloatToFixed(equ[0]), gglFloatToFixed(equ[1]), gglFloatToFixed(equ[2]), gglFloatToFixed(equ[3]) }; ogles_context_t* c = ogles_context_t::get(); clipPlanex(plane, equx, c); } void glClipPlanex(GLenum plane, const GLfixed* equ) { ogles_context_t* c = ogles_context_t::get(); clipPlanex(plane, equ, c); } opengl/libagl/vertex.h0100644 0000000 0000000 00000002575 13077405420 014024 0ustar000000000 0000000 /* libs/opengles/vertex.h ** ** Copyright 2006, 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_OPENGLES_VERTEX_H #define ANDROID_OPENGLES_VERTEX_H #include #include #include namespace android { namespace gl { struct vertex_t; struct ogles_context_t; }; void ogles_init_vertex(ogles_context_t* c); void ogles_uninit_vertex(ogles_context_t* c); void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*); void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*); void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*); void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*); void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*); void ogles_vertex_project(ogles_context_t* c, vertex_t*); }; // namespace android #endif // ANDROID_OPENGLES_VERTEX_H opengl/libs/0040755 0000000 0000000 00000000000 13077405420 012027 5ustar000000000 0000000 opengl/libs/Android.mk0100644 0000000 0000000 00000011133 13077405420 013734 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) ############################################################################### # Build META EGL library # egl.cfg_config_module := # OpenGL drivers config file ifneq ($(BOARD_EGL_CFG),) include $(CLEAR_VARS) LOCAL_MODULE := egl.cfg LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG) include $(BUILD_PREBUILT) egl.cfg_config_module := $(LOCAL_MODULE) endif include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ EGL/egl_tls.cpp \ EGL/egl_cache.cpp \ EGL/egl_display.cpp \ EGL/egl_object.cpp \ EGL/egl.cpp \ EGL/eglApi.cpp \ EGL/getProcAddress.cpp.arm \ EGL/Loader.cpp \ # LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libui LOCAL_MODULE:= libEGL LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL LOCAL_SHARED_LIBRARIES += libdl # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true) LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION endif ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),) LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE) endif ifneq ($(MAX_EGL_CACHE_KEY_SIZE),) LOCAL_CFLAGS += -DMAX_EGL_CACHE_KEY_SIZE=$(MAX_EGL_CACHE_KEY_SIZE) endif ifneq ($(MAX_EGL_CACHE_SIZE),) LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE) endif ifneq ($(filter address,$(SANITIZE_TARGET)),) LOCAL_CFLAGS_32 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib\" LOCAL_CFLAGS_64 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib64\" endif LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module) egl.cfg_config_module := include $(BUILD_SHARED_LIBRARY) ############################################################################### # Build the wrapper OpenGL ES 1.x library # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ GLES_CM/gl.cpp.arm \ # LOCAL_CLANG := false LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL LOCAL_MODULE:= libGLESv1_CM LOCAL_SHARED_LIBRARIES += libdl # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden # TODO: This is to work around b/20093774. Remove after root cause is fixed LOCAL_LDFLAGS_arm += -Wl,--hash-style,both include $(BUILD_SHARED_LIBRARY) ############################################################################### # Build the wrapper OpenGL ES 2.x library # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ GLES2/gl2.cpp \ # LOCAL_CLANG := false LOCAL_ARM_MODE := arm LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL LOCAL_MODULE:= libGLESv2 LOCAL_SHARED_LIBRARIES += libdl # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden # TODO: This is to work around b/20093774. Remove after root cause is fixed LOCAL_LDFLAGS_arm += -Wl,--hash-style,both include $(BUILD_SHARED_LIBRARY) ############################################################################### # Build the wrapper OpenGL ES 3.x library (this is just different name for v2) # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ GLES2/gl2.cpp \ # LOCAL_CLANG := false LOCAL_ARM_MODE := arm LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL LOCAL_MODULE:= libGLESv3 LOCAL_SHARED_LIBRARIES += libdl # we need to access the private Bionic header LOCAL_C_INCLUDES += bionic/libc/private LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden # TODO: This is to work around b/20093774. Remove after root cause is fixed LOCAL_LDFLAGS_arm += -Wl,--hash-style,both include $(BUILD_SHARED_LIBRARY) ############################################################################### # Build the ETC1 host static library # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ETC1/etc1.cpp \ # LOCAL_MODULE:= libETC1 LOCAL_MODULE_HOST_OS := darwin linux windows include $(BUILD_HOST_STATIC_LIBRARY) ############################################################################### # Build the ETC1 device library # include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ETC1/etc1.cpp \ # LOCAL_MODULE:= libETC1 include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) opengl/libs/EGL/0040755 0000000 0000000 00000000000 13077405420 012436 5ustar000000000 0000000 opengl/libs/EGL/Loader.cpp0100644 0000000 0000000 00000035334 13077405420 014355 0ustar000000000 0000000 /* ** Copyright 2007, 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 #include #include #include #include #include #include #include #include #include #include #include "egldefs.h" #include "Loader.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- /* * EGL userspace drivers must be provided either: * - as a single library: * /vendor/lib/egl/libGLES.so * * - as separate libraries: * /vendor/lib/egl/libEGL.so * /vendor/lib/egl/libGLESv1_CM.so * /vendor/lib/egl/libGLESv2.so * * The software renderer for the emulator must be provided as a single * library at: * * /system/lib/egl/libGLES_android.so * * * For backward compatibility and to facilitate the transition to * this new naming scheme, the loader will additionally look for: * * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so * */ ANDROID_SINGLETON_STATIC_INSTANCE( Loader ) /* This function is called to check whether we run inside the emulator, * and if this is the case whether GLES GPU emulation is supported. * * Returned values are: * -1 -> not running inside the emulator * 0 -> running inside the emulator, but GPU emulation not supported * 1 -> running inside the emulator, GPU emulation is supported * through the "emulation" host-side OpenGL ES implementation. * 2 -> running inside the emulator, GPU emulation is supported * through a guest-side vendor driver's OpenGL ES implementation. */ static int checkGlesEmulationStatus(void) { /* We're going to check for the following kernel parameters: * * qemu=1 -> tells us that we run inside the emulator * android.qemu.gles= -> tells us the GLES GPU emulation status * * Note that we will return if we find it. This let us support * more additionnal emulation modes in the future. */ char prop[PROPERTY_VALUE_MAX]; int result = -1; /* First, check for qemu=1 */ property_get("ro.kernel.qemu",prop,"0"); if (atoi(prop) != 1) return -1; /* We are in the emulator, get GPU status value */ property_get("qemu.gles",prop,"0"); return atoi(prop); } // ---------------------------------------------------------------------------- static char const * getProcessCmdline() { long pid = getpid(); char procPath[128]; snprintf(procPath, 128, "/proc/%ld/cmdline", pid); FILE * file = fopen(procPath, "r"); if (file) { static char cmdline[256]; char *str = fgets(cmdline, sizeof(cmdline) - 1, file); fclose(file); if (str) { return cmdline; } } return NULL; } // ---------------------------------------------------------------------------- Loader::driver_t::driver_t(void* gles) { dso[0] = gles; for (size_t i=1 ; iset( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); hnd->set( load_driver("GLESv2", cnx, GLESv2), GLESv2 ); } } LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation"); cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); LOG_ALWAYS_FATAL_IF(!cnx->libEgl, "couldn't load system EGL wrapper libraries"); LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, "couldn't load system OpenGL ES wrapper libraries"); return (void*)hnd; } status_t Loader::close(void* driver) { driver_t* hnd = (driver_t*)driver; delete hnd; return NO_ERROR; } void Loader::init_api(void* dso, char const * const * api, __eglMustCastToProperFunctionPointerType* curr, getProcAddressType getProcAddress) { const ssize_t SIZE = 256; char scrap[SIZE]; while (*api) { char const * name = *api; __eglMustCastToProperFunctionPointerType f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); if (f == NULL) { // couldn't find the entry-point, use eglGetProcAddress() f = getProcAddress(name); } if (f == NULL) { // Try without the OES postfix ssize_t index = ssize_t(strlen(name)) - 3; if ((index>0 && (index instead", scrap); } } if (f == NULL) { // Try with the OES postfix ssize_t index = ssize_t(strlen(name)) - 3; if (index>0 && strcmp(name+index, "OES")) { snprintf(scrap, SIZE, "%sOES", name); f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap); //ALOGD_IF(f, "found <%s> instead", scrap); } } if (f == NULL) { //ALOGD("%s", name); f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented; /* * GL_EXT_debug_label is special, we always report it as * supported, it's handled by GLES_trace. If GLES_trace is not * enabled, then these are no-ops. */ if (!strcmp(name, "glInsertEventMarkerEXT")) { f = (__eglMustCastToProperFunctionPointerType)gl_noop; } else if (!strcmp(name, "glPushGroupMarkerEXT")) { f = (__eglMustCastToProperFunctionPointerType)gl_noop; } else if (!strcmp(name, "glPopGroupMarkerEXT")) { f = (__eglMustCastToProperFunctionPointerType)gl_noop; } } *curr++ = f; api++; } } void *Loader::load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask) { class MatchFile { public: static String8 find(const char* kind) { String8 result; int emulationStatus = checkGlesEmulationStatus(); switch (emulationStatus) { case 0: #if defined(__LP64__) result.setTo("/system/lib64/egl/libGLES_android.so"); #else result.setTo("/system/lib/egl/libGLES_android.so"); #endif return result; case 1: // Use host-side OpenGL through the "emulation" library #if defined(__LP64__) result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind); #else result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind); #endif return result; default: // Not in emulator, or use other guest-side implementation break; } String8 pattern; pattern.appendFormat("lib%s", kind); const char* const searchPaths[] = { #if defined(__LP64__) "/vendor/lib64/egl", "/system/lib64/egl" #else "/vendor/lib/egl", "/system/lib/egl" #endif }; // first, we search for the exact name of the GLES userspace // driver in both locations. // i.e.: // libGLES.so, or: // libEGL.so, libGLESv1_CM.so, libGLESv2.so for (size_t i=0 ; id_type == DT_DIR) { continue; } if (!strcmp(e->d_name, "libGLES_android.so")) { // always skip the software renderer continue; } if (strstr(e->d_name, pattern.string()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { result.clear(); result.appendFormat("%s/%s", search, e->d_name); closedir(d); return true; } } } closedir(d); } return false; } }; String8 absolutePath = MatchFile::find(kind); if (absolutePath.isEmpty()) { // this happens often, we don't want to log an error return 0; } const char* const driver_absolute_path = absolutePath.string(); void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); if (dso == 0) { const char* err = dlerror(); ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown"); return 0; } ALOGD("loaded %s", driver_absolute_path); if (mask & EGL) { getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress"); ALOGE_IF(!getProcAddress, "can't find eglGetProcAddress() in %s", driver_absolute_path); egl_t* egl = &cnx->egl; __eglMustCastToProperFunctionPointerType* curr = (__eglMustCastToProperFunctionPointerType*)egl; char const * const * api = egl_names; while (*api) { char const * name = *api; __eglMustCastToProperFunctionPointerType f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); if (f == NULL) { // couldn't find the entry-point, use eglGetProcAddress() f = getProcAddress(name); if (f == NULL) { f = (__eglMustCastToProperFunctionPointerType)0; } } *curr++ = f; api++; } } if (mask & GLESv1_CM) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl, getProcAddress); } if (mask & GLESv2) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl, getProcAddress); } return dso; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/EGL/Loader.h0100644 0000000 0000000 00000004230 13077405420 014011 0ustar000000000 0000000 /* ** Copyright 2009, 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_EGL_LOADER_H #define ANDROID_EGL_LOADER_H #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- struct egl_connection_t; class Loader : public Singleton { friend class Singleton; typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)( const char*); enum { EGL = 0x01, GLESv1_CM = 0x02, GLESv2 = 0x04 }; struct driver_t { driver_t(void* gles); ~driver_t(); status_t set(void* hnd, int32_t api); void* dso[3]; }; getProcAddressType getProcAddress; public: ~Loader(); void* open(egl_connection_t* cnx); status_t close(void* driver); private: Loader(); void *load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask); static __attribute__((noinline)) void init_api(void* dso, char const * const * api, __eglMustCastToProperFunctionPointerType* curr, getProcAddressType getProcAddress); }; // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif /* ANDROID_EGL_LOADER_H */ opengl/libs/EGL/egl.cpp0100644 0000000 0000000 00000017263 13077405420 013717 0ustar000000000 0000000 /* ** Copyright 2007, 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 #include #include #include #include #include #include #include #include #include #include #include #include "../egl_impl.h" #include "egl_tls.h" #include "egldefs.h" #include "Loader.h" #include "egl_display.h" #include "egl_object.h" typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- egl_connection_t gEGLImpl; gl_hooks_t gHooks[2]; gl_hooks_t gHooksNoContext; pthread_key_t gGLWrapperKey = -1; // ---------------------------------------------------------------------------- void setGLHooksThreadSpecific(gl_hooks_t const *value) { setGlThreadSpecific(value); } /*****************************************************************************/ static int gl_no_context() { if (egl_tls_t::logNoContextCall()) { char const* const error = "call to OpenGL ES API with " "no current context (logged once per thread)"; if (LOG_NDEBUG) { ALOGE(error); } else { LOG_ALWAYS_FATAL(error); } char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { CallStack stack(LOG_TAG); } } return 0; } static void early_egl_init(void) { int numHooks = sizeof(gHooksNoContext) / sizeof(EGLFuncPointer); EGLFuncPointer *iter = reinterpret_cast(&gHooksNoContext); for (int hook = 0; hook < numHooks; ++hook) { *(iter++) = reinterpret_cast(gl_no_context); } setGLHooksThreadSpecific(&gHooksNoContext); } static pthread_once_t once_control = PTHREAD_ONCE_INIT; static int sEarlyInitState = pthread_once(&once_control, &early_egl_init); // ---------------------------------------------------------------------------- egl_display_ptr validate_display(EGLDisplay dpy) { egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL)); if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL)); return dp; } egl_display_ptr validate_display_connection(EGLDisplay dpy, egl_connection_t*& cnx) { cnx = NULL; egl_display_ptr dp = validate_display(dpy); if (!dp) return dp; cnx = &gEGLImpl; if (cnx->dso == 0) { return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL)); } return dp; } // ---------------------------------------------------------------------------- const GLubyte * egl_get_string_for_current_context(GLenum name) { // NOTE: returning NULL here will fall-back to the default // implementation. EGLContext context = egl_tls_t::getContext(); if (context == EGL_NO_CONTEXT) return NULL; egl_context_t const * const c = get_context(context); if (c == NULL) // this should never happen, by construction return NULL; if (name != GL_EXTENSIONS) return NULL; return (const GLubyte *)c->gl_extensions.string(); } const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) { // NOTE: returning NULL here will fall-back to the default // implementation. EGLContext context = egl_tls_t::getContext(); if (context == EGL_NO_CONTEXT) return NULL; egl_context_t const * const c = get_context(context); if (c == NULL) // this should never happen, by construction return NULL; if (name != GL_EXTENSIONS) return NULL; // if index is out of bounds, assume it will be in the default // implementation too, so we don't have to generate a GL error here if (index >= c->tokenized_gl_extensions.size()) return NULL; return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string(); } GLint egl_get_num_extensions_for_current_context() { // NOTE: returning -1 here will fall-back to the default // implementation. EGLContext context = egl_tls_t::getContext(); if (context == EGL_NO_CONTEXT) return -1; egl_context_t const * const c = get_context(context); if (c == NULL) // this should never happen, by construction return -1; return (GLint)c->tokenized_gl_extensions.size(); } // ---------------------------------------------------------------------------- // this mutex protects: // d->disp[] // egl_init_drivers_locked() // static EGLBoolean egl_init_drivers_locked() { if (sEarlyInitState) { // initialized by static ctor. should be set here. return EGL_FALSE; } // get our driver loader Loader& loader(Loader::getInstance()); // dynamically load our EGL implementation egl_connection_t* cnx = &gEGLImpl; if (cnx->dso == 0) { cnx->hooks[egl_connection_t::GLESv1_INDEX] = &gHooks[egl_connection_t::GLESv1_INDEX]; cnx->hooks[egl_connection_t::GLESv2_INDEX] = &gHooks[egl_connection_t::GLESv2_INDEX]; cnx->dso = loader.open(cnx); } return cnx->dso ? EGL_TRUE : EGL_FALSE; } static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER; EGLBoolean egl_init_drivers() { EGLBoolean res; pthread_mutex_lock(&sInitDriverMutex); res = egl_init_drivers_locked(); pthread_mutex_unlock(&sInitDriverMutex); return res; } static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER; static nsecs_t sLogPrintTime = 0; #define NSECS_DURATION 1000000000 void gl_unimplemented() { bool printLog = false; nsecs_t now = systemTime(); pthread_mutex_lock(&sLogPrintMutex); if ((now - sLogPrintTime) > NSECS_DURATION) { sLogPrintTime = now; printLog = true; } pthread_mutex_unlock(&sLogPrintMutex); if (printLog) { ALOGE("called unimplemented OpenGL ES API"); char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { CallStack stack(LOG_TAG); } } } void gl_noop() { } // ---------------------------------------------------------------------------- void setGlThreadSpecific(gl_hooks_t const *value) { gl_hooks_t const * volatile * tls_hooks = get_tls_hooks(); tls_hooks[TLS_SLOT_OPENGL_API] = value; } // ---------------------------------------------------------------------------- // GL / EGL hooks // ---------------------------------------------------------------------------- #undef GL_ENTRY #undef EGL_ENTRY #define GL_ENTRY(_r, _api, ...) #_api, #define EGL_ENTRY(_r, _api, ...) #_api, char const * const gl_names[] = { #include "../entries.in" NULL }; char const * const egl_names[] = { #include "egl_entries.in" NULL }; #undef GL_ENTRY #undef EGL_ENTRY // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/EGL/eglApi.cpp0100644 0000000 0000000 00000171771 13077405420 014356 0ustar000000000 0000000 /* ** Copyright 2007, 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../egl_impl.h" #include "../hooks.h" #include "egl_display.h" #include "egl_object.h" #include "egl_tls.h" #include "egldefs.h" using namespace android; // This extension has not been ratified yet, so can't be shipped. // Implementation is incomplete and untested. #define ENABLE_EGL_KHR_GL_COLORSPACE 0 // ---------------------------------------------------------------------------- namespace android { struct extention_map_t { const char* name; __eglMustCastToProperFunctionPointerType address; }; /* * This is the list of EGL extensions exposed to applications. * * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL * wrapper and are always available. * * The rest (gExtensionString) depend on support in the EGL driver, and are * only available if the driver supports them. However, some of these must be * supported because they are used by the Android system itself; these are * listed as mandatory below and are required by the CDD. The system *assumes* * the mandatory extensions are present and may not function properly if some * are missing. * * NOTE: Both strings MUST have a single space as the last character. */ extern char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " "EGL_KHR_swap_buffers_with_damage " "EGL_ANDROID_create_native_client_buffer " "EGL_ANDROID_front_buffer_auto_refresh " ; extern char const * const gExtensionString = "EGL_KHR_image " // mandatory "EGL_KHR_image_base " // mandatory "EGL_KHR_image_pixmap " "EGL_KHR_lock_surface " #if (ENABLE_EGL_KHR_GL_COLORSPACE != 0) "EGL_KHR_gl_colorspace " #endif "EGL_KHR_gl_texture_2D_image " "EGL_KHR_gl_texture_3D_image " "EGL_KHR_gl_texture_cubemap_image " "EGL_KHR_gl_renderbuffer_image " "EGL_KHR_reusable_sync " "EGL_KHR_fence_sync " "EGL_KHR_create_context " "EGL_KHR_config_attribs " "EGL_KHR_surfaceless_context " "EGL_KHR_stream " "EGL_KHR_stream_fifo " "EGL_KHR_stream_producer_eglsurface " "EGL_KHR_stream_consumer_gltexture " "EGL_KHR_stream_cross_process_fd " "EGL_EXT_create_context_robustness " "EGL_NV_system_time " "EGL_ANDROID_image_native_buffer " // mandatory "EGL_KHR_wait_sync " // strongly recommended "EGL_ANDROID_recordable " // mandatory "EGL_KHR_partial_update " // strongly recommended "EGL_EXT_buffer_age " // strongly recommended with partial_update "EGL_KHR_create_context_no_error " "EGL_KHR_mutable_render_buffer " "EGL_EXT_yuv_surface " "EGL_EXT_protected_content " ; // extensions not exposed to applications but used by the ANDROID system // "EGL_ANDROID_blob_cache " // strongly recommended // "EGL_IMG_hibernate_process " // optional // "EGL_ANDROID_native_fence_sync " // strongly recommended // "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1 // "EGL_ANDROID_image_crop " // optional /* * EGL Extensions entry-points exposed to 3rd party applications * (keep in sync with gExtensionString above) * */ static const extention_map_t sExtensionMap[] = { // EGL_KHR_lock_surface { "eglLockSurfaceKHR", (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, { "eglUnlockSurfaceKHR", (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, // EGL_KHR_image, EGL_KHR_image_base { "eglCreateImageKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, { "eglDestroyImageKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, // EGL_KHR_reusable_sync, EGL_KHR_fence_sync { "eglCreateSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, { "eglDestroySyncKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, { "eglClientWaitSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, { "eglSignalSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR }, { "eglGetSyncAttribKHR", (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, // EGL_NV_system_time { "eglGetSystemTimeFrequencyNV", (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV }, { "eglGetSystemTimeNV", (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV }, // EGL_KHR_wait_sync { "eglWaitSyncKHR", (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR }, // EGL_ANDROID_presentation_time { "eglPresentationTimeANDROID", (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID }, // EGL_KHR_swap_buffers_with_damage { "eglSwapBuffersWithDamageKHR", (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR }, // EGL_ANDROID_native_client_buffer { "eglCreateNativeClientBufferANDROID", (__eglMustCastToProperFunctionPointerType)&eglCreateNativeClientBufferANDROID }, // EGL_KHR_partial_update { "eglSetDamageRegionKHR", (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR }, { "eglCreateStreamKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR }, { "eglDestroyStreamKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR }, { "eglStreamAttribKHR", (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR }, { "eglQueryStreamKHR", (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR }, { "eglQueryStreamu64KHR", (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR }, { "eglQueryStreamTimeKHR", (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR }, { "eglCreateStreamProducerSurfaceKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR }, { "eglStreamConsumerGLTextureExternalKHR", (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR }, { "eglStreamConsumerAcquireKHR", (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR }, { "eglStreamConsumerReleaseKHR", (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR }, { "eglGetStreamFileDescriptorKHR", (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR }, { "eglCreateStreamFromFileDescriptorKHR", (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR }, }; /* * These extensions entry-points should not be exposed to applications. * They're used internally by the Android EGL layer. */ #define FILTER_EXTENSIONS(procname) \ (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \ !strcmp((procname), "eglHibernateProcessIMG") || \ !strcmp((procname), "eglAwakenProcessIMG") || \ !strcmp((procname), "eglDupNativeFenceFDANDROID")) // accesses protected by sExtensionMapMutex static DefaultKeyedVector sGLExtentionMap; static int sGLExtentionSlot = 0; static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; static void(*findProcAddress(const char* name, const extention_map_t* map, size_t n))() { for (uint32_t i=0 ; i(display); if (index >= NUM_DISPLAYS) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); } if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); } EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); return dpy; } // ---------------------------------------------------------------------------- // Initialization // ---------------------------------------------------------------------------- EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { clearError(); egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean res = dp->initialize(major, minor); return res; } EGLBoolean eglTerminate(EGLDisplay dpy) { // NOTE: don't unload the drivers b/c some APIs can be called // after eglTerminate() has been called. eglTerminate() only // terminates an EGLDisplay, not a EGL itself. clearError(); egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean res = dp->terminate(); return res; } // ---------------------------------------------------------------------------- // configuration // ---------------------------------------------------------------------------- EGLBoolean eglGetConfigs( EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; if (num_config==0) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLBoolean res = EGL_FALSE; *num_config = 0; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso) { res = cnx->egl.eglGetConfigs( dp->disp.dpy, configs, config_size, num_config); } return res; } EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; if (num_config==0) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLBoolean res = EGL_FALSE; *num_config = 0; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso) { if (attrib_list) { char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.force_msaa", value, "false"); if (!strcmp(value, "true")) { size_t attribCount = 0; EGLint attrib = attrib_list[0]; // Only enable MSAA if the context is OpenGL ES 2.0 and // if no caveat is requested const EGLint *attribRendererable = NULL; const EGLint *attribCaveat = NULL; // Count the number of attributes and look for // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT while (attrib != EGL_NONE) { attrib = attrib_list[attribCount]; switch (attrib) { case EGL_RENDERABLE_TYPE: attribRendererable = &attrib_list[attribCount]; break; case EGL_CONFIG_CAVEAT: attribCaveat = &attrib_list[attribCount]; break; } attribCount++; } if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT && (!attribCaveat || attribCaveat[1] != EGL_NONE)) { // Insert 2 extra attributes to force-enable MSAA 4x EGLint aaAttribs[attribCount + 4]; aaAttribs[0] = EGL_SAMPLE_BUFFERS; aaAttribs[1] = 1; aaAttribs[2] = EGL_SAMPLES; aaAttribs[3] = 4; memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint)); EGLint numConfigAA; EGLBoolean resAA = cnx->egl.eglChooseConfig( dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA); if (resAA == EGL_TRUE && numConfigAA > 0) { ALOGD("Enabling MSAA 4x"); *num_config = numConfigAA; return resAA; } } } } res = cnx->egl.eglChooseConfig( dp->disp.dpy, attrib_list, configs, config_size, num_config); } return res; } EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { clearError(); egl_connection_t* cnx = NULL; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; return cnx->egl.eglGetConfigAttrib( dp->disp.dpy, config, attribute, value); } // ---------------------------------------------------------------------------- // surfaces // ---------------------------------------------------------------------------- // The EGL_KHR_gl_colorspace spec hasn't been ratified yet, so these haven't // been added to the Khronos egl.h. #define EGL_GL_COLORSPACE_KHR EGL_VG_COLORSPACE #define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB #define EGL_GL_COLORSPACE_LINEAR_KHR EGL_VG_COLORSPACE_LINEAR // Turn linear formats into corresponding sRGB formats when colorspace is // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where // the modification isn't possible, the original dataSpace is returned. static android_dataspace modifyBufferDataspace( android_dataspace dataSpace, EGLint colorspace) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { return HAL_DATASPACE_SRGB; } return dataSpace; } EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) { clearError(); egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLDisplay iDpy = dp->disp.dpy; int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); if (result != OK) { ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " "failed (%#x) (already connected to another API?)", window, result); return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } // Set the native window's buffers format to match what this config requests. // Whether to use sRGB gamma is not part of the EGLconfig, but is part // of our native format. So if sRGB gamma is requested, we have to // modify the EGLconfig's format before setting the native window's // format. // by default, just pick RGBA_8888 EGLint format = HAL_PIXEL_FORMAT_RGBA_8888; android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; EGLint a = 0; cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a); if (a > 0) { // alpha-channel requested, there's really only one suitable format format = HAL_PIXEL_FORMAT_RGBA_8888; } else { EGLint r, g, b; r = g = b = 0; cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r); cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g); cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b); EGLint colorDepth = r + g + b; if (colorDepth <= 16) { format = HAL_PIXEL_FORMAT_RGB_565; } else { format = HAL_PIXEL_FORMAT_RGBX_8888; } } // now select a corresponding sRGB format if needed if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { if (*attr == EGL_GL_COLORSPACE_KHR) { if (ENABLE_EGL_KHR_GL_COLORSPACE) { dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); } else { // Normally we'd pass through unhandled attributes to // the driver. But in case the driver implements this // extension but we're disabling it, we want to prevent // it getting through -- support will be broken without // our help. ALOGE("sRGB window surfaces not supported"); return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } } } } if (format != 0) { int err = native_window_set_buffers_format(window, format); if (err != 0) { ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err); native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } } if (dataSpace != 0) { int err = native_window_set_buffers_data_space(window, dataSpace); if (err != 0) { ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err); native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } } // the EGL spec requires that a new EGLSurface default to swap interval // 1, so explicitly set that on the window here. ANativeWindow* anw = reinterpret_cast(window); anw->setSwapInterval(anw, 1); EGLSurface surface = cnx->egl.eglCreateWindowSurface( iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, window, surface, cnx); return s; } // EGLSurface creation failed native_window_set_buffers_format(window, 0); native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } return EGL_NO_SURFACE; } EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list) { clearError(); egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, cnx); return s; } } return EGL_NO_SURFACE; } EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { clearError(); egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, cnx); return s; } } return EGL_NO_SURFACE; } EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t * const s = get_surface(surface); EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); if (result == EGL_TRUE) { _s.terminate(); } return result; } EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); return s->cnx->egl.eglQuerySurface( dp->disp.dpy, s->surface, attribute, value); } void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { ATRACE_CALL(); clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) { return; } SurfaceRef _s(dp.get(), surface); if (!_s.get()) { setError(EGL_BAD_SURFACE, EGL_FALSE); return; } } // ---------------------------------------------------------------------------- // Contexts // ---------------------------------------------------------------------------- EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list) { clearError(); egl_connection_t* cnx = NULL; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { if (share_list != EGL_NO_CONTEXT) { if (!ContextRef(dp.get(), share_list).get()) { return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); } egl_context_t* const c = get_context(share_list); share_list = c->context; } EGLContext context = cnx->egl.eglCreateContext( dp->disp.dpy, config, share_list, attrib_list); if (context != EGL_NO_CONTEXT) { // figure out if it's a GLESv1 or GLESv2 int version = 0; if (attrib_list) { while (*attrib_list != EGL_NONE) { GLint attr = *attrib_list++; GLint value = *attrib_list++; if (attr == EGL_CONTEXT_CLIENT_VERSION) { if (value == 1) { version = egl_connection_t::GLESv1_INDEX; } else if (value == 2 || value == 3) { version = egl_connection_t::GLESv2_INDEX; } } }; } egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version); return c; } } return EGL_NO_CONTEXT; } EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; ContextRef _c(dp.get(), ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); if (result == EGL_TRUE) { _c.terminate(); } return result; } EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { clearError(); egl_display_ptr dp = validate_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is // a valid but uninitialized display. if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || (draw != EGL_NO_SURFACE) ) { if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE); } // get a reference to the object passed in ContextRef _c(dp.get(), ctx); SurfaceRef _d(dp.get(), draw); SurfaceRef _r(dp.get(), read); // validate the context (if not EGL_NO_CONTEXT) if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { // EGL_NO_CONTEXT is valid return setError(EGL_BAD_CONTEXT, EGL_FALSE); } // these are the underlying implementation's object EGLContext impl_ctx = EGL_NO_CONTEXT; EGLSurface impl_draw = EGL_NO_SURFACE; EGLSurface impl_read = EGL_NO_SURFACE; // these are our objects structs passed in egl_context_t * c = NULL; egl_surface_t const * d = NULL; egl_surface_t const * r = NULL; // these are the current objects structs egl_context_t * cur_c = get_context(getContext()); if (ctx != EGL_NO_CONTEXT) { c = get_context(ctx); impl_ctx = c->context; } else { // no context given, use the implementation of the current context if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); return setError(EGL_BAD_MATCH, EGL_FALSE); } if (cur_c == NULL) { // no current context // not an error, there is just no current context. return EGL_TRUE; } } // retrieve the underlying implementation's draw EGLSurface if (draw != EGL_NO_SURFACE) { if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); d = get_surface(draw); impl_draw = d->surface; } // retrieve the underlying implementation's read EGLSurface if (read != EGL_NO_SURFACE) { if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); r = get_surface(read); impl_read = r->surface; } EGLBoolean result = dp->makeCurrent(c, cur_c, draw, read, ctx, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { if (c) { setGLHooksThreadSpecific(c->cnx->hooks[c->version]); egl_tls_t::setContext(ctx); _c.acquire(); _r.acquire(); _d.acquire(); } else { setGLHooksThreadSpecific(&gHooksNoContext); egl_tls_t::setContext(EGL_NO_CONTEXT); } } else { // this will ALOGE the error egl_connection_t* const cnx = &gEGLImpl; result = setError(cnx->egl.eglGetError(), EGL_FALSE); } return result; } EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; ContextRef _c(dp.get(), ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); return c->cnx->egl.eglQueryContext( dp->disp.dpy, c->context, attribute, value); } EGLContext eglGetCurrentContext(void) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_CONTEXT. clearError(); EGLContext ctx = getContext(); return ctx; } EGLSurface eglGetCurrentSurface(EGLint readdraw) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_SURFACE. clearError(); EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); switch (readdraw) { case EGL_READ: return c->read; case EGL_DRAW: return c->draw; default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); } } return EGL_NO_SURFACE; } EGLDisplay eglGetCurrentDisplay(void) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_DISPLAY. clearError(); EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); return c->dpy; } return EGL_NO_DISPLAY; } EGLBoolean eglWaitGL(void) { clearError(); egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, EGL_FALSE); return cnx->egl.eglWaitGL(); } EGLBoolean eglWaitNative(EGLint engine) { clearError(); egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, EGL_FALSE); return cnx->egl.eglWaitNative(engine); } EGLint eglGetError(void) { EGLint err = EGL_SUCCESS; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso) { err = cnx->egl.eglGetError(); } if (err == EGL_SUCCESS) { err = egl_tls_t::getError(); } return err; } static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( const char* procname) { const egl_connection_t* cnx = &gEGLImpl; void* proc = NULL; proc = dlsym(cnx->libEgl, procname); if (proc) return (__eglMustCastToProperFunctionPointerType)proc; proc = dlsym(cnx->libGles2, procname); if (proc) return (__eglMustCastToProperFunctionPointerType)proc; proc = dlsym(cnx->libGles1, procname); if (proc) return (__eglMustCastToProperFunctionPointerType)proc; return NULL; } __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { // eglGetProcAddress() could be the very first function called // in which case we must make sure we've initialized ourselves, this // happens the first time egl_get_display() is called. clearError(); if (egl_init_drivers() == EGL_FALSE) { setError(EGL_BAD_PARAMETER, NULL); return NULL; } if (FILTER_EXTENSIONS(procname)) { return NULL; } __eglMustCastToProperFunctionPointerType addr; addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap)); if (addr) return addr; addr = findBuiltinWrapper(procname); if (addr) return addr; // this protects accesses to sGLExtentionMap and sGLExtentionSlot pthread_mutex_lock(&sExtensionMapMutex); /* * Since eglGetProcAddress() is not associated to anything, it needs * to return a function pointer that "works" regardless of what * the current context is. * * For this reason, we return a "forwarder", a small stub that takes * care of calling the function associated with the context * currently bound. * * We first look for extensions we've already resolved, if we're seeing * this extension for the first time, we go through all our * implementations and call eglGetProcAddress() and record the * result in the appropriate implementation hooks and return the * address of the forwarder corresponding to that hook set. * */ const String8 name(procname); addr = sGLExtentionMap.valueFor(name); const int slot = sGLExtentionSlot; ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, "no more slots for eglGetProcAddress(\"%s\")", procname); if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { bool found = false; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglGetProcAddress) { // Extensions are independent of the bound context addr = cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = cnx->egl.eglGetProcAddress(procname); if (addr) found = true; } if (found) { addr = gExtensionForwarders[slot]; sGLExtentionMap.add(name, addr); sGLExtentionSlot++; } } pthread_mutex_unlock(&sExtensionMapMutex); return addr; } class FrameCompletionThread : public Thread { public: static void queueSync(EGLSyncKHR sync) { static sp thread(new FrameCompletionThread); static bool running = false; if (!running) { thread->run("GPUFrameCompletion"); running = true; } { Mutex::Autolock lock(thread->mMutex); ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d", thread->mFramesQueued).string()); thread->mQueue.push_back(sync); thread->mCondition.signal(); thread->mFramesQueued++; ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size()); } } private: FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {} virtual bool threadLoop() { EGLSyncKHR sync; uint32_t frameNum; { Mutex::Autolock lock(mMutex); while (mQueue.isEmpty()) { mCondition.wait(mMutex); } sync = mQueue[0]; frameNum = mFramesCompleted; } EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); { ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d", frameNum).string()); EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); if (result == EGL_FALSE) { ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ALOGE("FrameCompletion: timeout waiting for fence"); } eglDestroySyncKHR(dpy, sync); } { Mutex::Autolock lock(mMutex); mQueue.removeAt(0); mFramesCompleted++; ATRACE_INT("GPU Frames Outstanding", mQueue.size()); } return true; } uint32_t mFramesQueued; uint32_t mFramesCompleted; Vector mQueue; Condition mCondition; Mutex mMutex; }; EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, EGLint *rects, EGLint n_rects) { ATRACE_CALL(); clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), draw); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(draw); if (CC_UNLIKELY(dp->traceGpuCompletion)) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (sync != EGL_NO_SYNC_KHR) { FrameCompletionThread::queueSync(sync); } } if (CC_UNLIKELY(dp->finishOnSwap)) { uint32_t pixel; egl_context_t * const c = get_context( egl_tls_t::getContext() ); if (c) { // glReadPixels() ensures that the frame is complete s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1, GL_RGBA,GL_UNSIGNED_BYTE,&pixel); } } if (n_rects == 0) { return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); } Vector androidRects; for (int r = 0; r < n_rects; ++r) { int offset = r * 4; int x = rects[offset]; int y = rects[offset + 1]; int width = rects[offset + 2]; int height = rects[offset + 3]; android_native_rect_t androidRect; androidRect.left = x; androidRect.top = y + height; androidRect.right = x + width; androidRect.bottom = y; androidRects.push_back(androidRect); } native_window_set_surface_damage(s->win.get(), androidRects.array(), androidRects.size()); if (s->cnx->egl.eglSwapBuffersWithDamageKHR) { return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface, rects, n_rects); } else { return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); } } EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0); } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } const char* eglQueryString(EGLDisplay dpy, EGLint name) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) NULL; switch (name) { case EGL_VENDOR: return dp->getVendorString(); case EGL_VERSION: return dp->getVersionString(); case EGL_EXTENSIONS: return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); } return setError(EGL_BAD_PARAMETER, (const char *)0); } EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) NULL; switch (name) { case EGL_VENDOR: return dp->disp.queryString.vendor; case EGL_VERSION: return dp->disp.queryString.version; case EGL_EXTENSIONS: return dp->disp.queryString.extensions; case EGL_CLIENT_APIS: return dp->disp.queryString.clientApi; } return setError(EGL_BAD_PARAMETER, (const char *)0); } // ---------------------------------------------------------------------------- // EGL 1.1 // ---------------------------------------------------------------------------- EGLBoolean eglSurfaceAttrib( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) { int err = native_window_set_auto_refresh(s->win.get(), value ? true : false); return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, EGL_FALSE); } if (s->cnx->egl.eglSurfaceAttrib) { return s->cnx->egl.eglSurfaceAttrib( dp->disp.dpy, s->surface, attribute, value); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } EGLBoolean eglBindTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglBindTexImage) { return s->cnx->egl.eglBindTexImage( dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } EGLBoolean eglReleaseTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglReleaseTexImage) { return s->cnx->egl.eglReleaseTexImage( dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean res = EGL_TRUE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglSwapInterval) { res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); } return res; } // ---------------------------------------------------------------------------- // EGL 1.2 // ---------------------------------------------------------------------------- EGLBoolean eglWaitClient(void) { clearError(); egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, EGL_FALSE); EGLBoolean res; if (cnx->egl.eglWaitClient) { res = cnx->egl.eglWaitClient(); } else { res = cnx->egl.eglWaitGL(); } return res; } EGLBoolean eglBindAPI(EGLenum api) { clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } // bind this API on all EGLs EGLBoolean res = EGL_TRUE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglBindAPI) { res = cnx->egl.eglBindAPI(api); } return res; } EGLenum eglQueryAPI(void) { clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryAPI) { return cnx->egl.eglQueryAPI(); } // or, it can only be OpenGL ES return EGL_OPENGL_ES_API; } EGLBoolean eglReleaseThread(void) { clearError(); // If there is context bound to the thread, release it egl_display_t::loseCurrent(get_context(getContext())); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); } egl_tls_t::clearTLS(); return EGL_TRUE; } EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { clearError(); egl_connection_t* cnx = NULL; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; if (cnx->egl.eglCreatePbufferFromClientBuffer) { return cnx->egl.eglCreatePbufferFromClientBuffer( dp->disp.dpy, buftype, buffer, config, attrib_list); } return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); } // ---------------------------------------------------------------------------- // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglLockSurfaceKHR) { return s->cnx->egl.eglLockSurfaceKHR( dp->disp.dpy, s->surface, attrib_list); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; SurfaceRef _s(dp.get(), surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglUnlockSurfaceKHR) { return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; ContextRef _c(dp.get(), ctx); egl_context_t * const c = _c.get(); EGLImageKHR result = EGL_NO_IMAGE_KHR; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateImageKHR) { result = cnx->egl.eglCreateImageKHR( dp->disp.dpy, c ? c->context : EGL_NO_CONTEXT, target, buffer, attrib_list); } return result; } EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglDestroyImageKHR) { result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); } return result; } // ---------------------------------------------------------------------------- // EGL_EGLEXT_VERSION 5 // ---------------------------------------------------------------------------- EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SYNC_KHR; EGLSyncKHR result = EGL_NO_SYNC_KHR; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateSyncKHR) { result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); } return result; } EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglDestroySyncKHR) { result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); } return result; } EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglSignalSyncKHR) { result = cnx->egl.eglSignalSyncKHR( dp->disp.dpy, sync, mode); } return result; } EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { result = cnx->egl.eglClientWaitSyncKHR( dp->disp.dpy, sync, flags, timeout); } return result; } EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { result = cnx->egl.eglGetSyncAttribKHR( dp->disp.dpy, sync, attribute, value); } return result; } EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; EGLStreamKHR result = EGL_NO_STREAM_KHR; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateStreamKHR) { result = cnx->egl.eglCreateStreamKHR( dp->disp.dpy, attrib_list); } return result; } EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglDestroyStreamKHR) { result = cnx->egl.eglDestroyStreamKHR( dp->disp.dpy, stream); } return result; } EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglStreamAttribKHR) { result = cnx->egl.eglStreamAttribKHR( dp->disp.dpy, stream, attribute, value); } return result; } EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryStreamKHR) { result = cnx->egl.eglQueryStreamKHR( dp->disp.dpy, stream, attribute, value); } return result; } EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) { result = cnx->egl.eglQueryStreamu64KHR( dp->disp.dpy, stream, attribute, value); } return result; } EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) { result = cnx->egl.eglQueryStreamTimeKHR( dp->disp.dpy, stream, attribute, value); } return result; } EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list) { clearError(); egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( dp->disp.dpy, config, stream, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, cnx); return s; } } return EGL_NO_SURFACE; } EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( dp->disp.dpy, stream); } return result; } EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { result = cnx->egl.eglStreamConsumerAcquireKHR( dp->disp.dpy, stream); } return result; } EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLBoolean result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { result = cnx->egl.eglStreamConsumerReleaseKHR( dp->disp.dpy, stream); } return result; } EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( EGLDisplay dpy, EGLStreamKHR stream) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { result = cnx->egl.eglGetStreamFileDescriptorKHR( dp->disp.dpy, stream); } return result; } EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; EGLStreamKHR result = EGL_NO_STREAM_KHR; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) { result = cnx->egl.eglCreateStreamFromFileDescriptorKHR( dp->disp.dpy, file_descriptor); } return result; } // ---------------------------------------------------------------------------- // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLint result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglWaitSyncKHR) { result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); } return result; } // ---------------------------------------------------------------------------- // ANDROID extensions // ---------------------------------------------------------------------------- EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); } return result; } EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) { return EGL_FALSE; } SurfaceRef _s(dp.get(), surface); if (!_s.get()) { setError(EGL_BAD_SURFACE, EGL_FALSE); return EGL_FALSE; } egl_surface_t const * const s = get_surface(surface); native_window_set_buffers_timestamp(s->win.get(), time); return EGL_TRUE; } EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list) { clearError(); int usage = 0; uint32_t width = 0; uint32_t height = 0; uint32_t format = 0; uint32_t red_size = 0; uint32_t green_size = 0; uint32_t blue_size = 0; uint32_t alpha_size = 0; #define GET_NONNEGATIVE_VALUE(case_name, target) \ case case_name: \ if (value >= 0) { \ target = value; \ } else { \ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); \ } \ break if (attrib_list) { while (*attrib_list != EGL_NONE) { GLint attr = *attrib_list++; GLint value = *attrib_list++; switch (attr) { GET_NONNEGATIVE_VALUE(EGL_WIDTH, width); GET_NONNEGATIVE_VALUE(EGL_HEIGHT, height); GET_NONNEGATIVE_VALUE(EGL_RED_SIZE, red_size); GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size); GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size); GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size); case EGL_NATIVE_BUFFER_USAGE_ANDROID: if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) { usage |= GRALLOC_USAGE_PROTECTED; } if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) { usage |= GRALLOC_USAGE_HW_RENDER; } if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) { usage |= GRALLOC_USAGE_HW_TEXTURE; } // The buffer must be used for either a texture or a // renderbuffer. if ((value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) && (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID)) { return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); } break; default: return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); } } } #undef GET_NONNEGATIVE_VALUE // Validate format. if (red_size == 8 && green_size == 8 && blue_size == 8) { if (alpha_size == 8) { format = HAL_PIXEL_FORMAT_RGBA_8888; } else { format = HAL_PIXEL_FORMAT_RGB_888; } } else if (red_size == 5 && green_size == 6 && blue_size == 5 && alpha_size == 0) { format = HAL_PIXEL_FORMAT_RGB_565; } else { ALOGE("Invalid native pixel format { r=%d, g=%d, b=%d, a=%d }", red_size, green_size, blue_size, alpha_size); return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); } GraphicBuffer* gBuffer = new GraphicBuffer(width, height, format, usage); const status_t err = gBuffer->initCheck(); if (err != NO_ERROR) { ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x", width, height, format, usage, err); // Destroy the buffer. sp holder(gBuffer); return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0); } ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }", gBuffer, width, height, format, usage); return static_cast(gBuffer->getNativeBuffer()); } // ---------------------------------------------------------------------------- // NVIDIA extensions // ---------------------------------------------------------------------------- EGLuint64NV eglGetSystemTimeFrequencyNV() { clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { return cnx->egl.eglGetSystemTimeFrequencyNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); } EGLuint64NV eglGetSystemTimeNV() { clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { return cnx->egl.eglGetSystemTimeNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); } // ---------------------------------------------------------------------------- // Partial update extension // ---------------------------------------------------------------------------- EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) { setError(EGL_BAD_DISPLAY, EGL_FALSE); return EGL_FALSE; } SurfaceRef _s(dp.get(), surface); if (!_s.get()) { setError(EGL_BAD_SURFACE, EGL_FALSE); return EGL_FALSE; } egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglSetDamageRegionKHR) { return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface, rects, n_rects); } return EGL_FALSE; } opengl/libs/EGL/egl_cache.cpp0100644 0000000 0000000 00000025732 13077405420 015042 0ustar000000000 0000000 /* ** Copyright 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 "../egl_impl.h" #include "egl_cache.h" #include "egl_display.h" #include "egldefs.h" #include #include #include #include #include #include #ifndef MAX_EGL_CACHE_ENTRY_SIZE #define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024); #endif #ifndef MAX_EGL_CACHE_KEY_SIZE #define MAX_EGL_CACHE_KEY_SIZE (1024); #endif #ifndef MAX_EGL_CACHE_SIZE #define MAX_EGL_CACHE_SIZE (64 * 1024); #endif // Cache size limits. static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE; static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE; static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE; // Cache file header static const char* cacheFileMagic = "EGL$"; static const size_t cacheFileHeaderSize = 8; // The time in seconds to wait before saving newly inserted cache entries. static const unsigned int deferredSaveDelay = 4; // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- #define BC_EXT_STR "EGL_ANDROID_blob_cache" // // Callback functions passed to EGL. // static void setBlob(const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) { egl_cache_t::get()->setBlob(key, keySize, value, valueSize); } static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) { return egl_cache_t::get()->getBlob(key, keySize, value, valueSize); } // // egl_cache_t definition // egl_cache_t::egl_cache_t() : mInitialized(false), mBlobCache(NULL) { } egl_cache_t::~egl_cache_t() { } egl_cache_t egl_cache_t::sCache; egl_cache_t* egl_cache_t::get() { return &sCache; } void egl_cache_t::initialize(egl_display_t *display) { Mutex::Autolock lock(mMutex); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { const char* exts = display->disp.queryString.extensions; size_t bcExtLen = strlen(BC_EXT_STR); size_t extsLen = strlen(exts); bool equal = !strcmp(BC_EXT_STR, exts); bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); bool atEnd = (bcExtLen+1) < extsLen && !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); bool inMiddle = strstr(exts, " " BC_EXT_STR " "); if (equal || atStart || atEnd || inMiddle) { PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; eglSetBlobCacheFuncsANDROID = reinterpret_cast( cnx->egl.eglGetProcAddress( "eglSetBlobCacheFuncsANDROID")); if (eglSetBlobCacheFuncsANDROID == NULL) { ALOGE("EGL_ANDROID_blob_cache advertised, " "but unable to get eglSetBlobCacheFuncsANDROID"); return; } eglSetBlobCacheFuncsANDROID(display->disp.dpy, android::setBlob, android::getBlob); EGLint err = cnx->egl.eglGetError(); if (err != EGL_SUCCESS) { ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " "%#x", err); } } } mInitialized = true; } void egl_cache_t::terminate() { Mutex::Autolock lock(mMutex); saveBlobCacheLocked(); mBlobCache = NULL; } void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) { Mutex::Autolock lock(mMutex); if (keySize < 0 || valueSize < 0) { ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); return; } if (mInitialized) { sp bc = getBlobCacheLocked(); bc->set(key, keySize, value, valueSize); if (!mSavePending) { class DeferredSaveThread : public Thread { public: DeferredSaveThread() : Thread(false) {} virtual bool threadLoop() { sleep(deferredSaveDelay); egl_cache_t* c = egl_cache_t::get(); Mutex::Autolock lock(c->mMutex); if (c->mInitialized) { c->saveBlobCacheLocked(); } c->mSavePending = false; return false; } }; // The thread will hold a strong ref to itself until it has finished // running, so there's no need to keep a ref around. sp deferredSaveThread(new DeferredSaveThread()); mSavePending = true; deferredSaveThread->run("DeferredSaveThread"); } } } EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) { Mutex::Autolock lock(mMutex); if (keySize < 0 || valueSize < 0) { ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); return 0; } if (mInitialized) { sp bc = getBlobCacheLocked(); return bc->get(key, keySize, value, valueSize); } return 0; } void egl_cache_t::setCacheFilename(const char* filename) { Mutex::Autolock lock(mMutex); mFilename = filename; } sp egl_cache_t::getBlobCacheLocked() { if (mBlobCache == NULL) { mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize); loadBlobCacheLocked(); } return mBlobCache; } static uint32_t crc32c(const uint8_t* buf, size_t len) { const uint32_t polyBits = 0x82F63B78; uint32_t r = 0; for (size_t i = 0; i < len; i++) { r ^= buf[i]; for (int j = 0; j < 8; j++) { if (r & 1) { r = (r >> 1) ^ polyBits; } else { r >>= 1; } } } return r; } void egl_cache_t::saveBlobCacheLocked() { if (mFilename.length() > 0 && mBlobCache != NULL) { size_t cacheSize = mBlobCache->getFlattenedSize(); size_t headerSize = cacheFileHeaderSize; const char* fname = mFilename.string(); // Try to create the file with no permissions so we can write it // without anyone trying to read it. int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); if (fd == -1) { if (errno == EEXIST) { // The file exists, delete it and try again. if (unlink(fname) == -1) { // No point in retrying if the unlink failed. ALOGE("error unlinking cache file %s: %s (%d)", fname, strerror(errno), errno); return; } // Retry now that we've unlinked the file. fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); } if (fd == -1) { ALOGE("error creating cache file %s: %s (%d)", fname, strerror(errno), errno); return; } } size_t fileSize = headerSize + cacheSize; uint8_t* buf = new uint8_t [fileSize]; if (!buf) { ALOGE("error allocating buffer for cache contents: %s (%d)", strerror(errno), errno); close(fd); unlink(fname); return; } status_t err = mBlobCache->flatten(buf + headerSize, cacheSize); if (err != OK) { ALOGE("error writing cache contents: %s (%d)", strerror(-err), -err); delete [] buf; close(fd); unlink(fname); return; } // Write the file magic and CRC memcpy(buf, cacheFileMagic, 4); uint32_t* crc = reinterpret_cast(buf + 4); *crc = crc32c(buf + headerSize, cacheSize); if (write(fd, buf, fileSize) == -1) { ALOGE("error writing cache file: %s (%d)", strerror(errno), errno); delete [] buf; close(fd); unlink(fname); return; } delete [] buf; fchmod(fd, S_IRUSR); close(fd); } } void egl_cache_t::loadBlobCacheLocked() { if (mFilename.length() > 0) { size_t headerSize = cacheFileHeaderSize; int fd = open(mFilename.string(), O_RDONLY, 0); if (fd == -1) { if (errno != ENOENT) { ALOGE("error opening cache file %s: %s (%d)", mFilename.string(), strerror(errno), errno); } return; } struct stat statBuf; if (fstat(fd, &statBuf) == -1) { ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); close(fd); return; } // Sanity check the size before trying to mmap it. size_t fileSize = statBuf.st_size; if (fileSize > maxTotalSize * 2) { ALOGE("cache file is too large: %#" PRIx64, static_cast(statBuf.st_size)); close(fd); return; } uint8_t* buf = reinterpret_cast(mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); if (buf == MAP_FAILED) { ALOGE("error mmaping cache file: %s (%d)", strerror(errno), errno); close(fd); return; } // Check the file magic and CRC size_t cacheSize = fileSize - headerSize; if (memcmp(buf, cacheFileMagic, 4) != 0) { ALOGE("cache file has bad mojo"); close(fd); return; } uint32_t* crc = reinterpret_cast(buf + 4); if (crc32c(buf + headerSize, cacheSize) != *crc) { ALOGE("cache file failed CRC check"); close(fd); return; } status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize); if (err != OK) { ALOGE("error reading cache contents: %s (%d)", strerror(-err), -err); munmap(buf, fileSize); close(fd); return; } munmap(buf, fileSize); close(fd); } } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/EGL/egl_cache.h0100644 0000000 0000000 00000012256 13077405420 014504 0ustar000000000 0000000 /* ** Copyright 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_EGL_CACHE_H #define ANDROID_EGL_CACHE_H #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class egl_display_t; class EGLAPI egl_cache_t { public: // get returns a pointer to the singleton egl_cache_t object. This // singleton object will never be destroyed. static egl_cache_t* get(); // initialize puts the egl_cache_t into an initialized state, such that it // is able to insert and retrieve entries from the cache. This should be // called when EGL is initialized. When not in the initialized state the // getBlob and setBlob methods will return without performing any cache // operations. void initialize(egl_display_t* display); // terminate puts the egl_cache_t back into the uninitialized state. When // in this state the getBlob and setBlob methods will return without // performing any cache operations. void terminate(); // setBlob attempts to insert a new key/value blob pair into the cache. // This will be called by the hardware vendor's EGL implementation via the // EGL_ANDROID_blob_cache extension. void setBlob(const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize); // getBlob attempts to retrieve the value blob associated with a given key // blob from cache. This will be called by the hardware vendor's EGL // implementation via the EGL_ANDROID_blob_cache extension. EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize); // setCacheFilename sets the name of the file that should be used to store // cache contents from one program invocation to another. void setCacheFilename(const char* filename); private: // Creation and (the lack of) destruction is handled internally. egl_cache_t(); ~egl_cache_t(); // Copying is disallowed. egl_cache_t(const egl_cache_t&); // not implemented void operator=(const egl_cache_t&); // not implemented // getBlobCacheLocked returns the BlobCache object being used to store the // key/value blob pairs. If the BlobCache object has not yet been created, // this will do so, loading the serialized cache contents from disk if // possible. sp getBlobCacheLocked(); // saveBlobCache attempts to save the current contents of mBlobCache to // disk. void saveBlobCacheLocked(); // loadBlobCache attempts to load the saved cache contents from disk into // mBlobCache. void loadBlobCacheLocked(); // mInitialized indicates whether the egl_cache_t is in the initialized // state. It is initialized to false at construction time, and gets set to // true when initialize is called. It is set back to false when terminate // is called. When in this state, the cache behaves as normal. When not, // the getBlob and setBlob methods will return without performing any cache // operations. bool mInitialized; // mBlobCache is the cache in which the key/value blob pairs are stored. It // is initially NULL, and will be initialized by getBlobCacheLocked the // first time it's needed. sp mBlobCache; // mFilename is the name of the file for storing cache contents in between // program invocations. It is initialized to an empty string at // construction time, and can be set with the setCacheFilename method. An // empty string indicates that the cache should not be saved to or restored // from disk. String8 mFilename; // mSavePending indicates whether or not a deferred save operation is // pending. Each time a key/value pair is inserted into the cache via // setBlob, a deferred save is initiated if one is not already pending. // This will wait some amount of time and then trigger a save of the cache // contents to disk. bool mSavePending; // mMutex is the mutex used to prevent concurrent access to the member // variables. It must be locked whenever the member variables are accessed. mutable Mutex mMutex; // sCache is the singleton egl_cache_t object. static egl_cache_t sCache; }; // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif // ANDROID_EGL_CACHE_H opengl/libs/EGL/egl_display.cpp0100644 0000000 0000000 00000032714 13077405420 015442 0ustar000000000 0000000 /* ** Copyright 2007, 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. */ #define __STDC_LIMIT_MACROS 1 #include #include "../egl_impl.h" #include "egl_cache.h" #include "egl_display.h" #include "egl_object.h" #include "egl_tls.h" #include "Loader.h" #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- static char const * const sVendorString = "Android"; static char const * const sVersionString = "1.4 Android META-EGL"; static char const * const sClientApiString = "OpenGL_ES"; extern char const * const gBuiltinExtensionString; extern char const * const gExtensionString; extern void setGLHooksThreadSpecific(gl_hooks_t const *value); // ---------------------------------------------------------------------------- static bool findExtension(const char* exts, const char* name, size_t nameLen) { if (exts) { for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) { if (match[nameLen] == '\0' || match[nameLen] == ' ') { return true; } } } return false; } egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) { } egl_display_t::~egl_display_t() { magic = 0; egl_cache_t::get()->terminate(); } egl_display_t* egl_display_t::get(EGLDisplay dpy) { uintptr_t index = uintptr_t(dpy)-1U; return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index]; } void egl_display_t::addObject(egl_object_t* object) { Mutex::Autolock _l(lock); objects.add(object); } void egl_display_t::removeObject(egl_object_t* object) { Mutex::Autolock _l(lock); objects.remove(object); } bool egl_display_t::getObject(egl_object_t* object) const { Mutex::Autolock _l(lock); if (objects.indexOf(object) >= 0) { if (object->getDisplay() == this) { object->incRef(); return true; } } return false; } EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) { if (uintptr_t(disp) >= NUM_DISPLAYS) return NULL; return sDisplay[uintptr_t(disp)].getDisplay(disp); } EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { Mutex::Autolock _l(lock); // get our driver loader Loader& loader(Loader::getInstance()); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) { EGLDisplay dpy = cnx->egl.eglGetDisplay(display); disp.dpy = dpy; if (dpy == EGL_NO_DISPLAY) { loader.close(cnx->dso); cnx->dso = NULL; } } return EGLDisplay(uintptr_t(display) + 1U); } EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { { Mutex::Autolock _rf(refLock); refs++; if (refs > 1) { if (major != NULL) *major = VERSION_MAJOR; if (minor != NULL) *minor = VERSION_MINOR; while(!eglIsInitialized) refCond.wait(refLock); return EGL_TRUE; } while(eglIsInitialized) refCond.wait(refLock); } { Mutex::Autolock _l(lock); setGLHooksThreadSpecific(&gHooksNoContext); // initialize each EGL and // build our own extension string first, based on the extension we know // and the extension supported by our client implementation egl_connection_t* const cnx = &gEGLImpl; cnx->major = -1; cnx->minor = -1; if (cnx->dso) { EGLDisplay idpy = disp.dpy; if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", // idpy, cnx->major, cnx->minor, cnx); // display is now initialized disp.state = egl_display_t::INITIALIZED; // get the query-strings for this display for each implementation disp.queryString.vendor = cnx->egl.eglQueryString(idpy, EGL_VENDOR); disp.queryString.version = cnx->egl.eglQueryString(idpy, EGL_VERSION); disp.queryString.extensions = cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS); disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS); } else { ALOGW("eglInitialize(%p) failed (%s)", idpy, egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } } // the query strings are per-display mVendorString.setTo(sVendorString); mVersionString.setTo(sVersionString); mClientApiString.setTo(sClientApiString); mExtensionString.setTo(gBuiltinExtensionString); char const* start = gExtensionString; do { // length of the extension name size_t len = strcspn(start, " "); if (len) { // NOTE: we could avoid the copy if we had strnstr. const String8 ext(start, len); if (findExtension(disp.queryString.extensions, ext.string(), len)) { mExtensionString.append(ext + " "); } // advance to the next extension name, skipping the space. start += len; start += (*start == ' ') ? 1 : 0; } } while (*start != '\0'); egl_cache_t::get()->initialize(this); char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.finish", value, "0"); if (atoi(value)) { finishOnSwap = true; } property_get("debug.egl.traceGpuCompletion", value, "0"); if (atoi(value)) { traceGpuCompletion = true; } if (major != NULL) *major = VERSION_MAJOR; if (minor != NULL) *minor = VERSION_MINOR; mHibernation.setDisplayValid(true); } { Mutex::Autolock _rf(refLock); eglIsInitialized = true; refCond.broadcast(); } return EGL_TRUE; } EGLBoolean egl_display_t::terminate() { { Mutex::Autolock _rl(refLock); if (refs == 0) { /* * From the EGL spec (3.2): * "Termination of a display that has already been terminated, * (...), is allowed, but the only effect of such a call is * to return EGL_TRUE (...) */ return EGL_TRUE; } // this is specific to Android, display termination is ref-counted. refs--; if (refs > 0) { return EGL_TRUE; } } EGLBoolean res = EGL_FALSE; { Mutex::Autolock _l(lock); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } // REVISIT: it's unclear what to do if eglTerminate() fails disp.state = egl_display_t::TERMINATED; res = EGL_TRUE; } mHibernation.setDisplayValid(false); // Reset the extension string since it will be regenerated if we get // reinitialized. mExtensionString.setTo(""); // Mark all objects remaining in the list as terminated, unless // there are no reference to them, it which case, we're free to // delete them. size_t count = objects.size(); ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count); for (size_t i=0 ; idestroy(); } // this marks all object handles are "terminated" objects.clear(); } { Mutex::Autolock _rl(refLock); eglIsInitialized = false; refCond.broadcast(); } return res; } void egl_display_t::loseCurrent(egl_context_t * cur_c) { if (cur_c) { egl_display_t* display = cur_c->getDisplay(); if (display) { display->loseCurrentImpl(cur_c); } } } void egl_display_t::loseCurrentImpl(egl_context_t * cur_c) { // by construction, these are either 0 or valid (possibly terminated) // it should be impossible for these to be invalid ContextRef _cur_c(cur_c); SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); { // scope for the lock Mutex::Autolock _l(lock); cur_c->onLooseCurrent(); } // This cannot be called with the lock held because it might end-up // calling back into EGL (in particular when a surface is destroyed // it calls ANativeWindow::disconnect _cur_c.release(); _cur_r.release(); _cur_d.release(); } EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, EGLSurface draw, EGLSurface read, EGLContext /*ctx*/, EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx) { EGLBoolean result; // by construction, these are either 0 or valid (possibly terminated) // it should be impossible for these to be invalid ContextRef _cur_c(cur_c); SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); { // scope for the lock Mutex::Autolock _l(lock); if (c) { result = c->cnx->egl.eglMakeCurrent( disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { c->onMakeCurrent(draw, read); if (!cur_c) { mHibernation.incWakeCount(HibernationMachine::STRONG); } } } else { result = cur_c->cnx->egl.eglMakeCurrent( disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { cur_c->onLooseCurrent(); mHibernation.decWakeCount(HibernationMachine::STRONG); } } } if (result == EGL_TRUE) { // This cannot be called with the lock held because it might end-up // calling back into EGL (in particular when a surface is destroyed // it calls ANativeWindow::disconnect _cur_c.release(); _cur_r.release(); _cur_d.release(); } return result; } bool egl_display_t::haveExtension(const char* name, size_t nameLen) const { if (!nameLen) { nameLen = strlen(name); } return findExtension(mExtensionString.string(), name, nameLen); } // ---------------------------------------------------------------------------- bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) { Mutex::Autolock _l(mLock); ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX, "Invalid WakeCount (%d) on enter\n", mWakeCount); mWakeCount++; if (strength == STRONG) mAttemptHibernation = false; if (CC_UNLIKELY(mHibernating)) { ALOGV("Awakening\n"); egl_connection_t* const cnx = &gEGLImpl; // These conditions should be guaranteed before entering hibernation; // we don't want to get into a state where we can't wake up. ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG, "Invalid hibernation state, unable to awaken\n"); if (!cnx->egl.eglAwakenProcessIMG()) { ALOGE("Failed to awaken EGL implementation\n"); return false; } mHibernating = false; } return true; } void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) { Mutex::Autolock _l(mLock); ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount); mWakeCount--; if (strength == STRONG) mAttemptHibernation = true; if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) { egl_connection_t* const cnx = &gEGLImpl; mAttemptHibernation = false; if (mAllowHibernation && mDpyValid && cnx->egl.eglHibernateProcessIMG && cnx->egl.eglAwakenProcessIMG) { ALOGV("Hibernating\n"); if (!cnx->egl.eglHibernateProcessIMG()) { ALOGE("Failed to hibernate EGL implementation\n"); return; } mHibernating = true; } } } void egl_display_t::HibernationMachine::setDisplayValid(bool valid) { Mutex::Autolock _l(mLock); mDpyValid = valid; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/EGL/egl_display.h0100644 0000000 0000000 00000021533 13077405420 015104 0ustar000000000 0000000 /* ** Copyright 2007, 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_EGL_DISPLAY_H #define ANDROID_EGL_DISPLAY_H #include #include #include #include #include #include #include #include #include #include "egldefs.h" #include "../hooks.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class egl_object_t; class egl_context_t; struct egl_connection_t; // ---------------------------------------------------------------------------- class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes static egl_display_t sDisplay[NUM_DISPLAYS]; EGLDisplay getDisplay(EGLNativeDisplayType display); void loseCurrentImpl(egl_context_t * cur_c); public: enum { NOT_INITIALIZED = 0, INITIALIZED = 1, TERMINATED = 2 }; egl_display_t(); ~egl_display_t(); EGLBoolean initialize(EGLint *major, EGLint *minor); EGLBoolean terminate(); // add object to this display's list void addObject(egl_object_t* object); // remove object from this display's list void removeObject(egl_object_t* object); // add reference to this object. returns true if this is a valid object. bool getObject(egl_object_t* object) const; // These notifications allow the display to keep track of how many window // surfaces exist, which it uses to decide whether to hibernate the // underlying EGL implementation. They can be called by any thread without // holding a lock, but must be called via egl_display_ptr to ensure // proper hibernate/wakeup sequencing. If a surface destruction triggers // hibernation, hibernation will be delayed at least until the calling // thread's egl_display_ptr is destroyed. void onWindowSurfaceCreated() { mHibernation.incWakeCount(HibernationMachine::STRONG); } void onWindowSurfaceDestroyed() { mHibernation.decWakeCount(HibernationMachine::STRONG); } static egl_display_t* get(EGLDisplay dpy); static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp); EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c, EGLSurface draw, EGLSurface read, EGLContext ctx, EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx); static void loseCurrent(egl_context_t * cur_c); inline bool isReady() const { return (refs > 0); } inline bool isValid() const { return magic == '_dpy'; } inline bool isAlive() const { return isValid(); } char const * getVendorString() const { return mVendorString.string(); } char const * getVersionString() const { return mVersionString.string(); } char const * getClientApiString() const { return mClientApiString.string(); } char const * getExtensionString() const { return mExtensionString.string(); } bool haveExtension(const char* name, size_t nameLen = 0) const; inline uint32_t getRefsCount() const { return refs; } struct strings_t { char const * vendor; char const * version; char const * clientApi; char const * extensions; }; struct DisplayImpl { DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { } EGLDisplay dpy; EGLint state; strings_t queryString; }; private: uint32_t magic; public: DisplayImpl disp; bool finishOnSwap; // property: debug.egl.finish bool traceGpuCompletion; // property: debug.egl.traceGpuCompletion private: friend class egl_display_ptr; bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); } void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); } uint32_t refs; bool eglIsInitialized; mutable Mutex lock, refLock; mutable Condition refCond; SortedVector objects; String8 mVendorString; String8 mVersionString; String8 mClientApiString; String8 mExtensionString; // HibernationMachine uses its own internal mutex to protect its own data. // The owning egl_display_t's lock may be but is not required to be held // when calling HibernationMachine methods. As a result, nothing in this // class may call back up to egl_display_t directly or indirectly. class HibernationMachine { public: // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt // the next time the wakecount reaches zero. WEAK refs don't affect // whether a hibernation attempt will be made. Use STRONG refs only // for infrequent/heavy changes that are likely to indicate the // EGLDisplay is entering or leaving a long-term idle state. enum WakeRefStrength { WEAK = 0, STRONG = 1, }; HibernationMachine(): mWakeCount(0), mHibernating(false), mAttemptHibernation(false), mDpyValid(false), #if BOARD_ALLOW_EGL_HIBERNATION mAllowHibernation(true) #else mAllowHibernation(false) #endif {} ~HibernationMachine() {} bool incWakeCount(WakeRefStrength strenth); void decWakeCount(WakeRefStrength strenth); void setDisplayValid(bool valid); private: Mutex mLock; int32_t mWakeCount; bool mHibernating; bool mAttemptHibernation; bool mDpyValid; const bool mAllowHibernation; }; HibernationMachine mHibernation; }; // ---------------------------------------------------------------------------- // An egl_display_ptr is a kind of smart pointer for egl_display_t objects. // It doesn't refcount the egl_display_t, but does ensure that the underlying // EGL implementation is "awake" (not hibernating) and ready for use as long // as the egl_display_ptr exists. class egl_display_ptr { public: explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) { if (mDpy) { if (CC_UNLIKELY(!mDpy->enter())) { mDpy = NULL; } } } // We only really need a C++11 move constructor, not a copy constructor. // A move constructor would save an enter()/leave() pair on every EGL API // call. But enabling -std=c++0x causes lots of errors elsewhere, so I // can't use a move constructor until those are cleaned up. // // egl_display_ptr(egl_display_ptr&& other) { // mDpy = other.mDpy; // other.mDpy = NULL; // } // egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) { if (mDpy) { mDpy->enter(); } } ~egl_display_ptr() { if (mDpy) { mDpy->leave(); } } const egl_display_t* operator->() const { return mDpy; } egl_display_t* operator->() { return mDpy; } const egl_display_t* get() const { return mDpy; } egl_display_t* get() { return mDpy; } operator bool() const { return mDpy != NULL; } private: egl_display_t* mDpy; // non-assignable egl_display_ptr& operator=(const egl_display_ptr&); }; // ---------------------------------------------------------------------------- inline egl_display_ptr get_display(EGLDisplay dpy) { return egl_display_ptr(egl_display_t::get(dpy)); } // Does not ensure EGL is unhibernated. Use with caution: calls into the // underlying EGL implementation are not safe. inline egl_display_t* get_display_nowake(EGLDisplay dpy) { return egl_display_t::get(dpy); } // ---------------------------------------------------------------------------- egl_display_ptr validate_display(EGLDisplay dpy); egl_display_ptr validate_display_connection(EGLDisplay dpy, egl_connection_t*& cnx); EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx); EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface); // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif // ANDROID_EGL_DISPLAY_H opengl/libs/EGL/egl_entries.in0100644 0000000 0000000 00000012223 13077405420 015263 0ustar000000000 0000000 EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType) EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*) EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay) EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*) EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *) EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *) EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *) EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *) EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *) EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface) EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *) EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *) EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext) EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext) EGL_ENTRY(EGLContext, eglGetCurrentContext, void) EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint) EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void) EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *) EGL_ENTRY(EGLBoolean, eglWaitGL, void) EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint) EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface) EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType) EGL_ENTRY(EGLint, eglGetError, void) EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint) EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *) /* EGL 1.1 */ EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint) EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint) EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint) EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint) /* EGL 1.2 */ EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum) EGL_ENTRY(EGLenum, eglQueryAPI, void) EGL_ENTRY(EGLBoolean, eglWaitClient, void) EGL_ENTRY(EGLBoolean, eglReleaseThread, void) EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *) /* EGL 1.3 */ /* EGL 1.4 */ /* EGL_EGLEXT_VERSION 3 */ EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *) EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface) EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *) EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR) /* EGL_EGLEXT_VERSION 5 */ EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint *) EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR) EGL_ENTRY(EGLint, eglClientWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR) EGL_ENTRY(EGLBoolean, eglSignalSyncKHR, EGLDisplay, EGLSyncKHR, EGLenum) EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLint *) /* EGL_EGLEXT_VERSION 15 */ EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint *) EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR) EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint) EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint *) EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *) EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR) EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR) EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR) EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *) EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*) EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR) EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR) EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint) /* ANDROID extensions */ EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface) EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR) EGL_ENTRY(EGLClientBuffer, eglCreateNativeClientBufferANDROID, const EGLint *) /* NVIDIA extensions */ EGL_ENTRY(EGLuint64NV, eglGetSystemTimeFrequencyNV, void) EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void) /* IMG extensions */ EGL_ENTRY(EGLBoolean, eglHibernateProcessIMG, void) EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void) /* Partial update extensions */ EGL_ENTRY(EGLBoolean, eglSwapBuffersWithDamageKHR, EGLDisplay, EGLSurface, EGLint *, EGLint) EGL_ENTRY(EGLBoolean, eglSetDamageRegionKHR, EGLDisplay, EGLSurface, EGLint *, EGLint) opengl/libs/EGL/egl_object.cpp0100644 0000000 0000000 00000010521 13077405420 015233 0ustar000000000 0000000 /* ** Copyright 2007, 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 #include #include #include #include #include #include #include #include "egl_object.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- egl_object_t::egl_object_t(egl_display_t* disp) : display(disp), count(1) { // NOTE: this does an implicit incRef display->addObject(this); } egl_object_t::~egl_object_t() { } void egl_object_t::terminate() { // this marks the object as "terminated" display->removeObject(this); if (decRef() == 1) { // shouldn't happen because this is called from LocalRef ALOGE("egl_object_t::terminate() removed the last reference!"); } } void egl_object_t::destroy() { if (decRef() == 1) { delete this; } } bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // used by LocalRef, this does an incRef() atomically with // checking that the object is valid. return display->getObject(object); } // ---------------------------------------------------------------------------- egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, egl_connection_t const* cnx) : egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx), connected(true) { if (win) { getDisplay()->onWindowSurfaceCreated(); } } egl_surface_t::~egl_surface_t() { ANativeWindow* const window = win.get(); if (window != NULL) { disconnect(); getDisplay()->onWindowSurfaceDestroyed(); } } void egl_surface_t::disconnect() { ANativeWindow* const window = win.get(); if (window != NULL && connected) { native_window_set_buffers_format(window, 0); if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) { ALOGW("EGLNativeWindowType %p disconnect failed", window); } connected = false; } } void egl_surface_t::terminate() { disconnect(); egl_object_t::terminate(); } // ---------------------------------------------------------------------------- egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, egl_connection_t const* cnx, int version) : egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context), config(config), read(0), draw(0), cnx(cnx), version(version) { } void egl_context_t::onLooseCurrent() { read = NULL; draw = NULL; } void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { this->read = read; this->draw = draw; /* * Here we cache the GL_EXTENSIONS string for this context and we * add the extensions always handled by the wrapper */ if (gl_extensions.isEmpty()) { // call the implementation's glGetString(GL_EXTENSIONS) const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS); gl_extensions.setTo(exts); if (gl_extensions.find("GL_EXT_debug_marker") < 0) { String8 temp("GL_EXT_debug_marker "); temp.append(gl_extensions); gl_extensions.setTo(temp); } // tokenize the supported extensions for the glGetStringi() wrapper std::stringstream ss; std::string str; ss << gl_extensions.string(); while (ss >> str) { tokenized_gl_extensions.push(String8(str.c_str())); } } } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/EGL/egl_object.h0100644 0000000 0000000 00000012221 13077405420 014677 0ustar000000000 0000000 /* ** Copyright 2007, 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_EGL_OBJECT_H #define ANDROID_EGL_OBJECT_H #include #include #include #include #include #include #include #include #include #include #include "egl_display.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class egl_display_t; class egl_object_t { egl_display_t *display; mutable std::atomic_size_t count; protected: virtual ~egl_object_t(); virtual void terminate(); public: egl_object_t(egl_display_t* display); void destroy(); inline void incRef() { count.fetch_add(1, std::memory_order_relaxed); } inline size_t decRef() { return count.fetch_sub(1, std::memory_order_acq_rel); } inline egl_display_t* getDisplay() const { return display; } private: static bool get(egl_display_t const* display, egl_object_t* object); public: template class LocalRef { egl_object_t* ref; LocalRef(); LocalRef(const LocalRef* rhs); public: ~LocalRef(); explicit LocalRef(egl_object_t* rhs); explicit LocalRef(egl_display_t const* display, T o) : ref(0) { egl_object_t* native = reinterpret_cast(o); if (o && egl_object_t::get(display, native)) { ref = native; } } inline N* get() { return static_cast(ref); } void acquire() const; void release() const; void terminate(); }; template friend class LocalRef; }; template egl_object_t::LocalRef::LocalRef(egl_object_t* rhs) : ref(rhs) { if (ref) { ref->incRef(); } } template egl_object_t::LocalRef::~LocalRef() { if (ref) { ref->destroy(); } } template void egl_object_t::LocalRef::acquire() const { if (ref) { ref->incRef(); } } template void egl_object_t::LocalRef::release() const { if (ref) { if (ref->decRef() == 1) { // shouldn't happen because this is called from LocalRef ALOGE("LocalRef::release() removed the last reference!"); } } } template void egl_object_t::LocalRef::terminate() { if (ref) { ref->terminate(); } } // ---------------------------------------------------------------------------- class egl_surface_t : public egl_object_t { protected: ~egl_surface_t(); void terminate() override; public: typedef egl_object_t::LocalRef Ref; egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, egl_connection_t const* cnx); EGLSurface surface; EGLConfig config; sp win; egl_connection_t const* cnx; private: bool connected; void disconnect(); }; class egl_context_t: public egl_object_t { protected: ~egl_context_t() {} public: typedef egl_object_t::LocalRef Ref; egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, egl_connection_t const* cnx, int version); void onLooseCurrent(); void onMakeCurrent(EGLSurface draw, EGLSurface read); EGLDisplay dpy; EGLContext context; EGLConfig config; EGLSurface read; EGLSurface draw; egl_connection_t const* cnx; int version; String8 gl_extensions; Vector tokenized_gl_extensions; }; // ---------------------------------------------------------------------------- typedef egl_surface_t::Ref SurfaceRef; typedef egl_context_t::Ref ContextRef; // ---------------------------------------------------------------------------- template static inline NATIVE* egl_to_native_cast(EGL arg) { return reinterpret_cast(arg); } static inline egl_surface_t* get_surface(EGLSurface surface) { return egl_to_native_cast(surface); } static inline egl_context_t* get_context(EGLContext context) { return egl_to_native_cast(context); } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif // ANDROID_EGL_OBJECT_H opengl/libs/EGL/egl_tls.cpp0100644 0000000 0000000 00000010515 13077405420 014572 0ustar000000000 0000000 /* ** Copyright 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 #include #include #include #include #include #include "egl_tls.h" namespace android { pthread_key_t egl_tls_t::sKey = TLS_KEY_NOT_INITIALIZED; pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT; egl_tls_t::egl_tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { } const char *egl_tls_t::egl_strerror(EGLint err) { switch (err) { case EGL_SUCCESS: return "EGL_SUCCESS"; case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; default: return "UNKNOWN"; } } void egl_tls_t::validateTLSKey() { struct TlsKeyInitializer { static void create() { pthread_key_create(&sKey, (void (*)(void*))&eglReleaseThread); } }; pthread_once(&sOnceKey, TlsKeyInitializer::create); } void egl_tls_t::setErrorEtcImpl( const char* caller, int line, EGLint error, bool quiet) { validateTLSKey(); egl_tls_t* tls = getTLS(); if (tls->error != error) { if (!quiet) { ALOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error)); char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { CallStack stack(LOG_TAG); } } tls->error = error; } } bool egl_tls_t::logNoContextCall() { egl_tls_t* tls = getTLS(); if (tls->logCallWithNoContext == true) { tls->logCallWithNoContext = false; return true; } return false; } egl_tls_t* egl_tls_t::getTLS() { egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey); if (tls == 0) { tls = new egl_tls_t; pthread_setspecific(sKey, tls); } return tls; } void egl_tls_t::clearTLS() { if (sKey != TLS_KEY_NOT_INITIALIZED) { egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey); if (tls) { pthread_setspecific(sKey, 0); delete tls; } } } void egl_tls_t::clearError() { // This must clear the error from all the underlying EGL implementations as // well as the EGL wrapper layer. eglGetError(); } EGLint egl_tls_t::getError() { if (sKey == TLS_KEY_NOT_INITIALIZED) { return EGL_SUCCESS; } egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey); if (!tls) { return EGL_SUCCESS; } EGLint error = tls->error; tls->error = EGL_SUCCESS; return error; } void egl_tls_t::setContext(EGLContext ctx) { validateTLSKey(); getTLS()->ctx = ctx; } EGLContext egl_tls_t::getContext() { if (sKey == TLS_KEY_NOT_INITIALIZED) { return EGL_NO_CONTEXT; } egl_tls_t* tls = (egl_tls_t *)pthread_getspecific(sKey); if (!tls) return EGL_NO_CONTEXT; return tls->ctx; } } // namespace android opengl/libs/EGL/egl_tls.h0100644 0000000 0000000 00000004312 13077405420 014235 0ustar000000000 0000000 /* ** Copyright 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_EGL_TLS_H #define ANDROID_EGL_TLS_H #include #include #include "egldefs.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class DbgContext; class egl_tls_t { enum { TLS_KEY_NOT_INITIALIZED = -1 }; static pthread_key_t sKey; static pthread_once_t sOnceKey; EGLint error; EGLContext ctx; EGLBoolean logCallWithNoContext; egl_tls_t(); static void validateTLSKey(); static void setErrorEtcImpl( const char* caller, int line, EGLint error, bool quiet); public: static egl_tls_t* getTLS(); static void clearTLS(); static void clearError(); static EGLint getError(); static void setContext(EGLContext ctx); static EGLContext getContext(); static bool logNoContextCall(); static const char *egl_strerror(EGLint err); template static T setErrorEtc(const char* caller, int line, EGLint error, T returnValue, bool quiet = false) { setErrorEtcImpl(caller, line, error, quiet); return returnValue; } }; #define setError(_e, _r) \ egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r) #define setErrorQuiet(_e, _r) \ egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r, true) // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif // ANDROID_EGL_TLS_H opengl/libs/EGL/egldefs.h0100644 0000000 0000000 00000004045 13077405420 014220 0ustar000000000 0000000 /* ** Copyright 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_EGLDEFS_H #define ANDROID_EGLDEFS_H #include "../hooks.h" #define VERSION_MAJOR 1 #define VERSION_MINOR 4 // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- // EGLDisplay are global, not attached to a given thread const unsigned int NUM_DISPLAYS = 1; // ---------------------------------------------------------------------------- struct egl_connection_t { enum { GLESv1_INDEX = 0, GLESv2_INDEX = 1 }; inline egl_connection_t() : dso(0) { } void * dso; gl_hooks_t * hooks[2]; EGLint major; EGLint minor; egl_t egl; void* libEgl; void* libGles1; void* libGles2; }; // ---------------------------------------------------------------------------- extern gl_hooks_t gHooks[2]; extern gl_hooks_t gHooksNoContext; extern pthread_key_t gGLWrapperKey; extern "C" void gl_unimplemented(); extern "C" void gl_noop(); extern char const * const gl_names[]; extern char const * const egl_names[]; extern egl_connection_t gEGLImpl; // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif /* ANDROID_EGLDEFS_H */ opengl/libs/EGL/getProcAddress.cpp0100644 0000000 0000000 00000032232 13077405420 016052 0ustar000000000 0000000 /* ** Copyright 2009, 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 #include #include #include #include "egldefs.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- #undef API_ENTRY #undef CALL_GL_EXTENSION_API #undef GL_EXTENSION #undef GL_EXTENSION_NAME #undef GL_EXTENSION_ARRAY #undef GL_EXTENSION_LIST #undef GET_TLS #if defined(__arm__) #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" #define API_ENTRY(_api) __attribute__((naked)) _api #define CALL_GL_EXTENSION_API(_api) \ asm volatile( \ GET_TLS(r12) \ "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "addne r12, %[api] \n" \ "ldrne r12, [r12, %[ext]] \n" \ "cmpne r12, #0 \n" \ "bxne r12 \n" \ "bx lr \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ [ext] "J"(__builtin_offsetof(gl_hooks_t, \ ext.extensions[0])), \ [api] "J"(_api*sizeof(void*)) \ : "r12" \ ); #elif defined(__aarch64__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_EXTENSION_API(_api) \ asm volatile( \ "mrs x16, tpidr_el0\n" \ "ldr x16, [x16, %[tls]]\n" \ "cbz x16, 1f\n" \ "ldr x16, [x16, %[api]]\n" \ "cbz x16, 1f\n" \ "br x16\n" \ "1:\n" \ : \ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, \ ext.extensions[_api])) \ : "x16" \ ); #elif defined(__i386__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_EXTENSION_API(_api) \ register void** fn; \ __asm__ volatile( \ "mov %%gs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "cmovne %P[api](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%[fn]\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, \ ext.extensions[_api])) \ : "cc" \ ); #elif defined(__x86_64__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_EXTENSION_API(_api) \ register void** fn; \ __asm__ volatile( \ "mov %%fs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "cmovne %P[api](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%[fn]\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, \ ext.extensions[_api])) \ : "cc" \ ); #elif defined(__mips64) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_EXTENSION_API(_api, ...) \ register unsigned int _t0 asm("$12"); \ register unsigned int _fn asm("$25"); \ register unsigned int _tls asm("$3"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ "rdhwr %[tls], $29\n\t" \ "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ "ld %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " nop\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, \ ext.extensions[_api])) \ : \ ); #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_EXTENSION_API(_api, ...) \ register unsigned int _t0 asm("$8"); \ register unsigned int _fn asm("$25"); \ register unsigned int _tls asm("$3"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ "rdhwr %[tls], $29\n\t" \ "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ "lw %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " nop\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, \ ext.extensions[_api])) \ : \ ); #endif #if defined(CALL_GL_EXTENSION_API) #define GL_EXTENSION_NAME(_n) __glExtFwd##_n #define GL_EXTENSION(_n) \ void API_ENTRY(GL_EXTENSION_NAME(_n))() { \ CALL_GL_EXTENSION_API(_n); \ } #else #define GL_EXTENSION_NAME(_n) NULL #define GL_EXTENSION(_n) #warning "eglGetProcAddress() partially supported" #endif #define GL_EXTENSION_LIST(name) \ name(0) name(1) name(2) name(3) name(4) name(5) name(6) name(7) \ name(8) name(9) name(10) name(11) name(12) name(13) name(14) name(15) \ name(16) name(17) name(18) name(19) name(20) name(21) name(22) name(23) \ name(24) name(25) name(26) name(27) name(28) name(29) name(30) name(31) \ name(32) name(33) name(34) name(35) name(36) name(37) name(38) name(39) \ name(40) name(41) name(42) name(43) name(44) name(45) name(46) name(47) \ name(48) name(49) name(50) name(51) name(52) name(53) name(54) name(55) \ name(56) name(57) name(58) name(59) name(60) name(61) name(62) name(63) \ name(64) name(65) name(66) name(67) name(68) name(69) name(70) name(71) \ name(72) name(73) name(74) name(75) name(76) name(77) name(78) name(79) \ name(80) name(81) name(82) name(83) name(84) name(85) name(86) name(87) \ name(88) name(89) name(90) name(91) name(92) name(93) name(94) name(95) \ name(96) name(97) name(98) name(99) \ name(100) name(101) name(102) name(103) name(104) name(105) name(106) name(107) \ name(108) name(109) name(110) name(111) name(112) name(113) name(114) name(115) \ name(116) name(117) name(118) name(119) name(120) name(121) name(122) name(123) \ name(124) name(125) name(126) name(127) name(128) name(129) name(130) name(131) \ name(132) name(133) name(134) name(135) name(136) name(137) name(138) name(139) \ name(140) name(141) name(142) name(143) name(144) name(145) name(146) name(147) \ name(148) name(149) name(150) name(151) name(152) name(153) name(154) name(155) \ name(156) name(157) name(158) name(159) name(160) name(161) name(162) name(163) \ name(164) name(165) name(166) name(167) name(168) name(169) name(170) name(171) \ name(172) name(173) name(174) name(175) name(176) name(177) name(178) name(179) \ name(180) name(181) name(182) name(183) name(184) name(185) name(186) name(187) \ name(188) name(189) name(190) name(191) name(192) name(193) name(194) name(195) \ name(196) name(197) name(198) name(199) \ name(200) name(201) name(202) name(203) name(204) name(205) name(206) name(207) \ name(208) name(209) name(210) name(211) name(212) name(213) name(214) name(215) \ name(216) name(217) name(218) name(219) name(220) name(221) name(222) name(223) \ name(224) name(225) name(226) name(227) name(228) name(229) name(230) name(231) \ name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \ name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \ name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255) GL_EXTENSION_LIST( GL_EXTENSION ) #define GL_EXTENSION_ARRAY(_n) GL_EXTENSION_NAME(_n), extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS] = { GL_EXTENSION_LIST( GL_EXTENSION_ARRAY ) }; #undef GET_TLS #undef GL_EXTENSION_LIST #undef GL_EXTENSION_ARRAY #undef GL_EXTENSION_NAME #undef GL_EXTENSION #undef API_ENTRY #undef CALL_GL_EXTENSION_API // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- opengl/libs/ETC1/0040755 0000000 0000000 00000000000 13077405420 012523 5ustar000000000 0000000 opengl/libs/ETC1/etc1.cpp0100644 0000000 0000000 00000052667 13077405420 014100 0ustar000000000 0000000 // Copyright 2009 Google Inc. // // 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 #include /* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt The number of bits that represent a 4x4 texel block is 64 bits if is given by ETC1_RGB8_OES. The data for a block is a number of bytes, {q0, q1, q2, q3, q4, q5, q6, q7} where byte q0 is located at the lowest memory address and q7 at the highest. The 64 bits specifying the block is then represented by the following 64 bit integer: int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; ETC1_RGB8_OES: a) bit layout in bits 63 through 32 if diffbit = 0 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 ----------------------------------------------- | base col1 | base col2 | base col1 | base col2 | | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| ----------------------------------------------- 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 --------------------------------------------------- | base col1 | base col2 | table | table |diff|flip| | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | --------------------------------------------------- b) bit layout in bits 63 through 32 if diffbit = 1 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 ----------------------------------------------- | base col1 | dcol 2 | base col1 | dcol 2 | | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | ----------------------------------------------- 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 --------------------------------------------------- | base col 1 | dcol 2 | table | table |diff|flip| | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | --------------------------------------------------- c) bit layout in bits 31 through 0 (in both cases) 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 ----------------------------------------------- | most significant pixel index bits | | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| ----------------------------------------------- 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -------------------------------------------------- | least significant pixel index bits | | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | -------------------------------------------------- Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: table codeword modifier table ------------------ ---------------------- 0 -8 -2 2 8 1 -17 -5 5 17 2 -29 -9 9 29 3 -42 -13 13 42 4 -60 -18 18 60 5 -80 -24 24 80 6 -106 -33 33 106 7 -183 -47 47 183 Add table 3.17.3 Mapping from pixel index values to modifier values for ETC1 compressed textures: pixel index value --------------- msb lsb resulting modifier value ----- ----- ------------------------- 1 1 -b (large negative value) 1 0 -a (small negative value) 0 0 a (small positive value) 0 1 b (large positive value) */ static const int kModifierTable[] = { /* 0 */2, 8, -2, -8, /* 1 */5, 17, -5, -17, /* 2 */9, 29, -9, -29, /* 3 */13, 42, -13, -42, /* 4 */18, 60, -18, -60, /* 5 */24, 80, -24, -80, /* 6 */33, 106, -33, -106, /* 7 */47, 183, -47, -183 }; static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; static inline etc1_byte clamp(int x) { return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); } static inline int convert4To8(int b) { int c = b & 0xf; return (c << 4) | c; } static inline int convert5To8(int b) { int c = b & 0x1f; return (c << 3) | (c >> 2); } static inline int convert6To8(int b) { int c = b & 0x3f; return (c << 2) | (c >> 4); } static inline int divideBy255(int d) { return (d + 128 + (d >> 8)) >> 8; } static inline int convert8To4(int b) { int c = b & 0xff; return divideBy255(c * 15); } static inline int convert8To5(int b) { int c = b & 0xff; return divideBy255(c * 31); } static inline int convertDiff(int base, int diff) { return convert5To8((0x1f & base) + kLookup[0x7 & diff]); } static void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, etc1_uint32 low, bool second, bool flipped) { int baseX = 0; int baseY = 0; if (second) { if (flipped) { baseY = 2; } else { baseX = 2; } } for (int i = 0; i < 8; i++) { int x, y; if (flipped) { x = baseX + (i >> 1); y = baseY + (i & 1); } else { x = baseX + (i >> 2); y = baseY + (i & 3); } int k = y + (x * 4); int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); int delta = table[offset]; etc1_byte* q = pOut + 3 * (x + 4 * y); *q++ = clamp(r + delta); *q++ = clamp(g + delta); *q++ = clamp(b + delta); } } // Input is an ETC1 compressed version of the data. // Output is a 4 x 4 square of 3-byte pixels in form R, G, B void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; int r1, r2, g1, g2, b1, b2; if (high & 2) { // differential int rBase = high >> 27; int gBase = high >> 19; int bBase = high >> 11; r1 = convert5To8(rBase); r2 = convertDiff(rBase, high >> 24); g1 = convert5To8(gBase); g2 = convertDiff(gBase, high >> 16); b1 = convert5To8(bBase); b2 = convertDiff(bBase, high >> 8); } else { // not differential r1 = convert4To8(high >> 28); r2 = convert4To8(high >> 24); g1 = convert4To8(high >> 20); g2 = convert4To8(high >> 16); b1 = convert4To8(high >> 12); b2 = convert4To8(high >> 8); } int tableIndexA = 7 & (high >> 5); int tableIndexB = 7 & (high >> 2); const int* tableA = kModifierTable + tableIndexA * 4; const int* tableB = kModifierTable + tableIndexB * 4; bool flipped = (high & 1) != 0; decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); } typedef struct { etc1_uint32 high; etc1_uint32 low; etc1_uint32 score; // Lower is more accurate } etc_compressed; static inline void take_best(etc_compressed* a, const etc_compressed* b) { if (a->score > b->score) { *a = *b; } } static void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, etc1_byte* pColors, bool flipped, bool second) { int r = 0; int g = 0; int b = 0; if (flipped) { int by = 0; if (second) { by = 2; } for (int y = 0; y < 2; y++) { int yy = by + y; for (int x = 0; x < 4; x++) { int i = x + 4 * yy; if (inMask & (1 << i)) { const etc1_byte* p = pIn + i * 3; r += *(p++); g += *(p++); b += *(p++); } } } } else { int bx = 0; if (second) { bx = 2; } for (int y = 0; y < 4; y++) { for (int x = 0; x < 2; x++) { int xx = bx + x; int i = xx + 4 * y; if (inMask & (1 << i)) { const etc1_byte* p = pIn + i * 3; r += *(p++); g += *(p++); b += *(p++); } } } } pColors[0] = (etc1_byte)((r + 4) >> 3); pColors[1] = (etc1_byte)((g + 4) >> 3); pColors[2] = (etc1_byte)((b + 4) >> 3); } static inline int square(int x) { return x * x; } static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, const int* pModifierTable) { etc1_uint32 bestScore = ~0; int bestIndex = 0; int pixelR = pIn[0]; int pixelG = pIn[1]; int pixelB = pIn[2]; int r = pBaseColors[0]; int g = pBaseColors[1]; int b = pBaseColors[2]; for (int i = 0; i < 4; i++) { int modifier = pModifierTable[i]; int decodedG = clamp(g + modifier); etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); if (score >= bestScore) { continue; } int decodedR = clamp(r + modifier); score += (etc1_uint32) (3 * square(decodedR - pixelR)); if (score >= bestScore) { continue; } int decodedB = clamp(b + modifier); score += (etc1_uint32) square(decodedB - pixelB); if (score < bestScore) { bestScore = score; bestIndex = i; } } etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) << bitIndex; *pLow |= lowMask; return bestScore; } static void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, etc_compressed* pCompressed, bool flipped, bool second, const etc1_byte* pBaseColors, const int* pModifierTable) { int score = pCompressed->score; if (flipped) { int by = 0; if (second) { by = 2; } for (int y = 0; y < 2; y++) { int yy = by + y; for (int x = 0; x < 4; x++) { int i = x + 4 * yy; if (inMask & (1 << i)) { score += chooseModifier(pBaseColors, pIn + i * 3, &pCompressed->low, yy + x * 4, pModifierTable); } } } } else { int bx = 0; if (second) { bx = 2; } for (int y = 0; y < 4; y++) { for (int x = 0; x < 2; x++) { int xx = bx + x; int i = xx + 4 * y; if (inMask & (1 << i)) { score += chooseModifier(pBaseColors, pIn + i * 3, &pCompressed->low, y + xx * 4, pModifierTable); } } } } pCompressed->score = score; } static bool inRange4bitSigned(int color) { return color >= -4 && color <= 3; } static void etc_encodeBaseColors(etc1_byte* pBaseColors, const etc1_byte* pColors, etc_compressed* pCompressed) { int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks bool differential; { int r51 = convert8To5(pColors[0]); int g51 = convert8To5(pColors[1]); int b51 = convert8To5(pColors[2]); int r52 = convert8To5(pColors[3]); int g52 = convert8To5(pColors[4]); int b52 = convert8To5(pColors[5]); r1 = convert5To8(r51); g1 = convert5To8(g51); b1 = convert5To8(b51); int dr = r52 - r51; int dg = g52 - g51; int db = b52 - b51; differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) && inRange4bitSigned(db); if (differential) { r2 = convert5To8(r51 + dr); g2 = convert5To8(g51 + dg); b2 = convert5To8(b51 + db); pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; } } if (!differential) { int r41 = convert8To4(pColors[0]); int g41 = convert8To4(pColors[1]); int b41 = convert8To4(pColors[2]); int r42 = convert8To4(pColors[3]); int g42 = convert8To4(pColors[4]); int b42 = convert8To4(pColors[5]); r1 = convert4To8(r41); g1 = convert4To8(g41); b1 = convert4To8(b41); r2 = convert4To8(r42); g2 = convert4To8(g42); b2 = convert4To8(b42); pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 << 16) | (b41 << 12) | (b42 << 8); } pBaseColors[0] = r1; pBaseColors[1] = g1; pBaseColors[2] = b1; pBaseColors[3] = r2; pBaseColors[4] = g2; pBaseColors[5] = b2; } static void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { pCompressed->score = ~0; pCompressed->high = (flipped ? 1 : 0); pCompressed->low = 0; etc1_byte pBaseColors[6]; etc_encodeBaseColors(pBaseColors, pColors, pCompressed); int originalHigh = pCompressed->high; const int* pModifierTable = kModifierTable; for (int i = 0; i < 8; i++, pModifierTable += 4) { etc_compressed temp; temp.score = 0; temp.high = originalHigh | (i << 5); temp.low = 0; etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, pBaseColors, pModifierTable); take_best(pCompressed, &temp); } pModifierTable = kModifierTable; etc_compressed firstHalf = *pCompressed; for (int i = 0; i < 8; i++, pModifierTable += 4) { etc_compressed temp; temp.score = firstHalf.score; temp.high = firstHalf.high | (i << 2); temp.low = firstHalf.low; etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, pBaseColors + 3, pModifierTable); if (i == 0) { *pCompressed = temp; } else { take_best(pCompressed, &temp); } } } static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { pOut[0] = (etc1_byte)(d >> 24); pOut[1] = (etc1_byte)(d >> 16); pOut[2] = (etc1_byte)(d >> 8); pOut[3] = (etc1_byte) d; } // Input is a 4 x 4 square of 3-byte pixels in form R, G, B // inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) // pixel is valid or not. Invalid pixel color values are ignored when compressing. // Output is an ETC1 compressed version of the data. void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, etc1_byte* pOut) { etc1_byte colors[6]; etc1_byte flippedColors[6]; etc_average_colors_subblock(pIn, inMask, colors, false, false); etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); etc_compressed a, b; etc_encode_block_helper(pIn, inMask, colors, &a, false); etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); take_best(&a, &b); writeBigEndian(pOut, a.high); writeBigEndian(pOut + 4, a.low); } // Return the size of the encoded image data (does not include size of PKM header). etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; } // Encode an entire image. // pIn - pointer to the image data. Formatted such that the Red component of // pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; // pOut - pointer to encoded data. Must be large enough to store entire encoded image. int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { if (pixelSize < 2 || pixelSize > 3) { return -1; } static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, 0xffff }; etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; etc1_uint32 encodedWidth = (width + 3) & ~3; etc1_uint32 encodedHeight = (height + 3) & ~3; for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { etc1_uint32 yEnd = height - y; if (yEnd > 4) { yEnd = 4; } int ymask = kYMask[yEnd]; for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { etc1_uint32 xEnd = width - x; if (xEnd > 4) { xEnd = 4; } int mask = ymask & kXMask[xEnd]; for (etc1_uint32 cy = 0; cy < yEnd; cy++) { etc1_byte* q = block + (cy * 4) * 3; const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); if (pixelSize == 3) { memcpy(q, p, xEnd * 3); } else { for (etc1_uint32 cx = 0; cx < xEnd; cx++) { int pixel = (p[1] << 8) | p[0]; *q++ = convert5To8(pixel >> 11); *q++ = convert6To8(pixel >> 5); *q++ = convert5To8(pixel); p += pixelSize; } } } etc1_encode_block(block, mask, encoded); memcpy(pOut, encoded, sizeof(encoded)); pOut += sizeof(encoded); } } return 0; } // Decode an entire image. // pIn - pointer to encoded data. // pOut - pointer to the image data. Will be written such that the Red component of // pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be // large enough to store entire image. int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, etc1_uint32 width, etc1_uint32 height, etc1_uint32 pixelSize, etc1_uint32 stride) { if (pixelSize < 2 || pixelSize > 3) { return -1; } etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; etc1_uint32 encodedWidth = (width + 3) & ~3; etc1_uint32 encodedHeight = (height + 3) & ~3; for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { etc1_uint32 yEnd = height - y; if (yEnd > 4) { yEnd = 4; } for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { etc1_uint32 xEnd = width - x; if (xEnd > 4) { xEnd = 4; } etc1_decode_block(pIn, block); pIn += ETC1_ENCODED_BLOCK_SIZE; for (etc1_uint32 cy = 0; cy < yEnd; cy++) { const etc1_byte* q = block + (cy * 4) * 3; etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); if (pixelSize == 3) { memcpy(p, q, xEnd * 3); } else { for (etc1_uint32 cx = 0; cx < xEnd; cx++) { etc1_byte r = *q++; etc1_byte g = *q++; etc1_byte b = *q++; etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); *p++ = (etc1_byte) pixel; *p++ = (etc1_byte) (pixel >> 8); } } } } } return 0; } static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { pOut[0] = (etc1_byte) (data >> 8); pOut[1] = (etc1_byte) data; } static etc1_uint32 readBEUint16(const etc1_byte* pIn) { return (pIn[0] << 8) | pIn[1]; } // Format a PKM header void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { memcpy(pHeader, kMagic, sizeof(kMagic)); etc1_uint32 encodedWidth = (width + 3) & ~3; etc1_uint32 encodedHeight = (height + 3) & ~3; writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); } // Check if a PKM header is correctly formatted. etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { if (memcmp(pHeader, kMagic, sizeof(kMagic))) { return false; } etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); return format == ETC1_RGB_NO_MIPMAPS && encodedWidth >= width && encodedWidth - width < 4 && encodedHeight >= height && encodedHeight - height < 4; } // Read the image width from a PKM header etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); } // Read the image height from a PKM header etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); } opengl/libs/GLES2/0040755 0000000 0000000 00000000000 13077405420 012643 5ustar000000000 0000000 opengl/libs/GLES2/gl2.cpp0100644 0000000 0000000 00000027435 13077405420 014043 0ustar000000000 0000000 /* ** Copyright 2007, 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 #include #include #include #include #include #include "../hooks.h" #include "../egl_impl.h" using namespace android; // ---------------------------------------------------------------------------- // Actual GL entry-points // ---------------------------------------------------------------------------- #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN #if USE_SLOW_BINDING #define API_ENTRY(_api) _api #define CALL_GL_API(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ if (_c) return _c->_api(__VA_ARGS__); #elif defined(__arm__) #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ asm volatile( \ GET_TLS(r12) \ "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : "r12" \ ); #elif defined(__aarch64__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ asm volatile( \ "mrs x16, tpidr_el0\n" \ "ldr x16, [x16, %[tls]]\n" \ "cbz x16, 1f\n" \ "ldr x16, [x16, %[api]]\n" \ "br x16\n" \ "1:\n" \ : \ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "x16" \ ); #elif defined(__i386__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ __asm__ volatile( \ "mov %%gs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%P[api](%[fn])\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "cc" \ ); #elif defined(__x86_64__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ __asm__ volatile( \ "mov %%fs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%P[api](%[fn])\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "cc" \ ); #elif defined(__mips64) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ register unsigned long _t0 asm("$12"); \ register unsigned long _fn asm("$25"); \ register unsigned long _tls asm("$3"); \ register unsigned long _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ "rdhwr %[tls], $29\n\t" \ "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ "ld %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0), \ [v0] "=&r"(_v0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ ); #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ register unsigned int _t0 asm("$8"); \ register unsigned int _fn asm("$25"); \ register unsigned int _tls asm("$3"); \ register unsigned int _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ "rdhwr %[tls], $29\n\t" \ "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn],$ra\n\t" \ "lw %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0), \ [v0] "=&r"(_v0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ ); #endif #define CALL_GL_API_RETURN(_api, ...) \ CALL_GL_API(_api, __VA_ARGS__) \ return 0; extern "C" { #pragma GCC diagnostic ignored "-Wunused-parameter" #include "gl2_api.in" #include "gl2ext_api.in" #pragma GCC diagnostic warning "-Wunused-parameter" } #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN /* * glGetString() and glGetStringi() are special because we expose some * extensions in the wrapper. Also, wrapping glGetXXX() is required because * the value returned for GL_NUM_EXTENSIONS may have been altered by the * injection of the additional extensions. */ extern "C" { const GLubyte * __glGetString(GLenum name); const GLubyte * __glGetStringi(GLenum name, GLuint index); void __glGetBooleanv(GLenum pname, GLboolean * data); void __glGetFloatv(GLenum pname, GLfloat * data); void __glGetIntegerv(GLenum pname, GLint * data); void __glGetInteger64v(GLenum pname, GLint64 * data); } const GLubyte * glGetString(GLenum name) { const GLubyte * ret = egl_get_string_for_current_context(name); if (ret == NULL) { gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if(_c) ret = _c->glGetString(name); } return ret; } const GLubyte * glGetStringi(GLenum name, GLuint index) { const GLubyte * ret = egl_get_string_for_current_context(name, index); if (ret == NULL) { gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if(_c) ret = _c->glGetStringi(name, index); } return ret; } void glGetBooleanv(GLenum pname, GLboolean * data) { if (pname == GL_NUM_EXTENSIONS) { int num_exts = egl_get_num_extensions_for_current_context(); if (num_exts >= 0) { *data = num_exts > 0 ? GL_TRUE : GL_FALSE; return; } } gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if (_c) _c->glGetBooleanv(pname, data); } void glGetFloatv(GLenum pname, GLfloat * data) { if (pname == GL_NUM_EXTENSIONS) { int num_exts = egl_get_num_extensions_for_current_context(); if (num_exts >= 0) { *data = (GLfloat)num_exts; return; } } gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if (_c) _c->glGetFloatv(pname, data); } void glGetIntegerv(GLenum pname, GLint * data) { if (pname == GL_NUM_EXTENSIONS) { int num_exts = egl_get_num_extensions_for_current_context(); if (num_exts >= 0) { *data = (GLint)num_exts; return; } } gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if (_c) _c->glGetIntegerv(pname, data); } void glGetInteger64v(GLenum pname, GLint64 * data) { if (pname == GL_NUM_EXTENSIONS) { int num_exts = egl_get_num_extensions_for_current_context(); if (num_exts >= 0) { *data = (GLint64)num_exts; return; } } gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; if (_c) _c->glGetInteger64v(pname, data); } opengl/libs/GLES2/gl2_api.in0100644 0000000 0000000 00000154366 13077405420 014524 0ustar000000000 0000000 void API_ENTRY(glActiveTexture)(GLenum texture) { CALL_GL_API(glActiveTexture, texture); } void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) { CALL_GL_API(glAttachShader, program, shader); } void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar *name) { CALL_GL_API(glBindAttribLocation, program, index, name); } void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { CALL_GL_API(glBindBuffer, target, buffer); } void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) { CALL_GL_API(glBindFramebuffer, target, framebuffer); } void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) { CALL_GL_API(glBindRenderbuffer, target, renderbuffer); } void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { CALL_GL_API(glBindTexture, target, texture); } void API_ENTRY(glBlendColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { CALL_GL_API(glBlendColor, red, green, blue, alpha); } void API_ENTRY(glBlendEquation)(GLenum mode) { CALL_GL_API(glBlendEquation, mode); } void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) { CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha); } void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { CALL_GL_API(glBlendFunc, sfactor, dfactor); } void API_ENTRY(glBlendFuncSeparate)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) { CALL_GL_API(glBlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); } void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage) { CALL_GL_API(glBufferData, target, size, data, usage); } void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { CALL_GL_API(glBufferSubData, target, offset, size, data); } GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) { CALL_GL_API_RETURN(glCheckFramebufferStatus, target); } void API_ENTRY(glClear)(GLbitfield mask) { CALL_GL_API(glClear, mask); } void API_ENTRY(glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { CALL_GL_API(glClearColor, red, green, blue, alpha); } void API_ENTRY(glClearDepthf)(GLfloat d) { CALL_GL_API(glClearDepthf, d); } void API_ENTRY(glClearStencil)(GLint s) { CALL_GL_API(glClearStencil, s); } void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { CALL_GL_API(glColorMask, red, green, blue, alpha); } void API_ENTRY(glCompileShader)(GLuint shader) { CALL_GL_API(glCompileShader, shader); } void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); } void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); } void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border); } void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); } GLuint API_ENTRY(glCreateProgram)(void) { CALL_GL_API_RETURN(glCreateProgram); } GLuint API_ENTRY(glCreateShader)(GLenum type) { CALL_GL_API_RETURN(glCreateShader, type); } void API_ENTRY(glCullFace)(GLenum mode) { CALL_GL_API(glCullFace, mode); } void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint *buffers) { CALL_GL_API(glDeleteBuffers, n, buffers); } void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers) { CALL_GL_API(glDeleteFramebuffers, n, framebuffers); } void API_ENTRY(glDeleteProgram)(GLuint program) { CALL_GL_API(glDeleteProgram, program); } void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint *renderbuffers) { CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers); } void API_ENTRY(glDeleteShader)(GLuint shader) { CALL_GL_API(glDeleteShader, shader); } void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) { CALL_GL_API(glDeleteTextures, n, textures); } void API_ENTRY(glDepthFunc)(GLenum func) { CALL_GL_API(glDepthFunc, func); } void API_ENTRY(glDepthMask)(GLboolean flag) { CALL_GL_API(glDepthMask, flag); } void API_ENTRY(glDepthRangef)(GLfloat n, GLfloat f) { CALL_GL_API(glDepthRangef, n, f); } void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) { CALL_GL_API(glDetachShader, program, shader); } void API_ENTRY(glDisable)(GLenum cap) { CALL_GL_API(glDisable, cap); } void API_ENTRY(glDisableVertexAttribArray)(GLuint index) { CALL_GL_API(glDisableVertexAttribArray, index); } void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { CALL_GL_API(glDrawArrays, mode, first, count); } void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void *indices) { CALL_GL_API(glDrawElements, mode, count, type, indices); } void API_ENTRY(glEnable)(GLenum cap) { CALL_GL_API(glEnable, cap); } void API_ENTRY(glEnableVertexAttribArray)(GLuint index) { CALL_GL_API(glEnableVertexAttribArray, index); } void API_ENTRY(glFinish)(void) { CALL_GL_API(glFinish); } void API_ENTRY(glFlush)(void) { CALL_GL_API(glFlush); } void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer); } void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level); } void API_ENTRY(glFrontFace)(GLenum mode) { CALL_GL_API(glFrontFace, mode); } void API_ENTRY(glGenBuffers)(GLsizei n, GLuint *buffers) { CALL_GL_API(glGenBuffers, n, buffers); } void API_ENTRY(glGenerateMipmap)(GLenum target) { CALL_GL_API(glGenerateMipmap, target); } void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint *framebuffers) { CALL_GL_API(glGenFramebuffers, n, framebuffers); } void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint *renderbuffers) { CALL_GL_API(glGenRenderbuffers, n, renderbuffers); } void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) { CALL_GL_API(glGenTextures, n, textures); } void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { CALL_GL_API(glGetActiveAttrib, program, index, bufSize, length, size, type, name); } void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { CALL_GL_API(glGetActiveUniform, program, index, bufSize, length, size, type, name); } void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) { CALL_GL_API(glGetAttachedShaders, program, maxCount, count, shaders); } GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar *name) { CALL_GL_API_RETURN(glGetAttribLocation, program, name); } void API_ENTRY(__glGetBooleanv)(GLenum pname, GLboolean *data) { CALL_GL_API(glGetBooleanv, pname, data); } void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetBufferParameteriv, target, pname, params); } GLenum API_ENTRY(glGetError)(void) { CALL_GL_API_RETURN(glGetError); } void API_ENTRY(__glGetFloatv)(GLenum pname, GLfloat *data) { CALL_GL_API(glGetFloatv, pname, data); } void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params) { CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params); } void API_ENTRY(__glGetIntegerv)(GLenum pname, GLint *data) { CALL_GL_API(glGetIntegerv, pname, data); } void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint *params) { CALL_GL_API(glGetProgramiv, program, pname, params); } void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { CALL_GL_API(glGetProgramInfoLog, program, bufSize, length, infoLog); } void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params); } void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint *params) { CALL_GL_API(glGetShaderiv, shader, pname, params); } void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { CALL_GL_API(glGetShaderInfoLog, shader, bufSize, length, infoLog); } void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision) { CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision); } void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) { CALL_GL_API(glGetShaderSource, shader, bufSize, length, source); } const GLubyte * API_ENTRY(__glGetString)(GLenum name) { CALL_GL_API_RETURN(glGetString, name); } void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { CALL_GL_API(glGetTexParameterfv, target, pname, params); } void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexParameteriv, target, pname, params); } void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat *params) { CALL_GL_API(glGetUniformfv, program, location, params); } void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint *params) { CALL_GL_API(glGetUniformiv, program, location, params); } GLint API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar *name) { CALL_GL_API_RETURN(glGetUniformLocation, program, name); } void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat *params) { CALL_GL_API(glGetVertexAttribfv, index, pname, params); } void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint *params) { CALL_GL_API(glGetVertexAttribiv, index, pname, params); } void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void **pointer) { CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer); } void API_ENTRY(glHint)(GLenum target, GLenum mode) { CALL_GL_API(glHint, target, mode); } GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { CALL_GL_API_RETURN(glIsBuffer, buffer); } GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { CALL_GL_API_RETURN(glIsEnabled, cap); } GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) { CALL_GL_API_RETURN(glIsFramebuffer, framebuffer); } GLboolean API_ENTRY(glIsProgram)(GLuint program) { CALL_GL_API_RETURN(glIsProgram, program); } GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) { CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer); } GLboolean API_ENTRY(glIsShader)(GLuint shader) { CALL_GL_API_RETURN(glIsShader, shader); } GLboolean API_ENTRY(glIsTexture)(GLuint texture) { CALL_GL_API_RETURN(glIsTexture, texture); } void API_ENTRY(glLineWidth)(GLfloat width) { CALL_GL_API(glLineWidth, width); } void API_ENTRY(glLinkProgram)(GLuint program) { CALL_GL_API(glLinkProgram, program); } void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { CALL_GL_API(glPixelStorei, pname, param); } void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { CALL_GL_API(glPolygonOffset, factor, units); } void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); } void API_ENTRY(glReleaseShaderCompiler)(void) { CALL_GL_API(glReleaseShaderCompiler); } void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height); } void API_ENTRY(glSampleCoverage)(GLfloat value, GLboolean invert) { CALL_GL_API(glSampleCoverage, value, invert); } void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glScissor, x, y, width, height); } void API_ENTRY(glShaderBinary)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) { CALL_GL_API(glShaderBinary, count, shaders, binaryformat, binary, length); } void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) { CALL_GL_API(glShaderSource, shader, count, string, length); } void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { CALL_GL_API(glStencilFunc, func, ref, mask); } void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) { CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask); } void API_ENTRY(glStencilMask)(GLuint mask) { CALL_GL_API(glStencilMask, mask); } void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) { CALL_GL_API(glStencilMaskSeparate, face, mask); } void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { CALL_GL_API(glStencilOp, fail, zfail, zpass); } void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) { CALL_GL_API(glStencilOpSeparate, face, sfail, dpfail, dppass); } void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels); } void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { CALL_GL_API(glTexParameterf, target, pname, param); } void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { CALL_GL_API(glTexParameterfv, target, pname, params); } void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glTexParameteri, target, pname, param); } void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexParameteriv, target, pname, params); } void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); } void API_ENTRY(glUniform1f)(GLint location, GLfloat v0) { CALL_GL_API(glUniform1f, location, v0); } void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glUniform1fv, location, count, value); } void API_ENTRY(glUniform1i)(GLint location, GLint v0) { CALL_GL_API(glUniform1i, location, v0); } void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glUniform1iv, location, count, value); } void API_ENTRY(glUniform2f)(GLint location, GLfloat v0, GLfloat v1) { CALL_GL_API(glUniform2f, location, v0, v1); } void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glUniform2fv, location, count, value); } void API_ENTRY(glUniform2i)(GLint location, GLint v0, GLint v1) { CALL_GL_API(glUniform2i, location, v0, v1); } void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glUniform2iv, location, count, value); } void API_ENTRY(glUniform3f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { CALL_GL_API(glUniform3f, location, v0, v1, v2); } void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glUniform3fv, location, count, value); } void API_ENTRY(glUniform3i)(GLint location, GLint v0, GLint v1, GLint v2) { CALL_GL_API(glUniform3i, location, v0, v1, v2); } void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glUniform3iv, location, count, value); } void API_ENTRY(glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { CALL_GL_API(glUniform4f, location, v0, v1, v2, v3); } void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glUniform4fv, location, count, value); } void API_ENTRY(glUniform4i)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { CALL_GL_API(glUniform4i, location, v0, v1, v2, v3); } void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glUniform4iv, location, count, value); } void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value); } void API_ENTRY(glUseProgram)(GLuint program) { CALL_GL_API(glUseProgram, program); } void API_ENTRY(glValidateProgram)(GLuint program) { CALL_GL_API(glValidateProgram, program); } void API_ENTRY(glVertexAttrib1f)(GLuint index, GLfloat x) { CALL_GL_API(glVertexAttrib1f, index, x); } void API_ENTRY(glVertexAttrib1fv)(GLuint index, const GLfloat *v) { CALL_GL_API(glVertexAttrib1fv, index, v); } void API_ENTRY(glVertexAttrib2f)(GLuint index, GLfloat x, GLfloat y) { CALL_GL_API(glVertexAttrib2f, index, x, y); } void API_ENTRY(glVertexAttrib2fv)(GLuint index, const GLfloat *v) { CALL_GL_API(glVertexAttrib2fv, index, v); } void API_ENTRY(glVertexAttrib3f)(GLuint index, GLfloat x, GLfloat y, GLfloat z) { CALL_GL_API(glVertexAttrib3f, index, x, y, z); } void API_ENTRY(glVertexAttrib3fv)(GLuint index, const GLfloat *v) { CALL_GL_API(glVertexAttrib3fv, index, v); } void API_ENTRY(glVertexAttrib4f)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { CALL_GL_API(glVertexAttrib4f, index, x, y, z, w); } void API_ENTRY(glVertexAttrib4fv)(GLuint index, const GLfloat *v) { CALL_GL_API(glVertexAttrib4fv, index, v); } void API_ENTRY(glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) { CALL_GL_API(glVertexAttribPointer, index, size, type, normalized, stride, pointer); } void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glViewport, x, y, width, height); } void API_ENTRY(glReadBuffer)(GLenum src) { CALL_GL_API(glReadBuffer, src); } void API_ENTRY(glDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) { CALL_GL_API(glDrawRangeElements, mode, start, end, count, type, indices); } void API_ENTRY(glTexImage3D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexImage3D, target, level, internalformat, width, height, depth, border, format, type, pixels); } void API_ENTRY(glTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexSubImage3D, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } void API_ENTRY(glCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glCopyTexSubImage3D, target, level, xoffset, yoffset, zoffset, x, y, width, height); } void API_ENTRY(glCompressedTexImage3D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexImage3D, target, level, internalformat, width, height, depth, border, imageSize, data); } void API_ENTRY(glCompressedTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexSubImage3D, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); } void API_ENTRY(glGenQueries)(GLsizei n, GLuint *ids) { CALL_GL_API(glGenQueries, n, ids); } void API_ENTRY(glDeleteQueries)(GLsizei n, const GLuint *ids) { CALL_GL_API(glDeleteQueries, n, ids); } GLboolean API_ENTRY(glIsQuery)(GLuint id) { CALL_GL_API_RETURN(glIsQuery, id); } void API_ENTRY(glBeginQuery)(GLenum target, GLuint id) { CALL_GL_API(glBeginQuery, target, id); } void API_ENTRY(glEndQuery)(GLenum target) { CALL_GL_API(glEndQuery, target); } void API_ENTRY(glGetQueryiv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetQueryiv, target, pname, params); } void API_ENTRY(glGetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params) { CALL_GL_API(glGetQueryObjectuiv, id, pname, params); } GLboolean API_ENTRY(glUnmapBuffer)(GLenum target) { CALL_GL_API_RETURN(glUnmapBuffer, target); } void API_ENTRY(glGetBufferPointerv)(GLenum target, GLenum pname, void **params) { CALL_GL_API(glGetBufferPointerv, target, pname, params); } void API_ENTRY(glDrawBuffers)(GLsizei n, const GLenum *bufs) { CALL_GL_API(glDrawBuffers, n, bufs); } void API_ENTRY(glUniformMatrix2x3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix2x3fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix3x2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix3x2fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix2x4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix2x4fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix4x2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix4x2fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix3x4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix3x4fv, location, count, transpose, value); } void API_ENTRY(glUniformMatrix4x3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix4x3fv, location, count, transpose, value); } void API_ENTRY(glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { CALL_GL_API(glBlitFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } void API_ENTRY(glRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisample, target, samples, internalformat, width, height); } void API_ENTRY(glFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { CALL_GL_API(glFramebufferTextureLayer, target, attachment, texture, level, layer); } void * API_ENTRY(glMapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { CALL_GL_API_RETURN(glMapBufferRange, target, offset, length, access); } void API_ENTRY(glFlushMappedBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length) { CALL_GL_API(glFlushMappedBufferRange, target, offset, length); } void API_ENTRY(glBindVertexArray)(GLuint array) { CALL_GL_API(glBindVertexArray, array); } void API_ENTRY(glDeleteVertexArrays)(GLsizei n, const GLuint *arrays) { CALL_GL_API(glDeleteVertexArrays, n, arrays); } void API_ENTRY(glGenVertexArrays)(GLsizei n, GLuint *arrays) { CALL_GL_API(glGenVertexArrays, n, arrays); } GLboolean API_ENTRY(glIsVertexArray)(GLuint array) { CALL_GL_API_RETURN(glIsVertexArray, array); } void API_ENTRY(glGetIntegeri_v)(GLenum target, GLuint index, GLint *data) { CALL_GL_API(glGetIntegeri_v, target, index, data); } void API_ENTRY(glBeginTransformFeedback)(GLenum primitiveMode) { CALL_GL_API(glBeginTransformFeedback, primitiveMode); } void API_ENTRY(glEndTransformFeedback)(void) { CALL_GL_API(glEndTransformFeedback); } void API_ENTRY(glBindBufferRange)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { CALL_GL_API(glBindBufferRange, target, index, buffer, offset, size); } void API_ENTRY(glBindBufferBase)(GLenum target, GLuint index, GLuint buffer) { CALL_GL_API(glBindBufferBase, target, index, buffer); } void API_ENTRY(glTransformFeedbackVaryings)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode) { CALL_GL_API(glTransformFeedbackVaryings, program, count, varyings, bufferMode); } void API_ENTRY(glGetTransformFeedbackVarying)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) { CALL_GL_API(glGetTransformFeedbackVarying, program, index, bufSize, length, size, type, name); } void API_ENTRY(glVertexAttribIPointer)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glVertexAttribIPointer, index, size, type, stride, pointer); } void API_ENTRY(glGetVertexAttribIiv)(GLuint index, GLenum pname, GLint *params) { CALL_GL_API(glGetVertexAttribIiv, index, pname, params); } void API_ENTRY(glGetVertexAttribIuiv)(GLuint index, GLenum pname, GLuint *params) { CALL_GL_API(glGetVertexAttribIuiv, index, pname, params); } void API_ENTRY(glVertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w) { CALL_GL_API(glVertexAttribI4i, index, x, y, z, w); } void API_ENTRY(glVertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { CALL_GL_API(glVertexAttribI4ui, index, x, y, z, w); } void API_ENTRY(glVertexAttribI4iv)(GLuint index, const GLint *v) { CALL_GL_API(glVertexAttribI4iv, index, v); } void API_ENTRY(glVertexAttribI4uiv)(GLuint index, const GLuint *v) { CALL_GL_API(glVertexAttribI4uiv, index, v); } void API_ENTRY(glGetUniformuiv)(GLuint program, GLint location, GLuint *params) { CALL_GL_API(glGetUniformuiv, program, location, params); } GLint API_ENTRY(glGetFragDataLocation)(GLuint program, const GLchar *name) { CALL_GL_API_RETURN(glGetFragDataLocation, program, name); } void API_ENTRY(glUniform1ui)(GLint location, GLuint v0) { CALL_GL_API(glUniform1ui, location, v0); } void API_ENTRY(glUniform2ui)(GLint location, GLuint v0, GLuint v1) { CALL_GL_API(glUniform2ui, location, v0, v1); } void API_ENTRY(glUniform3ui)(GLint location, GLuint v0, GLuint v1, GLuint v2) { CALL_GL_API(glUniform3ui, location, v0, v1, v2); } void API_ENTRY(glUniform4ui)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { CALL_GL_API(glUniform4ui, location, v0, v1, v2, v3); } void API_ENTRY(glUniform1uiv)(GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glUniform1uiv, location, count, value); } void API_ENTRY(glUniform2uiv)(GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glUniform2uiv, location, count, value); } void API_ENTRY(glUniform3uiv)(GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glUniform3uiv, location, count, value); } void API_ENTRY(glUniform4uiv)(GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glUniform4uiv, location, count, value); } void API_ENTRY(glClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint *value) { CALL_GL_API(glClearBufferiv, buffer, drawbuffer, value); } void API_ENTRY(glClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint *value) { CALL_GL_API(glClearBufferuiv, buffer, drawbuffer, value); } void API_ENTRY(glClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat *value) { CALL_GL_API(glClearBufferfv, buffer, drawbuffer, value); } void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil); } const GLubyte * API_ENTRY(__glGetStringi)(GLenum name, GLuint index) { CALL_GL_API_RETURN(glGetStringi, name, index); } void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { CALL_GL_API(glCopyBufferSubData, readTarget, writeTarget, readOffset, writeOffset, size); } void API_ENTRY(glGetUniformIndices)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices) { CALL_GL_API(glGetUniformIndices, program, uniformCount, uniformNames, uniformIndices); } void API_ENTRY(glGetActiveUniformsiv)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) { CALL_GL_API(glGetActiveUniformsiv, program, uniformCount, uniformIndices, pname, params); } GLuint API_ENTRY(glGetUniformBlockIndex)(GLuint program, const GLchar *uniformBlockName) { CALL_GL_API_RETURN(glGetUniformBlockIndex, program, uniformBlockName); } void API_ENTRY(glGetActiveUniformBlockiv)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) { CALL_GL_API(glGetActiveUniformBlockiv, program, uniformBlockIndex, pname, params); } void API_ENTRY(glGetActiveUniformBlockName)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) { CALL_GL_API(glGetActiveUniformBlockName, program, uniformBlockIndex, bufSize, length, uniformBlockName); } void API_ENTRY(glUniformBlockBinding)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { CALL_GL_API(glUniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding); } void API_ENTRY(glDrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) { CALL_GL_API(glDrawArraysInstanced, mode, first, count, instancecount); } void API_ENTRY(glDrawElementsInstanced)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount) { CALL_GL_API(glDrawElementsInstanced, mode, count, type, indices, instancecount); } GLsync API_ENTRY(glFenceSync)(GLenum condition, GLbitfield flags) { CALL_GL_API_RETURN(glFenceSync, condition, flags); } GLboolean API_ENTRY(glIsSync)(GLsync sync) { CALL_GL_API_RETURN(glIsSync, sync); } void API_ENTRY(glDeleteSync)(GLsync sync) { CALL_GL_API(glDeleteSync, sync); } GLenum API_ENTRY(glClientWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API_RETURN(glClientWaitSync, sync, flags, timeout); } void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API(glWaitSync, sync, flags, timeout); } void API_ENTRY(__glGetInteger64v)(GLenum pname, GLint64 *data) { CALL_GL_API(glGetInteger64v, pname, data); } void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { CALL_GL_API(glGetSynciv, sync, pname, bufSize, length, values); } void API_ENTRY(glGetInteger64i_v)(GLenum target, GLuint index, GLint64 *data) { CALL_GL_API(glGetInteger64i_v, target, index, data); } void API_ENTRY(glGetBufferParameteri64v)(GLenum target, GLenum pname, GLint64 *params) { CALL_GL_API(glGetBufferParameteri64v, target, pname, params); } void API_ENTRY(glGenSamplers)(GLsizei count, GLuint *samplers) { CALL_GL_API(glGenSamplers, count, samplers); } void API_ENTRY(glDeleteSamplers)(GLsizei count, const GLuint *samplers) { CALL_GL_API(glDeleteSamplers, count, samplers); } GLboolean API_ENTRY(glIsSampler)(GLuint sampler) { CALL_GL_API_RETURN(glIsSampler, sampler); } void API_ENTRY(glBindSampler)(GLuint unit, GLuint sampler) { CALL_GL_API(glBindSampler, unit, sampler); } void API_ENTRY(glSamplerParameteri)(GLuint sampler, GLenum pname, GLint param) { CALL_GL_API(glSamplerParameteri, sampler, pname, param); } void API_ENTRY(glSamplerParameteriv)(GLuint sampler, GLenum pname, const GLint *param) { CALL_GL_API(glSamplerParameteriv, sampler, pname, param); } void API_ENTRY(glSamplerParameterf)(GLuint sampler, GLenum pname, GLfloat param) { CALL_GL_API(glSamplerParameterf, sampler, pname, param); } void API_ENTRY(glSamplerParameterfv)(GLuint sampler, GLenum pname, const GLfloat *param) { CALL_GL_API(glSamplerParameterfv, sampler, pname, param); } void API_ENTRY(glGetSamplerParameteriv)(GLuint sampler, GLenum pname, GLint *params) { CALL_GL_API(glGetSamplerParameteriv, sampler, pname, params); } void API_ENTRY(glGetSamplerParameterfv)(GLuint sampler, GLenum pname, GLfloat *params) { CALL_GL_API(glGetSamplerParameterfv, sampler, pname, params); } void API_ENTRY(glVertexAttribDivisor)(GLuint index, GLuint divisor) { CALL_GL_API(glVertexAttribDivisor, index, divisor); } void API_ENTRY(glBindTransformFeedback)(GLenum target, GLuint id) { CALL_GL_API(glBindTransformFeedback, target, id); } void API_ENTRY(glDeleteTransformFeedbacks)(GLsizei n, const GLuint *ids) { CALL_GL_API(glDeleteTransformFeedbacks, n, ids); } void API_ENTRY(glGenTransformFeedbacks)(GLsizei n, GLuint *ids) { CALL_GL_API(glGenTransformFeedbacks, n, ids); } GLboolean API_ENTRY(glIsTransformFeedback)(GLuint id) { CALL_GL_API_RETURN(glIsTransformFeedback, id); } void API_ENTRY(glPauseTransformFeedback)(void) { CALL_GL_API(glPauseTransformFeedback); } void API_ENTRY(glResumeTransformFeedback)(void) { CALL_GL_API(glResumeTransformFeedback); } void API_ENTRY(glGetProgramBinary)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { CALL_GL_API(glGetProgramBinary, program, bufSize, length, binaryFormat, binary); } void API_ENTRY(glProgramBinary)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) { CALL_GL_API(glProgramBinary, program, binaryFormat, binary, length); } void API_ENTRY(glProgramParameteri)(GLuint program, GLenum pname, GLint value) { CALL_GL_API(glProgramParameteri, program, pname, value); } void API_ENTRY(glInvalidateFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { CALL_GL_API(glInvalidateFramebuffer, target, numAttachments, attachments); } void API_ENTRY(glInvalidateSubFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glInvalidateSubFramebuffer, target, numAttachments, attachments, x, y, width, height); } void API_ENTRY(glTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glTexStorage2D, target, levels, internalformat, width, height); } void API_ENTRY(glTexStorage3D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { CALL_GL_API(glTexStorage3D, target, levels, internalformat, width, height, depth); } void API_ENTRY(glGetInternalformativ)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetInternalformativ, target, internalformat, pname, bufSize, params); } void API_ENTRY(glDispatchCompute)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) { CALL_GL_API(glDispatchCompute, num_groups_x, num_groups_y, num_groups_z); } void API_ENTRY(glDispatchComputeIndirect)(GLintptr indirect) { CALL_GL_API(glDispatchComputeIndirect, indirect); } void API_ENTRY(glDrawArraysIndirect)(GLenum mode, const void *indirect) { CALL_GL_API(glDrawArraysIndirect, mode, indirect); } void API_ENTRY(glDrawElementsIndirect)(GLenum mode, GLenum type, const void *indirect) { CALL_GL_API(glDrawElementsIndirect, mode, type, indirect); } void API_ENTRY(glFramebufferParameteri)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glFramebufferParameteri, target, pname, param); } void API_ENTRY(glGetFramebufferParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetFramebufferParameteriv, target, pname, params); } void API_ENTRY(glGetProgramInterfaceiv)(GLuint program, GLenum programInterface, GLenum pname, GLint *params) { CALL_GL_API(glGetProgramInterfaceiv, program, programInterface, pname, params); } GLuint API_ENTRY(glGetProgramResourceIndex)(GLuint program, GLenum programInterface, const GLchar *name) { CALL_GL_API_RETURN(glGetProgramResourceIndex, program, programInterface, name); } void API_ENTRY(glGetProgramResourceName)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) { CALL_GL_API(glGetProgramResourceName, program, programInterface, index, bufSize, length, name); } void API_ENTRY(glGetProgramResourceiv)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) { CALL_GL_API(glGetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params); } GLint API_ENTRY(glGetProgramResourceLocation)(GLuint program, GLenum programInterface, const GLchar *name) { CALL_GL_API_RETURN(glGetProgramResourceLocation, program, programInterface, name); } void API_ENTRY(glUseProgramStages)(GLuint pipeline, GLbitfield stages, GLuint program) { CALL_GL_API(glUseProgramStages, pipeline, stages, program); } void API_ENTRY(glActiveShaderProgram)(GLuint pipeline, GLuint program) { CALL_GL_API(glActiveShaderProgram, pipeline, program); } GLuint API_ENTRY(glCreateShaderProgramv)(GLenum type, GLsizei count, const GLchar *const*strings) { CALL_GL_API_RETURN(glCreateShaderProgramv, type, count, strings); } void API_ENTRY(glBindProgramPipeline)(GLuint pipeline) { CALL_GL_API(glBindProgramPipeline, pipeline); } void API_ENTRY(glDeleteProgramPipelines)(GLsizei n, const GLuint *pipelines) { CALL_GL_API(glDeleteProgramPipelines, n, pipelines); } void API_ENTRY(glGenProgramPipelines)(GLsizei n, GLuint *pipelines) { CALL_GL_API(glGenProgramPipelines, n, pipelines); } GLboolean API_ENTRY(glIsProgramPipeline)(GLuint pipeline) { CALL_GL_API_RETURN(glIsProgramPipeline, pipeline); } void API_ENTRY(glGetProgramPipelineiv)(GLuint pipeline, GLenum pname, GLint *params) { CALL_GL_API(glGetProgramPipelineiv, pipeline, pname, params); } void API_ENTRY(glProgramUniform1i)(GLuint program, GLint location, GLint v0) { CALL_GL_API(glProgramUniform1i, program, location, v0); } void API_ENTRY(glProgramUniform2i)(GLuint program, GLint location, GLint v0, GLint v1) { CALL_GL_API(glProgramUniform2i, program, location, v0, v1); } void API_ENTRY(glProgramUniform3i)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) { CALL_GL_API(glProgramUniform3i, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform4i)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { CALL_GL_API(glProgramUniform4i, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform1ui)(GLuint program, GLint location, GLuint v0) { CALL_GL_API(glProgramUniform1ui, program, location, v0); } void API_ENTRY(glProgramUniform2ui)(GLuint program, GLint location, GLuint v0, GLuint v1) { CALL_GL_API(glProgramUniform2ui, program, location, v0, v1); } void API_ENTRY(glProgramUniform3ui)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) { CALL_GL_API(glProgramUniform3ui, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform4ui)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { CALL_GL_API(glProgramUniform4ui, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform1f)(GLuint program, GLint location, GLfloat v0) { CALL_GL_API(glProgramUniform1f, program, location, v0); } void API_ENTRY(glProgramUniform2f)(GLuint program, GLint location, GLfloat v0, GLfloat v1) { CALL_GL_API(glProgramUniform2f, program, location, v0, v1); } void API_ENTRY(glProgramUniform3f)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { CALL_GL_API(glProgramUniform3f, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform4f)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { CALL_GL_API(glProgramUniform4f, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform1iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform1iv, program, location, count, value); } void API_ENTRY(glProgramUniform2iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform2iv, program, location, count, value); } void API_ENTRY(glProgramUniform3iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform3iv, program, location, count, value); } void API_ENTRY(glProgramUniform4iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform4iv, program, location, count, value); } void API_ENTRY(glProgramUniform1uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform1uiv, program, location, count, value); } void API_ENTRY(glProgramUniform2uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform2uiv, program, location, count, value); } void API_ENTRY(glProgramUniform3uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform3uiv, program, location, count, value); } void API_ENTRY(glProgramUniform4uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform4uiv, program, location, count, value); } void API_ENTRY(glProgramUniform1fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform1fv, program, location, count, value); } void API_ENTRY(glProgramUniform2fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform2fv, program, location, count, value); } void API_ENTRY(glProgramUniform3fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform3fv, program, location, count, value); } void API_ENTRY(glProgramUniform4fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform4fv, program, location, count, value); } void API_ENTRY(glProgramUniformMatrix2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix2x3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2x3fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3x2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3x2fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix2x4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2x4fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4x2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4x2fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3x4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3x4fv, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4x3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4x3fv, program, location, count, transpose, value); } void API_ENTRY(glValidateProgramPipeline)(GLuint pipeline) { CALL_GL_API(glValidateProgramPipeline, pipeline); } void API_ENTRY(glGetProgramPipelineInfoLog)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { CALL_GL_API(glGetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog); } void API_ENTRY(glBindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { CALL_GL_API(glBindImageTexture, unit, texture, level, layered, layer, access, format); } void API_ENTRY(glGetBooleani_v)(GLenum target, GLuint index, GLboolean *data) { CALL_GL_API(glGetBooleani_v, target, index, data); } void API_ENTRY(glMemoryBarrier)(GLbitfield barriers) { CALL_GL_API(glMemoryBarrier, barriers); } void API_ENTRY(glMemoryBarrierByRegion)(GLbitfield barriers) { CALL_GL_API(glMemoryBarrierByRegion, barriers); } void API_ENTRY(glTexStorage2DMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) { CALL_GL_API(glTexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations); } void API_ENTRY(glGetMultisamplefv)(GLenum pname, GLuint index, GLfloat *val) { CALL_GL_API(glGetMultisamplefv, pname, index, val); } void API_ENTRY(glSampleMaski)(GLuint maskNumber, GLbitfield mask) { CALL_GL_API(glSampleMaski, maskNumber, mask); } void API_ENTRY(glGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params) { CALL_GL_API(glGetTexLevelParameteriv, target, level, pname, params); } void API_ENTRY(glGetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params) { CALL_GL_API(glGetTexLevelParameterfv, target, level, pname, params); } void API_ENTRY(glBindVertexBuffer)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) { CALL_GL_API(glBindVertexBuffer, bindingindex, buffer, offset, stride); } void API_ENTRY(glVertexAttribFormat)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) { CALL_GL_API(glVertexAttribFormat, attribindex, size, type, normalized, relativeoffset); } void API_ENTRY(glVertexAttribIFormat)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) { CALL_GL_API(glVertexAttribIFormat, attribindex, size, type, relativeoffset); } void API_ENTRY(glVertexAttribBinding)(GLuint attribindex, GLuint bindingindex) { CALL_GL_API(glVertexAttribBinding, attribindex, bindingindex); } void API_ENTRY(glVertexBindingDivisor)(GLuint bindingindex, GLuint divisor) { CALL_GL_API(glVertexBindingDivisor, bindingindex, divisor); } void API_ENTRY(glBlendBarrier)(void) { CALL_GL_API(glBlendBarrier); } void API_ENTRY(glCopyImageSubData)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { CALL_GL_API(glCopyImageSubData, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); } void API_ENTRY(glDebugMessageControl)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) { CALL_GL_API(glDebugMessageControl, source, type, severity, count, ids, enabled); } void API_ENTRY(glDebugMessageInsert)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) { CALL_GL_API(glDebugMessageInsert, source, type, id, severity, length, buf); } void API_ENTRY(glDebugMessageCallback)(GLDEBUGPROC callback, const void *userParam) { CALL_GL_API(glDebugMessageCallback, callback, userParam); } GLuint API_ENTRY(glGetDebugMessageLog)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) { CALL_GL_API_RETURN(glGetDebugMessageLog, count, bufSize, sources, types, ids, severities, lengths, messageLog); } void API_ENTRY(glPushDebugGroup)(GLenum source, GLuint id, GLsizei length, const GLchar *message) { CALL_GL_API(glPushDebugGroup, source, id, length, message); } void API_ENTRY(glPopDebugGroup)(void) { CALL_GL_API(glPopDebugGroup); } void API_ENTRY(glObjectLabel)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) { CALL_GL_API(glObjectLabel, identifier, name, length, label); } void API_ENTRY(glGetObjectLabel)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) { CALL_GL_API(glGetObjectLabel, identifier, name, bufSize, length, label); } void API_ENTRY(glObjectPtrLabel)(const void *ptr, GLsizei length, const GLchar *label) { CALL_GL_API(glObjectPtrLabel, ptr, length, label); } void API_ENTRY(glGetObjectPtrLabel)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) { CALL_GL_API(glGetObjectPtrLabel, ptr, bufSize, length, label); } void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { CALL_GL_API(glGetPointerv, pname, params); } void API_ENTRY(glEnablei)(GLenum target, GLuint index) { CALL_GL_API(glEnablei, target, index); } void API_ENTRY(glDisablei)(GLenum target, GLuint index) { CALL_GL_API(glDisablei, target, index); } void API_ENTRY(glBlendEquationi)(GLuint buf, GLenum mode) { CALL_GL_API(glBlendEquationi, buf, mode); } void API_ENTRY(glBlendEquationSeparatei)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { CALL_GL_API(glBlendEquationSeparatei, buf, modeRGB, modeAlpha); } void API_ENTRY(glBlendFunci)(GLuint buf, GLenum src, GLenum dst) { CALL_GL_API(glBlendFunci, buf, src, dst); } void API_ENTRY(glBlendFuncSeparatei)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { CALL_GL_API(glBlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); } void API_ENTRY(glColorMaski)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { CALL_GL_API(glColorMaski, index, r, g, b, a); } GLboolean API_ENTRY(glIsEnabledi)(GLenum target, GLuint index) { CALL_GL_API_RETURN(glIsEnabledi, target, index); } void API_ENTRY(glDrawElementsBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawElementsBaseVertex, mode, count, type, indices, basevertex); } void API_ENTRY(glDrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawRangeElementsBaseVertex, mode, start, end, count, type, indices, basevertex); } void API_ENTRY(glDrawElementsInstancedBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { CALL_GL_API(glDrawElementsInstancedBaseVertex, mode, count, type, indices, instancecount, basevertex); } void API_ENTRY(glFramebufferTexture)(GLenum target, GLenum attachment, GLuint texture, GLint level) { CALL_GL_API(glFramebufferTexture, target, attachment, texture, level); } void API_ENTRY(glPrimitiveBoundingBox)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { CALL_GL_API(glPrimitiveBoundingBox, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); } GLenum API_ENTRY(glGetGraphicsResetStatus)(void) { CALL_GL_API_RETURN(glGetGraphicsResetStatus); } void API_ENTRY(glReadnPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { CALL_GL_API(glReadnPixels, x, y, width, height, format, type, bufSize, data); } void API_ENTRY(glGetnUniformfv)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { CALL_GL_API(glGetnUniformfv, program, location, bufSize, params); } void API_ENTRY(glGetnUniformiv)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetnUniformiv, program, location, bufSize, params); } void API_ENTRY(glGetnUniformuiv)(GLuint program, GLint location, GLsizei bufSize, GLuint *params) { CALL_GL_API(glGetnUniformuiv, program, location, bufSize, params); } void API_ENTRY(glMinSampleShading)(GLfloat value) { CALL_GL_API(glMinSampleShading, value); } void API_ENTRY(glPatchParameteri)(GLenum pname, GLint value) { CALL_GL_API(glPatchParameteri, pname, value); } void API_ENTRY(glTexParameterIiv)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexParameterIiv, target, pname, params); } void API_ENTRY(glTexParameterIuiv)(GLenum target, GLenum pname, const GLuint *params) { CALL_GL_API(glTexParameterIuiv, target, pname, params); } void API_ENTRY(glGetTexParameterIiv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexParameterIiv, target, pname, params); } void API_ENTRY(glGetTexParameterIuiv)(GLenum target, GLenum pname, GLuint *params) { CALL_GL_API(glGetTexParameterIuiv, target, pname, params); } void API_ENTRY(glSamplerParameterIiv)(GLuint sampler, GLenum pname, const GLint *param) { CALL_GL_API(glSamplerParameterIiv, sampler, pname, param); } void API_ENTRY(glSamplerParameterIuiv)(GLuint sampler, GLenum pname, const GLuint *param) { CALL_GL_API(glSamplerParameterIuiv, sampler, pname, param); } void API_ENTRY(glGetSamplerParameterIiv)(GLuint sampler, GLenum pname, GLint *params) { CALL_GL_API(glGetSamplerParameterIiv, sampler, pname, params); } void API_ENTRY(glGetSamplerParameterIuiv)(GLuint sampler, GLenum pname, GLuint *params) { CALL_GL_API(glGetSamplerParameterIuiv, sampler, pname, params); } void API_ENTRY(glTexBuffer)(GLenum target, GLenum internalformat, GLuint buffer) { CALL_GL_API(glTexBuffer, target, internalformat, buffer); } void API_ENTRY(glTexBufferRange)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { CALL_GL_API(glTexBufferRange, target, internalformat, buffer, offset, size); } void API_ENTRY(glTexStorage3DMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { CALL_GL_API(glTexStorage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations); } opengl/libs/GLES2/gl2ext_api.in0100644 0000000 0000000 00000201366 13077405420 015236 0ustar000000000 0000000 void API_ENTRY(glBlendBarrierKHR)(void) { CALL_GL_API(glBlendBarrierKHR); } void API_ENTRY(glDebugMessageControlKHR)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) { CALL_GL_API(glDebugMessageControlKHR, source, type, severity, count, ids, enabled); } void API_ENTRY(glDebugMessageInsertKHR)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) { CALL_GL_API(glDebugMessageInsertKHR, source, type, id, severity, length, buf); } void API_ENTRY(glDebugMessageCallbackKHR)(GLDEBUGPROCKHR callback, const void *userParam) { CALL_GL_API(glDebugMessageCallbackKHR, callback, userParam); } GLuint API_ENTRY(glGetDebugMessageLogKHR)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) { CALL_GL_API_RETURN(glGetDebugMessageLogKHR, count, bufSize, sources, types, ids, severities, lengths, messageLog); } void API_ENTRY(glPushDebugGroupKHR)(GLenum source, GLuint id, GLsizei length, const GLchar *message) { CALL_GL_API(glPushDebugGroupKHR, source, id, length, message); } void API_ENTRY(glPopDebugGroupKHR)(void) { CALL_GL_API(glPopDebugGroupKHR); } void API_ENTRY(glObjectLabelKHR)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) { CALL_GL_API(glObjectLabelKHR, identifier, name, length, label); } void API_ENTRY(glGetObjectLabelKHR)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) { CALL_GL_API(glGetObjectLabelKHR, identifier, name, bufSize, length, label); } void API_ENTRY(glObjectPtrLabelKHR)(const void *ptr, GLsizei length, const GLchar *label) { CALL_GL_API(glObjectPtrLabelKHR, ptr, length, label); } void API_ENTRY(glGetObjectPtrLabelKHR)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) { CALL_GL_API(glGetObjectPtrLabelKHR, ptr, bufSize, length, label); } void API_ENTRY(glGetPointervKHR)(GLenum pname, void **params) { CALL_GL_API(glGetPointervKHR, pname, params); } GLenum API_ENTRY(glGetGraphicsResetStatusKHR)(void) { CALL_GL_API_RETURN(glGetGraphicsResetStatusKHR); } void API_ENTRY(glReadnPixelsKHR)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { CALL_GL_API(glReadnPixelsKHR, x, y, width, height, format, type, bufSize, data); } void API_ENTRY(glGetnUniformfvKHR)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { CALL_GL_API(glGetnUniformfvKHR, program, location, bufSize, params); } void API_ENTRY(glGetnUniformivKHR)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetnUniformivKHR, program, location, bufSize, params); } void API_ENTRY(glGetnUniformuivKHR)(GLuint program, GLint location, GLsizei bufSize, GLuint *params) { CALL_GL_API(glGetnUniformuivKHR, program, location, bufSize, params); } void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); } void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); } void API_ENTRY(glCopyImageSubDataOES)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { CALL_GL_API(glCopyImageSubDataOES, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); } void API_ENTRY(glEnableiOES)(GLenum target, GLuint index) { CALL_GL_API(glEnableiOES, target, index); } void API_ENTRY(glDisableiOES)(GLenum target, GLuint index) { CALL_GL_API(glDisableiOES, target, index); } void API_ENTRY(glBlendEquationiOES)(GLuint buf, GLenum mode) { CALL_GL_API(glBlendEquationiOES, buf, mode); } void API_ENTRY(glBlendEquationSeparateiOES)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { CALL_GL_API(glBlendEquationSeparateiOES, buf, modeRGB, modeAlpha); } void API_ENTRY(glBlendFunciOES)(GLuint buf, GLenum src, GLenum dst) { CALL_GL_API(glBlendFunciOES, buf, src, dst); } void API_ENTRY(glBlendFuncSeparateiOES)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { CALL_GL_API(glBlendFuncSeparateiOES, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); } void API_ENTRY(glColorMaskiOES)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { CALL_GL_API(glColorMaskiOES, index, r, g, b, a); } GLboolean API_ENTRY(glIsEnablediOES)(GLenum target, GLuint index) { CALL_GL_API_RETURN(glIsEnablediOES, target, index); } void API_ENTRY(glDrawElementsBaseVertexOES)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawElementsBaseVertexOES, mode, count, type, indices, basevertex); } void API_ENTRY(glDrawRangeElementsBaseVertexOES)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawRangeElementsBaseVertexOES, mode, start, end, count, type, indices, basevertex); } void API_ENTRY(glDrawElementsInstancedBaseVertexOES)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { CALL_GL_API(glDrawElementsInstancedBaseVertexOES, mode, count, type, indices, instancecount, basevertex); } void API_ENTRY(glMultiDrawElementsBaseVertexOES)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) { CALL_GL_API(glMultiDrawElementsBaseVertexOES, mode, count, type, indices, primcount, basevertex); } void API_ENTRY(glFramebufferTextureOES)(GLenum target, GLenum attachment, GLuint texture, GLint level) { CALL_GL_API(glFramebufferTextureOES, target, attachment, texture, level); } void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary); } void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length); } void * API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) { CALL_GL_API_RETURN(glMapBufferOES, target, access); } GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) { CALL_GL_API_RETURN(glUnmapBufferOES, target); } void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void **params) { CALL_GL_API(glGetBufferPointervOES, target, pname, params); } void API_ENTRY(glPrimitiveBoundingBoxOES)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { CALL_GL_API(glPrimitiveBoundingBoxOES, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); } void API_ENTRY(glMinSampleShadingOES)(GLfloat value) { CALL_GL_API(glMinSampleShadingOES, value); } void API_ENTRY(glPatchParameteriOES)(GLenum pname, GLint value) { CALL_GL_API(glPatchParameteriOES, pname, value); } void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels); } void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height); } void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data); } void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); } void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) { CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset); } void API_ENTRY(glTexParameterIivOES)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexParameterIivOES, target, pname, params); } void API_ENTRY(glTexParameterIuivOES)(GLenum target, GLenum pname, const GLuint *params) { CALL_GL_API(glTexParameterIuivOES, target, pname, params); } void API_ENTRY(glGetTexParameterIivOES)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexParameterIivOES, target, pname, params); } void API_ENTRY(glGetTexParameterIuivOES)(GLenum target, GLenum pname, GLuint *params) { CALL_GL_API(glGetTexParameterIuivOES, target, pname, params); } void API_ENTRY(glSamplerParameterIivOES)(GLuint sampler, GLenum pname, const GLint *param) { CALL_GL_API(glSamplerParameterIivOES, sampler, pname, param); } void API_ENTRY(glSamplerParameterIuivOES)(GLuint sampler, GLenum pname, const GLuint *param) { CALL_GL_API(glSamplerParameterIuivOES, sampler, pname, param); } void API_ENTRY(glGetSamplerParameterIivOES)(GLuint sampler, GLenum pname, GLint *params) { CALL_GL_API(glGetSamplerParameterIivOES, sampler, pname, params); } void API_ENTRY(glGetSamplerParameterIuivOES)(GLuint sampler, GLenum pname, GLuint *params) { CALL_GL_API(glGetSamplerParameterIuivOES, sampler, pname, params); } void API_ENTRY(glTexBufferOES)(GLenum target, GLenum internalformat, GLuint buffer) { CALL_GL_API(glTexBufferOES, target, internalformat, buffer); } void API_ENTRY(glTexBufferRangeOES)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { CALL_GL_API(glTexBufferRangeOES, target, internalformat, buffer, offset, size); } void API_ENTRY(glTexStorage3DMultisampleOES)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { CALL_GL_API(glTexStorage3DMultisampleOES, target, samples, internalformat, width, height, depth, fixedsamplelocations); } void API_ENTRY(glTextureViewOES)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { CALL_GL_API(glTextureViewOES, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); } void API_ENTRY(glBindVertexArrayOES)(GLuint array) { CALL_GL_API(glBindVertexArrayOES, array); } void API_ENTRY(glDeleteVertexArraysOES)(GLsizei n, const GLuint *arrays) { CALL_GL_API(glDeleteVertexArraysOES, n, arrays); } void API_ENTRY(glGenVertexArraysOES)(GLsizei n, GLuint *arrays) { CALL_GL_API(glGenVertexArraysOES, n, arrays); } GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) { CALL_GL_API_RETURN(glIsVertexArrayOES, array); } void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) { CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups); } void API_ENTRY(glGetPerfMonitorCountersAMD)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) { CALL_GL_API(glGetPerfMonitorCountersAMD, group, numCounters, maxActiveCounters, counterSize, counters); } void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString) { CALL_GL_API(glGetPerfMonitorGroupStringAMD, group, bufSize, length, groupString); } void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString) { CALL_GL_API(glGetPerfMonitorCounterStringAMD, group, counter, bufSize, length, counterString); } void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, void *data) { CALL_GL_API(glGetPerfMonitorCounterInfoAMD, group, counter, pname, data); } void API_ENTRY(glGenPerfMonitorsAMD)(GLsizei n, GLuint *monitors) { CALL_GL_API(glGenPerfMonitorsAMD, n, monitors); } void API_ENTRY(glDeletePerfMonitorsAMD)(GLsizei n, GLuint *monitors) { CALL_GL_API(glDeletePerfMonitorsAMD, n, monitors); } void API_ENTRY(glSelectPerfMonitorCountersAMD)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList) { CALL_GL_API(glSelectPerfMonitorCountersAMD, monitor, enable, group, numCounters, counterList); } void API_ENTRY(glBeginPerfMonitorAMD)(GLuint monitor) { CALL_GL_API(glBeginPerfMonitorAMD, monitor); } void API_ENTRY(glEndPerfMonitorAMD)(GLuint monitor) { CALL_GL_API(glEndPerfMonitorAMD, monitor); } void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) { CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten); } void API_ENTRY(glBlitFramebufferANGLE)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { CALL_GL_API(glBlitFramebufferANGLE, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } void API_ENTRY(glRenderbufferStorageMultisampleANGLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleANGLE, target, samples, internalformat, width, height); } void API_ENTRY(glDrawArraysInstancedANGLE)(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { CALL_GL_API(glDrawArraysInstancedANGLE, mode, first, count, primcount); } void API_ENTRY(glDrawElementsInstancedANGLE)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) { CALL_GL_API(glDrawElementsInstancedANGLE, mode, count, type, indices, primcount); } void API_ENTRY(glVertexAttribDivisorANGLE)(GLuint index, GLuint divisor) { CALL_GL_API(glVertexAttribDivisorANGLE, index, divisor); } void API_ENTRY(glGetTranslatedShaderSourceANGLE)(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) { CALL_GL_API(glGetTranslatedShaderSourceANGLE, shader, bufsize, length, source); } void API_ENTRY(glCopyTextureLevelsAPPLE)(GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount) { CALL_GL_API(glCopyTextureLevelsAPPLE, destinationTexture, sourceTexture, sourceBaseLevel, sourceLevelCount); } void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height); } void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) { CALL_GL_API(glResolveMultisampleFramebufferAPPLE); } GLsync API_ENTRY(glFenceSyncAPPLE)(GLenum condition, GLbitfield flags) { CALL_GL_API_RETURN(glFenceSyncAPPLE, condition, flags); } GLboolean API_ENTRY(glIsSyncAPPLE)(GLsync sync) { CALL_GL_API_RETURN(glIsSyncAPPLE, sync); } void API_ENTRY(glDeleteSyncAPPLE)(GLsync sync) { CALL_GL_API(glDeleteSyncAPPLE, sync); } GLenum API_ENTRY(glClientWaitSyncAPPLE)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API_RETURN(glClientWaitSyncAPPLE, sync, flags, timeout); } void API_ENTRY(glWaitSyncAPPLE)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API(glWaitSyncAPPLE, sync, flags, timeout); } void API_ENTRY(glGetInteger64vAPPLE)(GLenum pname, GLint64 *params) { CALL_GL_API(glGetInteger64vAPPLE, pname, params); } void API_ENTRY(glGetSyncivAPPLE)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { CALL_GL_API(glGetSyncivAPPLE, sync, pname, bufSize, length, values); } void API_ENTRY(glDrawArraysInstancedBaseInstanceEXT)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) { CALL_GL_API(glDrawArraysInstancedBaseInstanceEXT, mode, first, count, instancecount, baseinstance); } void API_ENTRY(glDrawElementsInstancedBaseInstanceEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance) { CALL_GL_API(glDrawElementsInstancedBaseInstanceEXT, mode, count, type, indices, instancecount, baseinstance); } void API_ENTRY(glDrawElementsInstancedBaseVertexBaseInstanceEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) { CALL_GL_API(glDrawElementsInstancedBaseVertexBaseInstanceEXT, mode, count, type, indices, instancecount, basevertex, baseinstance); } void API_ENTRY(glBindFragDataLocationIndexedEXT)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name) { CALL_GL_API(glBindFragDataLocationIndexedEXT, program, colorNumber, index, name); } void API_ENTRY(glBindFragDataLocationEXT)(GLuint program, GLuint color, const GLchar *name) { CALL_GL_API(glBindFragDataLocationEXT, program, color, name); } GLint API_ENTRY(glGetProgramResourceLocationIndexEXT)(GLuint program, GLenum programInterface, const GLchar *name) { CALL_GL_API_RETURN(glGetProgramResourceLocationIndexEXT, program, programInterface, name); } GLint API_ENTRY(glGetFragDataIndexEXT)(GLuint program, const GLchar *name) { CALL_GL_API_RETURN(glGetFragDataIndexEXT, program, name); } void API_ENTRY(glBufferStorageEXT)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags) { CALL_GL_API(glBufferStorageEXT, target, size, data, flags); } void API_ENTRY(glCopyImageSubDataEXT)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { CALL_GL_API(glCopyImageSubDataEXT, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); } void API_ENTRY(glLabelObjectEXT)(GLenum type, GLuint object, GLsizei length, const GLchar *label) { CALL_GL_API(glLabelObjectEXT, type, object, length, label); } void API_ENTRY(glGetObjectLabelEXT)(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) { CALL_GL_API(glGetObjectLabelEXT, type, object, bufSize, length, label); } void API_ENTRY(glInsertEventMarkerEXT)(GLsizei length, const GLchar *marker) { CALL_GL_API(glInsertEventMarkerEXT, length, marker); } void API_ENTRY(glPushGroupMarkerEXT)(GLsizei length, const GLchar *marker) { CALL_GL_API(glPushGroupMarkerEXT, length, marker); } void API_ENTRY(glPopGroupMarkerEXT)(void) { CALL_GL_API(glPopGroupMarkerEXT); } void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments); } void API_ENTRY(glGenQueriesEXT)(GLsizei n, GLuint *ids) { CALL_GL_API(glGenQueriesEXT, n, ids); } void API_ENTRY(glDeleteQueriesEXT)(GLsizei n, const GLuint *ids) { CALL_GL_API(glDeleteQueriesEXT, n, ids); } GLboolean API_ENTRY(glIsQueryEXT)(GLuint id) { CALL_GL_API_RETURN(glIsQueryEXT, id); } void API_ENTRY(glBeginQueryEXT)(GLenum target, GLuint id) { CALL_GL_API(glBeginQueryEXT, target, id); } void API_ENTRY(glEndQueryEXT)(GLenum target) { CALL_GL_API(glEndQueryEXT, target); } void API_ENTRY(glQueryCounterEXT)(GLuint id, GLenum target) { CALL_GL_API(glQueryCounterEXT, id, target); } void API_ENTRY(glGetQueryivEXT)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetQueryivEXT, target, pname, params); } void API_ENTRY(glGetQueryObjectivEXT)(GLuint id, GLenum pname, GLint *params) { CALL_GL_API(glGetQueryObjectivEXT, id, pname, params); } void API_ENTRY(glGetQueryObjectuivEXT)(GLuint id, GLenum pname, GLuint *params) { CALL_GL_API(glGetQueryObjectuivEXT, id, pname, params); } void API_ENTRY(glGetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64 *params) { CALL_GL_API(glGetQueryObjecti64vEXT, id, pname, params); } void API_ENTRY(glGetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64 *params) { CALL_GL_API(glGetQueryObjectui64vEXT, id, pname, params); } void API_ENTRY(glDrawBuffersEXT)(GLsizei n, const GLenum *bufs) { CALL_GL_API(glDrawBuffersEXT, n, bufs); } void API_ENTRY(glEnableiEXT)(GLenum target, GLuint index) { CALL_GL_API(glEnableiEXT, target, index); } void API_ENTRY(glDisableiEXT)(GLenum target, GLuint index) { CALL_GL_API(glDisableiEXT, target, index); } void API_ENTRY(glBlendEquationiEXT)(GLuint buf, GLenum mode) { CALL_GL_API(glBlendEquationiEXT, buf, mode); } void API_ENTRY(glBlendEquationSeparateiEXT)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { CALL_GL_API(glBlendEquationSeparateiEXT, buf, modeRGB, modeAlpha); } void API_ENTRY(glBlendFunciEXT)(GLuint buf, GLenum src, GLenum dst) { CALL_GL_API(glBlendFunciEXT, buf, src, dst); } void API_ENTRY(glBlendFuncSeparateiEXT)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { CALL_GL_API(glBlendFuncSeparateiEXT, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); } void API_ENTRY(glColorMaskiEXT)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { CALL_GL_API(glColorMaskiEXT, index, r, g, b, a); } GLboolean API_ENTRY(glIsEnablediEXT)(GLenum target, GLuint index) { CALL_GL_API_RETURN(glIsEnablediEXT, target, index); } void API_ENTRY(glDrawElementsBaseVertexEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawElementsBaseVertexEXT, mode, count, type, indices, basevertex); } void API_ENTRY(glDrawRangeElementsBaseVertexEXT)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { CALL_GL_API(glDrawRangeElementsBaseVertexEXT, mode, start, end, count, type, indices, basevertex); } void API_ENTRY(glDrawElementsInstancedBaseVertexEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { CALL_GL_API(glDrawElementsInstancedBaseVertexEXT, mode, count, type, indices, instancecount, basevertex); } void API_ENTRY(glMultiDrawElementsBaseVertexEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) { CALL_GL_API(glMultiDrawElementsBaseVertexEXT, mode, count, type, indices, primcount, basevertex); } void API_ENTRY(glDrawArraysInstancedEXT)(GLenum mode, GLint start, GLsizei count, GLsizei primcount) { CALL_GL_API(glDrawArraysInstancedEXT, mode, start, count, primcount); } void API_ENTRY(glDrawElementsInstancedEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) { CALL_GL_API(glDrawElementsInstancedEXT, mode, count, type, indices, primcount); } void API_ENTRY(glFramebufferTextureEXT)(GLenum target, GLenum attachment, GLuint texture, GLint level) { CALL_GL_API(glFramebufferTextureEXT, target, attachment, texture, level); } void API_ENTRY(glVertexAttribDivisorEXT)(GLuint index, GLuint divisor) { CALL_GL_API(glVertexAttribDivisorEXT, index, divisor); } void * API_ENTRY(glMapBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { CALL_GL_API_RETURN(glMapBufferRangeEXT, target, offset, length, access); } void API_ENTRY(glFlushMappedBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length) { CALL_GL_API(glFlushMappedBufferRangeEXT, target, offset, length); } void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) { CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount); } void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount) { CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount); } void API_ENTRY(glMultiDrawArraysIndirectEXT)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride) { CALL_GL_API(glMultiDrawArraysIndirectEXT, mode, indirect, drawcount, stride); } void API_ENTRY(glMultiDrawElementsIndirectEXT)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride) { CALL_GL_API(glMultiDrawElementsIndirectEXT, mode, type, indirect, drawcount, stride); } void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height); } void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples); } void API_ENTRY(glReadBufferIndexedEXT)(GLenum src, GLint index) { CALL_GL_API(glReadBufferIndexedEXT, src, index); } void API_ENTRY(glDrawBuffersIndexedEXT)(GLint n, const GLenum *location, const GLint *indices) { CALL_GL_API(glDrawBuffersIndexedEXT, n, location, indices); } void API_ENTRY(glGetIntegeri_vEXT)(GLenum target, GLuint index, GLint *data) { CALL_GL_API(glGetIntegeri_vEXT, target, index, data); } void API_ENTRY(glPrimitiveBoundingBoxEXT)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { CALL_GL_API(glPrimitiveBoundingBoxEXT, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); } void API_ENTRY(glRasterSamplesEXT)(GLuint samples, GLboolean fixedsamplelocations) { CALL_GL_API(glRasterSamplesEXT, samples, fixedsamplelocations); } GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) { CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT); } void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data); } void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params); } void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params); } void API_ENTRY(glActiveShaderProgramEXT)(GLuint pipeline, GLuint program) { CALL_GL_API(glActiveShaderProgramEXT, pipeline, program); } void API_ENTRY(glBindProgramPipelineEXT)(GLuint pipeline) { CALL_GL_API(glBindProgramPipelineEXT, pipeline); } GLuint API_ENTRY(glCreateShaderProgramvEXT)(GLenum type, GLsizei count, const GLchar **strings) { CALL_GL_API_RETURN(glCreateShaderProgramvEXT, type, count, strings); } void API_ENTRY(glDeleteProgramPipelinesEXT)(GLsizei n, const GLuint *pipelines) { CALL_GL_API(glDeleteProgramPipelinesEXT, n, pipelines); } void API_ENTRY(glGenProgramPipelinesEXT)(GLsizei n, GLuint *pipelines) { CALL_GL_API(glGenProgramPipelinesEXT, n, pipelines); } void API_ENTRY(glGetProgramPipelineInfoLogEXT)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { CALL_GL_API(glGetProgramPipelineInfoLogEXT, pipeline, bufSize, length, infoLog); } void API_ENTRY(glGetProgramPipelineivEXT)(GLuint pipeline, GLenum pname, GLint *params) { CALL_GL_API(glGetProgramPipelineivEXT, pipeline, pname, params); } GLboolean API_ENTRY(glIsProgramPipelineEXT)(GLuint pipeline) { CALL_GL_API_RETURN(glIsProgramPipelineEXT, pipeline); } void API_ENTRY(glProgramParameteriEXT)(GLuint program, GLenum pname, GLint value) { CALL_GL_API(glProgramParameteriEXT, program, pname, value); } void API_ENTRY(glProgramUniform1fEXT)(GLuint program, GLint location, GLfloat v0) { CALL_GL_API(glProgramUniform1fEXT, program, location, v0); } void API_ENTRY(glProgramUniform1fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform1fvEXT, program, location, count, value); } void API_ENTRY(glProgramUniform1iEXT)(GLuint program, GLint location, GLint v0) { CALL_GL_API(glProgramUniform1iEXT, program, location, v0); } void API_ENTRY(glProgramUniform1ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform1ivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform2fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1) { CALL_GL_API(glProgramUniform2fEXT, program, location, v0, v1); } void API_ENTRY(glProgramUniform2fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform2fvEXT, program, location, count, value); } void API_ENTRY(glProgramUniform2iEXT)(GLuint program, GLint location, GLint v0, GLint v1) { CALL_GL_API(glProgramUniform2iEXT, program, location, v0, v1); } void API_ENTRY(glProgramUniform2ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform2ivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform3fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { CALL_GL_API(glProgramUniform3fEXT, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform3fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform3fvEXT, program, location, count, value); } void API_ENTRY(glProgramUniform3iEXT)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) { CALL_GL_API(glProgramUniform3iEXT, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform3ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform3ivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform4fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { CALL_GL_API(glProgramUniform4fEXT, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform4fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { CALL_GL_API(glProgramUniform4fvEXT, program, location, count, value); } void API_ENTRY(glProgramUniform4iEXT)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { CALL_GL_API(glProgramUniform4iEXT, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform4ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { CALL_GL_API(glProgramUniform4ivEXT, program, location, count, value); } void API_ENTRY(glProgramUniformMatrix2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4fvEXT, program, location, count, transpose, value); } void API_ENTRY(glUseProgramStagesEXT)(GLuint pipeline, GLbitfield stages, GLuint program) { CALL_GL_API(glUseProgramStagesEXT, pipeline, stages, program); } void API_ENTRY(glValidateProgramPipelineEXT)(GLuint pipeline) { CALL_GL_API(glValidateProgramPipelineEXT, pipeline); } void API_ENTRY(glProgramUniform1uiEXT)(GLuint program, GLint location, GLuint v0) { CALL_GL_API(glProgramUniform1uiEXT, program, location, v0); } void API_ENTRY(glProgramUniform2uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1) { CALL_GL_API(glProgramUniform2uiEXT, program, location, v0, v1); } void API_ENTRY(glProgramUniform3uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) { CALL_GL_API(glProgramUniform3uiEXT, program, location, v0, v1, v2); } void API_ENTRY(glProgramUniform4uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { CALL_GL_API(glProgramUniform4uiEXT, program, location, v0, v1, v2, v3); } void API_ENTRY(glProgramUniform1uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform1uivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform2uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform2uivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform3uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform3uivEXT, program, location, count, value); } void API_ENTRY(glProgramUniform4uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { CALL_GL_API(glProgramUniform4uivEXT, program, location, count, value); } void API_ENTRY(glProgramUniformMatrix2x3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2x3fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3x2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3x2fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix2x4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix2x4fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4x2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4x2fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix3x4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix3x4fvEXT, program, location, count, transpose, value); } void API_ENTRY(glProgramUniformMatrix4x3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glProgramUniformMatrix4x3fvEXT, program, location, count, transpose, value); } void API_ENTRY(glTexPageCommitmentEXT)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit) { CALL_GL_API(glTexPageCommitmentEXT, target, level, xoffset, yoffset, zoffset, width, height, depth, commit); } void API_ENTRY(glPatchParameteriEXT)(GLenum pname, GLint value) { CALL_GL_API(glPatchParameteriEXT, pname, value); } void API_ENTRY(glTexParameterIivEXT)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexParameterIivEXT, target, pname, params); } void API_ENTRY(glTexParameterIuivEXT)(GLenum target, GLenum pname, const GLuint *params) { CALL_GL_API(glTexParameterIuivEXT, target, pname, params); } void API_ENTRY(glGetTexParameterIivEXT)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexParameterIivEXT, target, pname, params); } void API_ENTRY(glGetTexParameterIuivEXT)(GLenum target, GLenum pname, GLuint *params) { CALL_GL_API(glGetTexParameterIuivEXT, target, pname, params); } void API_ENTRY(glSamplerParameterIivEXT)(GLuint sampler, GLenum pname, const GLint *param) { CALL_GL_API(glSamplerParameterIivEXT, sampler, pname, param); } void API_ENTRY(glSamplerParameterIuivEXT)(GLuint sampler, GLenum pname, const GLuint *param) { CALL_GL_API(glSamplerParameterIuivEXT, sampler, pname, param); } void API_ENTRY(glGetSamplerParameterIivEXT)(GLuint sampler, GLenum pname, GLint *params) { CALL_GL_API(glGetSamplerParameterIivEXT, sampler, pname, params); } void API_ENTRY(glGetSamplerParameterIuivEXT)(GLuint sampler, GLenum pname, GLuint *params) { CALL_GL_API(glGetSamplerParameterIuivEXT, sampler, pname, params); } void API_ENTRY(glTexBufferEXT)(GLenum target, GLenum internalformat, GLuint buffer) { CALL_GL_API(glTexBufferEXT, target, internalformat, buffer); } void API_ENTRY(glTexBufferRangeEXT)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { CALL_GL_API(glTexBufferRangeEXT, target, internalformat, buffer, offset, size); } void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width); } void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height); } void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth); } void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width); } void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height); } void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth); } void API_ENTRY(glTextureViewEXT)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { CALL_GL_API(glTextureViewEXT, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); } void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height); } void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples); } void API_ENTRY(glApplyFramebufferAttachmentCMAAINTEL)(void) { CALL_GL_API(glApplyFramebufferAttachmentCMAAINTEL); } void API_ENTRY(glBeginPerfQueryINTEL)(GLuint queryHandle) { CALL_GL_API(glBeginPerfQueryINTEL, queryHandle); } void API_ENTRY(glCreatePerfQueryINTEL)(GLuint queryId, GLuint *queryHandle) { CALL_GL_API(glCreatePerfQueryINTEL, queryId, queryHandle); } void API_ENTRY(glDeletePerfQueryINTEL)(GLuint queryHandle) { CALL_GL_API(glDeletePerfQueryINTEL, queryHandle); } void API_ENTRY(glEndPerfQueryINTEL)(GLuint queryHandle) { CALL_GL_API(glEndPerfQueryINTEL, queryHandle); } void API_ENTRY(glGetFirstPerfQueryIdINTEL)(GLuint *queryId) { CALL_GL_API(glGetFirstPerfQueryIdINTEL, queryId); } void API_ENTRY(glGetNextPerfQueryIdINTEL)(GLuint queryId, GLuint *nextQueryId) { CALL_GL_API(glGetNextPerfQueryIdINTEL, queryId, nextQueryId); } void API_ENTRY(glGetPerfCounterInfoINTEL)(GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue) { CALL_GL_API(glGetPerfCounterInfoINTEL, queryId, counterId, counterNameLength, counterName, counterDescLength, counterDesc, counterOffset, counterDataSize, counterTypeEnum, counterDataTypeEnum, rawCounterMaxValue); } void API_ENTRY(glGetPerfQueryDataINTEL)(GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten) { CALL_GL_API(glGetPerfQueryDataINTEL, queryHandle, flags, dataSize, data, bytesWritten); } void API_ENTRY(glGetPerfQueryIdByNameINTEL)(GLchar *queryName, GLuint *queryId) { CALL_GL_API(glGetPerfQueryIdByNameINTEL, queryName, queryId); } void API_ENTRY(glGetPerfQueryInfoINTEL)(GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask) { CALL_GL_API(glGetPerfQueryInfoINTEL, queryId, queryNameLength, queryName, dataSize, noCounters, noInstances, capsMask); } GLuint64 API_ENTRY(glGetTextureHandleNV)(GLuint texture) { CALL_GL_API_RETURN(glGetTextureHandleNV, texture); } GLuint64 API_ENTRY(glGetTextureSamplerHandleNV)(GLuint texture, GLuint sampler) { CALL_GL_API_RETURN(glGetTextureSamplerHandleNV, texture, sampler); } void API_ENTRY(glMakeTextureHandleResidentNV)(GLuint64 handle) { CALL_GL_API(glMakeTextureHandleResidentNV, handle); } void API_ENTRY(glMakeTextureHandleNonResidentNV)(GLuint64 handle) { CALL_GL_API(glMakeTextureHandleNonResidentNV, handle); } GLuint64 API_ENTRY(glGetImageHandleNV)(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format) { CALL_GL_API_RETURN(glGetImageHandleNV, texture, level, layered, layer, format); } void API_ENTRY(glMakeImageHandleResidentNV)(GLuint64 handle, GLenum access) { CALL_GL_API(glMakeImageHandleResidentNV, handle, access); } void API_ENTRY(glMakeImageHandleNonResidentNV)(GLuint64 handle) { CALL_GL_API(glMakeImageHandleNonResidentNV, handle); } void API_ENTRY(glUniformHandleui64NV)(GLint location, GLuint64 value) { CALL_GL_API(glUniformHandleui64NV, location, value); } void API_ENTRY(glUniformHandleui64vNV)(GLint location, GLsizei count, const GLuint64 *value) { CALL_GL_API(glUniformHandleui64vNV, location, count, value); } void API_ENTRY(glProgramUniformHandleui64NV)(GLuint program, GLint location, GLuint64 value) { CALL_GL_API(glProgramUniformHandleui64NV, program, location, value); } void API_ENTRY(glProgramUniformHandleui64vNV)(GLuint program, GLint location, GLsizei count, const GLuint64 *values) { CALL_GL_API(glProgramUniformHandleui64vNV, program, location, count, values); } GLboolean API_ENTRY(glIsTextureHandleResidentNV)(GLuint64 handle) { CALL_GL_API_RETURN(glIsTextureHandleResidentNV, handle); } GLboolean API_ENTRY(glIsImageHandleResidentNV)(GLuint64 handle) { CALL_GL_API_RETURN(glIsImageHandleResidentNV, handle); } void API_ENTRY(glBlendParameteriNV)(GLenum pname, GLint value) { CALL_GL_API(glBlendParameteriNV, pname, value); } void API_ENTRY(glBlendBarrierNV)(void) { CALL_GL_API(glBlendBarrierNV); } void API_ENTRY(glBeginConditionalRenderNV)(GLuint id, GLenum mode) { CALL_GL_API(glBeginConditionalRenderNV, id, mode); } void API_ENTRY(glEndConditionalRenderNV)(void) { CALL_GL_API(glEndConditionalRenderNV); } void API_ENTRY(glSubpixelPrecisionBiasNV)(GLuint xbits, GLuint ybits) { CALL_GL_API(glSubpixelPrecisionBiasNV, xbits, ybits); } void API_ENTRY(glCopyBufferSubDataNV)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { CALL_GL_API(glCopyBufferSubDataNV, readTarget, writeTarget, readOffset, writeOffset, size); } void API_ENTRY(glCoverageMaskNV)(GLboolean mask) { CALL_GL_API(glCoverageMaskNV, mask); } void API_ENTRY(glCoverageOperationNV)(GLenum operation) { CALL_GL_API(glCoverageOperationNV, operation); } void API_ENTRY(glDrawBuffersNV)(GLsizei n, const GLenum *bufs) { CALL_GL_API(glDrawBuffersNV, n, bufs); } void API_ENTRY(glDrawArraysInstancedNV)(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { CALL_GL_API(glDrawArraysInstancedNV, mode, first, count, primcount); } void API_ENTRY(glDrawElementsInstancedNV)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) { CALL_GL_API(glDrawElementsInstancedNV, mode, count, type, indices, primcount); } void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) { CALL_GL_API(glDeleteFencesNV, n, fences); } void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) { CALL_GL_API(glGenFencesNV, n, fences); } GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) { CALL_GL_API_RETURN(glIsFenceNV, fence); } GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) { CALL_GL_API_RETURN(glTestFenceNV, fence); } void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) { CALL_GL_API(glGetFenceivNV, fence, pname, params); } void API_ENTRY(glFinishFenceNV)(GLuint fence) { CALL_GL_API(glFinishFenceNV, fence); } void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) { CALL_GL_API(glSetFenceNV, fence, condition); } void API_ENTRY(glFragmentCoverageColorNV)(GLuint color) { CALL_GL_API(glFragmentCoverageColorNV, color); } void API_ENTRY(glBlitFramebufferNV)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { CALL_GL_API(glBlitFramebufferNV, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } void API_ENTRY(glCoverageModulationTableNV)(GLsizei n, const GLfloat *v) { CALL_GL_API(glCoverageModulationTableNV, n, v); } void API_ENTRY(glGetCoverageModulationTableNV)(GLsizei bufsize, GLfloat *v) { CALL_GL_API(glGetCoverageModulationTableNV, bufsize, v); } void API_ENTRY(glCoverageModulationNV)(GLenum components) { CALL_GL_API(glCoverageModulationNV, components); } void API_ENTRY(glRenderbufferStorageMultisampleNV)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleNV, target, samples, internalformat, width, height); } void API_ENTRY(glVertexAttribDivisorNV)(GLuint index, GLuint divisor) { CALL_GL_API(glVertexAttribDivisorNV, index, divisor); } void API_ENTRY(glGetInternalformatSampleivNV)(GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetInternalformatSampleivNV, target, internalformat, samples, pname, bufSize, params); } void API_ENTRY(glUniformMatrix2x3fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix2x3fvNV, location, count, transpose, value); } void API_ENTRY(glUniformMatrix3x2fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix3x2fvNV, location, count, transpose, value); } void API_ENTRY(glUniformMatrix2x4fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix2x4fvNV, location, count, transpose, value); } void API_ENTRY(glUniformMatrix4x2fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix4x2fvNV, location, count, transpose, value); } void API_ENTRY(glUniformMatrix3x4fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix3x4fvNV, location, count, transpose, value); } void API_ENTRY(glUniformMatrix4x3fvNV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { CALL_GL_API(glUniformMatrix4x3fvNV, location, count, transpose, value); } GLuint API_ENTRY(glGenPathsNV)(GLsizei range) { CALL_GL_API_RETURN(glGenPathsNV, range); } void API_ENTRY(glDeletePathsNV)(GLuint path, GLsizei range) { CALL_GL_API(glDeletePathsNV, path, range); } GLboolean API_ENTRY(glIsPathNV)(GLuint path) { CALL_GL_API_RETURN(glIsPathNV, path); } void API_ENTRY(glPathCommandsNV)(GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords) { CALL_GL_API(glPathCommandsNV, path, numCommands, commands, numCoords, coordType, coords); } void API_ENTRY(glPathCoordsNV)(GLuint path, GLsizei numCoords, GLenum coordType, const void *coords) { CALL_GL_API(glPathCoordsNV, path, numCoords, coordType, coords); } void API_ENTRY(glPathSubCommandsNV)(GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords) { CALL_GL_API(glPathSubCommandsNV, path, commandStart, commandsToDelete, numCommands, commands, numCoords, coordType, coords); } void API_ENTRY(glPathSubCoordsNV)(GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords) { CALL_GL_API(glPathSubCoordsNV, path, coordStart, numCoords, coordType, coords); } void API_ENTRY(glPathStringNV)(GLuint path, GLenum format, GLsizei length, const void *pathString) { CALL_GL_API(glPathStringNV, path, format, length, pathString); } void API_ENTRY(glPathGlyphsNV)(GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale) { CALL_GL_API(glPathGlyphsNV, firstPathName, fontTarget, fontName, fontStyle, numGlyphs, type, charcodes, handleMissingGlyphs, pathParameterTemplate, emScale); } void API_ENTRY(glPathGlyphRangeNV)(GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale) { CALL_GL_API(glPathGlyphRangeNV, firstPathName, fontTarget, fontName, fontStyle, firstGlyph, numGlyphs, handleMissingGlyphs, pathParameterTemplate, emScale); } void API_ENTRY(glWeightPathsNV)(GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights) { CALL_GL_API(glWeightPathsNV, resultPath, numPaths, paths, weights); } void API_ENTRY(glCopyPathNV)(GLuint resultPath, GLuint srcPath) { CALL_GL_API(glCopyPathNV, resultPath, srcPath); } void API_ENTRY(glInterpolatePathsNV)(GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight) { CALL_GL_API(glInterpolatePathsNV, resultPath, pathA, pathB, weight); } void API_ENTRY(glTransformPathNV)(GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glTransformPathNV, resultPath, srcPath, transformType, transformValues); } void API_ENTRY(glPathParameterivNV)(GLuint path, GLenum pname, const GLint *value) { CALL_GL_API(glPathParameterivNV, path, pname, value); } void API_ENTRY(glPathParameteriNV)(GLuint path, GLenum pname, GLint value) { CALL_GL_API(glPathParameteriNV, path, pname, value); } void API_ENTRY(glPathParameterfvNV)(GLuint path, GLenum pname, const GLfloat *value) { CALL_GL_API(glPathParameterfvNV, path, pname, value); } void API_ENTRY(glPathParameterfNV)(GLuint path, GLenum pname, GLfloat value) { CALL_GL_API(glPathParameterfNV, path, pname, value); } void API_ENTRY(glPathDashArrayNV)(GLuint path, GLsizei dashCount, const GLfloat *dashArray) { CALL_GL_API(glPathDashArrayNV, path, dashCount, dashArray); } void API_ENTRY(glPathStencilFuncNV)(GLenum func, GLint ref, GLuint mask) { CALL_GL_API(glPathStencilFuncNV, func, ref, mask); } void API_ENTRY(glPathStencilDepthOffsetNV)(GLfloat factor, GLfloat units) { CALL_GL_API(glPathStencilDepthOffsetNV, factor, units); } void API_ENTRY(glStencilFillPathNV)(GLuint path, GLenum fillMode, GLuint mask) { CALL_GL_API(glStencilFillPathNV, path, fillMode, mask); } void API_ENTRY(glStencilStrokePathNV)(GLuint path, GLint reference, GLuint mask) { CALL_GL_API(glStencilStrokePathNV, path, reference, mask); } void API_ENTRY(glStencilFillPathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glStencilFillPathInstancedNV, numPaths, pathNameType, paths, pathBase, fillMode, mask, transformType, transformValues); } void API_ENTRY(glStencilStrokePathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glStencilStrokePathInstancedNV, numPaths, pathNameType, paths, pathBase, reference, mask, transformType, transformValues); } void API_ENTRY(glPathCoverDepthFuncNV)(GLenum func) { CALL_GL_API(glPathCoverDepthFuncNV, func); } void API_ENTRY(glCoverFillPathNV)(GLuint path, GLenum coverMode) { CALL_GL_API(glCoverFillPathNV, path, coverMode); } void API_ENTRY(glCoverStrokePathNV)(GLuint path, GLenum coverMode) { CALL_GL_API(glCoverStrokePathNV, path, coverMode); } void API_ENTRY(glCoverFillPathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glCoverFillPathInstancedNV, numPaths, pathNameType, paths, pathBase, coverMode, transformType, transformValues); } void API_ENTRY(glCoverStrokePathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glCoverStrokePathInstancedNV, numPaths, pathNameType, paths, pathBase, coverMode, transformType, transformValues); } void API_ENTRY(glGetPathParameterivNV)(GLuint path, GLenum pname, GLint *value) { CALL_GL_API(glGetPathParameterivNV, path, pname, value); } void API_ENTRY(glGetPathParameterfvNV)(GLuint path, GLenum pname, GLfloat *value) { CALL_GL_API(glGetPathParameterfvNV, path, pname, value); } void API_ENTRY(glGetPathCommandsNV)(GLuint path, GLubyte *commands) { CALL_GL_API(glGetPathCommandsNV, path, commands); } void API_ENTRY(glGetPathCoordsNV)(GLuint path, GLfloat *coords) { CALL_GL_API(glGetPathCoordsNV, path, coords); } void API_ENTRY(glGetPathDashArrayNV)(GLuint path, GLfloat *dashArray) { CALL_GL_API(glGetPathDashArrayNV, path, dashArray); } void API_ENTRY(glGetPathMetricsNV)(GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics) { CALL_GL_API(glGetPathMetricsNV, metricQueryMask, numPaths, pathNameType, paths, pathBase, stride, metrics); } void API_ENTRY(glGetPathMetricRangeNV)(GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics) { CALL_GL_API(glGetPathMetricRangeNV, metricQueryMask, firstPathName, numPaths, stride, metrics); } void API_ENTRY(glGetPathSpacingNV)(GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing) { CALL_GL_API(glGetPathSpacingNV, pathListMode, numPaths, pathNameType, paths, pathBase, advanceScale, kerningScale, transformType, returnedSpacing); } GLboolean API_ENTRY(glIsPointInFillPathNV)(GLuint path, GLuint mask, GLfloat x, GLfloat y) { CALL_GL_API_RETURN(glIsPointInFillPathNV, path, mask, x, y); } GLboolean API_ENTRY(glIsPointInStrokePathNV)(GLuint path, GLfloat x, GLfloat y) { CALL_GL_API_RETURN(glIsPointInStrokePathNV, path, x, y); } GLfloat API_ENTRY(glGetPathLengthNV)(GLuint path, GLsizei startSegment, GLsizei numSegments) { CALL_GL_API_RETURN(glGetPathLengthNV, path, startSegment, numSegments); } GLboolean API_ENTRY(glPointAlongPathNV)(GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY) { CALL_GL_API_RETURN(glPointAlongPathNV, path, startSegment, numSegments, distance, x, y, tangentX, tangentY); } void API_ENTRY(glMatrixLoad3x2fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixLoad3x2fNV, matrixMode, m); } void API_ENTRY(glMatrixLoad3x3fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixLoad3x3fNV, matrixMode, m); } void API_ENTRY(glMatrixLoadTranspose3x3fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixLoadTranspose3x3fNV, matrixMode, m); } void API_ENTRY(glMatrixMult3x2fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixMult3x2fNV, matrixMode, m); } void API_ENTRY(glMatrixMult3x3fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixMult3x3fNV, matrixMode, m); } void API_ENTRY(glMatrixMultTranspose3x3fNV)(GLenum matrixMode, const GLfloat *m) { CALL_GL_API(glMatrixMultTranspose3x3fNV, matrixMode, m); } void API_ENTRY(glStencilThenCoverFillPathNV)(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode) { CALL_GL_API(glStencilThenCoverFillPathNV, path, fillMode, mask, coverMode); } void API_ENTRY(glStencilThenCoverStrokePathNV)(GLuint path, GLint reference, GLuint mask, GLenum coverMode) { CALL_GL_API(glStencilThenCoverStrokePathNV, path, reference, mask, coverMode); } void API_ENTRY(glStencilThenCoverFillPathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glStencilThenCoverFillPathInstancedNV, numPaths, pathNameType, paths, pathBase, fillMode, mask, coverMode, transformType, transformValues); } void API_ENTRY(glStencilThenCoverStrokePathInstancedNV)(GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) { CALL_GL_API(glStencilThenCoverStrokePathInstancedNV, numPaths, pathNameType, paths, pathBase, reference, mask, coverMode, transformType, transformValues); } GLenum API_ENTRY(glPathGlyphIndexRangeNV)(GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]) { CALL_GL_API_RETURN(glPathGlyphIndexRangeNV, fontTarget, fontName, fontStyle, pathParameterTemplate, emScale, baseAndCount); } GLenum API_ENTRY(glPathGlyphIndexArrayNV)(GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale) { CALL_GL_API_RETURN(glPathGlyphIndexArrayNV, firstPathName, fontTarget, fontName, fontStyle, firstGlyphIndex, numGlyphs, pathParameterTemplate, emScale); } GLenum API_ENTRY(glPathMemoryGlyphIndexArrayNV)(GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale) { CALL_GL_API_RETURN(glPathMemoryGlyphIndexArrayNV, firstPathName, fontTarget, fontSize, fontData, faceIndex, firstGlyphIndex, numGlyphs, pathParameterTemplate, emScale); } void API_ENTRY(glProgramPathFragmentInputGenNV)(GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs) { CALL_GL_API(glProgramPathFragmentInputGenNV, program, location, genMode, components, coeffs); } void API_ENTRY(glGetProgramResourcefvNV)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params) { CALL_GL_API(glGetProgramResourcefvNV, program, programInterface, index, propCount, props, bufSize, length, params); } void API_ENTRY(glPolygonModeNV)(GLenum face, GLenum mode) { CALL_GL_API(glPolygonModeNV, face, mode); } void API_ENTRY(glReadBufferNV)(GLenum mode) { CALL_GL_API(glReadBufferNV, mode); } void API_ENTRY(glFramebufferSampleLocationsfvNV)(GLenum target, GLuint start, GLsizei count, const GLfloat *v) { CALL_GL_API(glFramebufferSampleLocationsfvNV, target, start, count, v); } void API_ENTRY(glNamedFramebufferSampleLocationsfvNV)(GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v) { CALL_GL_API(glNamedFramebufferSampleLocationsfvNV, framebuffer, start, count, v); } void API_ENTRY(glResolveDepthValuesNV)(void) { CALL_GL_API(glResolveDepthValuesNV); } void API_ENTRY(glViewportArrayvNV)(GLuint first, GLsizei count, const GLfloat *v) { CALL_GL_API(glViewportArrayvNV, first, count, v); } void API_ENTRY(glViewportIndexedfNV)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) { CALL_GL_API(glViewportIndexedfNV, index, x, y, w, h); } void API_ENTRY(glViewportIndexedfvNV)(GLuint index, const GLfloat *v) { CALL_GL_API(glViewportIndexedfvNV, index, v); } void API_ENTRY(glScissorArrayvNV)(GLuint first, GLsizei count, const GLint *v) { CALL_GL_API(glScissorArrayvNV, first, count, v); } void API_ENTRY(glScissorIndexedNV)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) { CALL_GL_API(glScissorIndexedNV, index, left, bottom, width, height); } void API_ENTRY(glScissorIndexedvNV)(GLuint index, const GLint *v) { CALL_GL_API(glScissorIndexedvNV, index, v); } void API_ENTRY(glDepthRangeArrayfvNV)(GLuint first, GLsizei count, const GLfloat *v) { CALL_GL_API(glDepthRangeArrayfvNV, first, count, v); } void API_ENTRY(glDepthRangeIndexedfNV)(GLuint index, GLfloat n, GLfloat f) { CALL_GL_API(glDepthRangeIndexedfNV, index, n, f); } void API_ENTRY(glGetFloati_vNV)(GLenum target, GLuint index, GLfloat *data) { CALL_GL_API(glGetFloati_vNV, target, index, data); } void API_ENTRY(glEnableiNV)(GLenum target, GLuint index) { CALL_GL_API(glEnableiNV, target, index); } void API_ENTRY(glDisableiNV)(GLenum target, GLuint index) { CALL_GL_API(glDisableiNV, target, index); } GLboolean API_ENTRY(glIsEnablediNV)(GLenum target, GLuint index) { CALL_GL_API_RETURN(glIsEnablediNV, target, index); } void API_ENTRY(glFramebufferTextureMultiviewOVR)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews) { CALL_GL_API(glFramebufferTextureMultiviewOVR, target, attachment, texture, level, baseViewIndex, numViews); } void API_ENTRY(glFramebufferTextureMultisampleMultiviewOVR)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews) { CALL_GL_API(glFramebufferTextureMultisampleMultiviewOVR, target, attachment, texture, level, samples, baseViewIndex, numViews); } void API_ENTRY(glAlphaFuncQCOM)(GLenum func, GLclampf ref) { CALL_GL_API(glAlphaFuncQCOM, func, ref); } void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) { CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls); } void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) { CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString); } void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) { CALL_GL_API(glEnableDriverControlQCOM, driverControl); } void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) { CALL_GL_API(glDisableDriverControlQCOM, driverControl); } void API_ENTRY(glExtGetTexturesQCOM)(GLuint *textures, GLint maxTextures, GLint *numTextures) { CALL_GL_API(glExtGetTexturesQCOM, textures, maxTextures, numTextures); } void API_ENTRY(glExtGetBuffersQCOM)(GLuint *buffers, GLint maxBuffers, GLint *numBuffers) { CALL_GL_API(glExtGetBuffersQCOM, buffers, maxBuffers, numBuffers); } void API_ENTRY(glExtGetRenderbuffersQCOM)(GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) { CALL_GL_API(glExtGetRenderbuffersQCOM, renderbuffers, maxRenderbuffers, numRenderbuffers); } void API_ENTRY(glExtGetFramebuffersQCOM)(GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) { CALL_GL_API(glExtGetFramebuffersQCOM, framebuffers, maxFramebuffers, numFramebuffers); } void API_ENTRY(glExtGetTexLevelParameterivQCOM)(GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) { CALL_GL_API(glExtGetTexLevelParameterivQCOM, texture, face, level, pname, params); } void API_ENTRY(glExtTexObjectStateOverrideiQCOM)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glExtTexObjectStateOverrideiQCOM, target, pname, param); } void API_ENTRY(glExtGetTexSubImageQCOM)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels) { CALL_GL_API(glExtGetTexSubImageQCOM, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels); } void API_ENTRY(glExtGetBufferPointervQCOM)(GLenum target, void **params) { CALL_GL_API(glExtGetBufferPointervQCOM, target, params); } void API_ENTRY(glExtGetShadersQCOM)(GLuint *shaders, GLint maxShaders, GLint *numShaders) { CALL_GL_API(glExtGetShadersQCOM, shaders, maxShaders, numShaders); } void API_ENTRY(glExtGetProgramsQCOM)(GLuint *programs, GLint maxPrograms, GLint *numPrograms) { CALL_GL_API(glExtGetProgramsQCOM, programs, maxPrograms, numPrograms); } GLboolean API_ENTRY(glExtIsProgramBinaryQCOM)(GLuint program) { CALL_GL_API_RETURN(glExtIsProgramBinaryQCOM, program); } void API_ENTRY(glExtGetProgramBinarySourceQCOM)(GLuint program, GLenum shadertype, GLchar *source, GLint *length) { CALL_GL_API(glExtGetProgramBinarySourceQCOM, program, shadertype, source, length); } void API_ENTRY(glStartTilingQCOM)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) { CALL_GL_API(glStartTilingQCOM, x, y, width, height, preserveMask); } void API_ENTRY(glEndTilingQCOM)(GLbitfield preserveMask) { CALL_GL_API(glEndTilingQCOM, preserveMask); } opengl/libs/GLES_CM/0040755 0000000 0000000 00000000000 13077405420 013140 5ustar000000000 0000000 opengl/libs/GLES_CM/gl.cpp0100644 0000000 0000000 00000027625 13077405420 014257 0ustar000000000 0000000 /* ** Copyright 2007, 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 #include #include #include #include #include #include #include #include "../hooks.h" #include "../egl_impl.h" using namespace android; // ---------------------------------------------------------------------------- // extensions for the framework // ---------------------------------------------------------------------------- extern "C" { GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr, GLsizei count); GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); } void glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr, GLsizei /*count*/) { glColorPointer(size, type, stride, ptr); } void glNormalPointerBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glNormalPointer(type, stride, pointer); } void glTexCoordPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glTexCoordPointer(size, type, stride, pointer); } void glVertexPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glVertexPointer(size, type, stride, pointer); } void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glPointSizePointerOES(type, stride, pointer); } GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glMatrixIndexPointerOES(size, type, stride, pointer); } GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) { glWeightPointerOES(size, type, stride, pointer); } // ---------------------------------------------------------------------------- // Actual GL entry-points // ---------------------------------------------------------------------------- #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN #if USE_SLOW_BINDING #define API_ENTRY(_api) _api #define CALL_GL_API(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ if (_c) return _c->_api(__VA_ARGS__); #elif defined(__arm__) #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ asm volatile( \ GET_TLS(r12) \ "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : "r12" \ ); #elif defined(__aarch64__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ asm volatile( \ "mrs x16, tpidr_el0\n" \ "ldr x16, [x16, %[tls]]\n" \ "cbz x16, 1f\n" \ "ldr x16, [x16, %[api]]\n" \ "br x16\n" \ "1:\n" \ : \ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "x16" \ ); #elif defined(__i386__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void* fn; \ __asm__ volatile( \ "mov %%gs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%P[api](%[fn])\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "cc" \ ); #elif defined(__x86_64__) #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ __asm__ volatile( \ "mov %%fs:0, %[fn]\n" \ "mov %P[tls](%[fn]), %[fn]\n" \ "test %[fn], %[fn]\n" \ "je 1f\n" \ "jmp *%P[api](%[fn])\n" \ "1:\n" \ : [fn] "=r" (fn) \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ : "cc" \ ); #elif defined(__mips64) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ register unsigned long _t0 asm("$12"); \ register unsigned long _fn asm("$25"); \ register unsigned long _tls asm("$3"); \ register unsigned long _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ "rdhwr %[tls], $29\n\t" \ "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ "ld %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0), \ [v0] "=&r"(_v0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ ); #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ register unsigned int _t0 asm("$8"); \ register unsigned int _fn asm("$25"); \ register unsigned int _tls asm("$3"); \ register unsigned int _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ "rdhwr %[tls], $29\n\t" \ "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ "lw %[t0], %[API](%[t0])\n\t" \ "beqz %[t0], 1f\n\t" \ " nop\n\t" \ "move %[fn], %[t0]\n\t" \ "1:\n\t" \ "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0), \ [v0] "=&r"(_v0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ ); #endif #define CALL_GL_API_RETURN(_api, ...) \ CALL_GL_API(_api, __VA_ARGS__) \ return 0; extern "C" { #pragma GCC diagnostic ignored "-Wunused-parameter" #include "gl_api.in" #include "glext_api.in" #pragma GCC diagnostic warning "-Wunused-parameter" } #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN /* * glGetString() is special because we expose some extensions in the wrapper */ extern "C" const GLubyte * __glGetString(GLenum name); const GLubyte * glGetString(GLenum name) { const GLubyte * ret = egl_get_string_for_current_context(name); if (ret == NULL) { gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; ret = _c->glGetString(name); } return ret; } opengl/libs/GLES_CM/gl_api.in0100644 0000000 0000000 00000042213 13077405420 014722 0ustar000000000 0000000 void API_ENTRY(glAlphaFunc)(GLenum func, GLfloat ref) { CALL_GL_API(glAlphaFunc, func, ref); } void API_ENTRY(glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { CALL_GL_API(glClearColor, red, green, blue, alpha); } void API_ENTRY(glClearDepthf)(GLfloat d) { CALL_GL_API(glClearDepthf, d); } void API_ENTRY(glClipPlanef)(GLenum p, const GLfloat *eqn) { CALL_GL_API(glClipPlanef, p, eqn); } void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { CALL_GL_API(glColor4f, red, green, blue, alpha); } void API_ENTRY(glDepthRangef)(GLfloat n, GLfloat f) { CALL_GL_API(glDepthRangef, n, f); } void API_ENTRY(glFogf)(GLenum pname, GLfloat param) { CALL_GL_API(glFogf, pname, param); } void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) { CALL_GL_API(glFogfv, pname, params); } void API_ENTRY(glFrustumf)(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { CALL_GL_API(glFrustumf, l, r, b, t, n, f); } void API_ENTRY(glGetClipPlanef)(GLenum plane, GLfloat *equation) { CALL_GL_API(glGetClipPlanef, plane, equation); } void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *data) { CALL_GL_API(glGetFloatv, pname, data); } void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) { CALL_GL_API(glGetLightfv, light, pname, params); } void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) { CALL_GL_API(glGetMaterialfv, face, pname, params); } void API_ENTRY(glGetTexEnvfv)(GLenum target, GLenum pname, GLfloat *params) { CALL_GL_API(glGetTexEnvfv, target, pname, params); } void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { CALL_GL_API(glGetTexParameterfv, target, pname, params); } void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) { CALL_GL_API(glLightModelf, pname, param); } void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) { CALL_GL_API(glLightModelfv, pname, params); } void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) { CALL_GL_API(glLightf, light, pname, param); } void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) { CALL_GL_API(glLightfv, light, pname, params); } void API_ENTRY(glLineWidth)(GLfloat width) { CALL_GL_API(glLineWidth, width); } void API_ENTRY(glLoadMatrixf)(const GLfloat *m) { CALL_GL_API(glLoadMatrixf, m); } void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) { CALL_GL_API(glMaterialf, face, pname, param); } void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) { CALL_GL_API(glMaterialfv, face, pname, params); } void API_ENTRY(glMultMatrixf)(const GLfloat *m) { CALL_GL_API(glMultMatrixf, m); } void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q); } void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) { CALL_GL_API(glNormal3f, nx, ny, nz); } void API_ENTRY(glOrthof)(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { CALL_GL_API(glOrthof, l, r, b, t, n, f); } void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) { CALL_GL_API(glPointParameterf, pname, param); } void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) { CALL_GL_API(glPointParameterfv, pname, params); } void API_ENTRY(glPointSize)(GLfloat size) { CALL_GL_API(glPointSize, size); } void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { CALL_GL_API(glPolygonOffset, factor, units); } void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { CALL_GL_API(glRotatef, angle, x, y, z); } void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) { CALL_GL_API(glScalef, x, y, z); } void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) { CALL_GL_API(glTexEnvf, target, pname, param); } void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) { CALL_GL_API(glTexEnvfv, target, pname, params); } void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { CALL_GL_API(glTexParameterf, target, pname, param); } void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { CALL_GL_API(glTexParameterfv, target, pname, params); } void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) { CALL_GL_API(glTranslatef, x, y, z); } void API_ENTRY(glActiveTexture)(GLenum texture) { CALL_GL_API(glActiveTexture, texture); } void API_ENTRY(glAlphaFuncx)(GLenum func, GLfixed ref) { CALL_GL_API(glAlphaFuncx, func, ref); } void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { CALL_GL_API(glBindBuffer, target, buffer); } void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { CALL_GL_API(glBindTexture, target, texture); } void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { CALL_GL_API(glBlendFunc, sfactor, dfactor); } void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage) { CALL_GL_API(glBufferData, target, size, data, usage); } void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { CALL_GL_API(glBufferSubData, target, offset, size, data); } void API_ENTRY(glClear)(GLbitfield mask) { CALL_GL_API(glClear, mask); } void API_ENTRY(glClearColorx)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { CALL_GL_API(glClearColorx, red, green, blue, alpha); } void API_ENTRY(glClearDepthx)(GLfixed depth) { CALL_GL_API(glClearDepthx, depth); } void API_ENTRY(glClearStencil)(GLint s) { CALL_GL_API(glClearStencil, s); } void API_ENTRY(glClientActiveTexture)(GLenum texture) { CALL_GL_API(glClientActiveTexture, texture); } void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) { CALL_GL_API(glClipPlanex, plane, equation); } void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { CALL_GL_API(glColor4ub, red, green, blue, alpha); } void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { CALL_GL_API(glColor4x, red, green, blue, alpha); } void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { CALL_GL_API(glColorMask, red, green, blue, alpha); } void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glColorPointer, size, type, stride, pointer); } void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); } void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) { CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); } void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border); } void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); } void API_ENTRY(glCullFace)(GLenum mode) { CALL_GL_API(glCullFace, mode); } void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint *buffers) { CALL_GL_API(glDeleteBuffers, n, buffers); } void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) { CALL_GL_API(glDeleteTextures, n, textures); } void API_ENTRY(glDepthFunc)(GLenum func) { CALL_GL_API(glDepthFunc, func); } void API_ENTRY(glDepthMask)(GLboolean flag) { CALL_GL_API(glDepthMask, flag); } void API_ENTRY(glDepthRangex)(GLfixed n, GLfixed f) { CALL_GL_API(glDepthRangex, n, f); } void API_ENTRY(glDisable)(GLenum cap) { CALL_GL_API(glDisable, cap); } void API_ENTRY(glDisableClientState)(GLenum array) { CALL_GL_API(glDisableClientState, array); } void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { CALL_GL_API(glDrawArrays, mode, first, count); } void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void *indices) { CALL_GL_API(glDrawElements, mode, count, type, indices); } void API_ENTRY(glEnable)(GLenum cap) { CALL_GL_API(glEnable, cap); } void API_ENTRY(glEnableClientState)(GLenum array) { CALL_GL_API(glEnableClientState, array); } void API_ENTRY(glFinish)(void) { CALL_GL_API(glFinish); } void API_ENTRY(glFlush)(void) { CALL_GL_API(glFlush); } void API_ENTRY(glFogx)(GLenum pname, GLfixed param) { CALL_GL_API(glFogx, pname, param); } void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *param) { CALL_GL_API(glFogxv, pname, param); } void API_ENTRY(glFrontFace)(GLenum mode) { CALL_GL_API(glFrontFace, mode); } void API_ENTRY(glFrustumx)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { CALL_GL_API(glFrustumx, l, r, b, t, n, f); } void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *data) { CALL_GL_API(glGetBooleanv, pname, data); } void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetBufferParameteriv, target, pname, params); } void API_ENTRY(glGetClipPlanex)(GLenum plane, GLfixed *equation) { CALL_GL_API(glGetClipPlanex, plane, equation); } void API_ENTRY(glGenBuffers)(GLsizei n, GLuint *buffers) { CALL_GL_API(glGenBuffers, n, buffers); } void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) { CALL_GL_API(glGenTextures, n, textures); } GLenum API_ENTRY(glGetError)(void) { CALL_GL_API_RETURN(glGetError); } void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) { CALL_GL_API(glGetFixedv, pname, params); } void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *data) { CALL_GL_API(glGetIntegerv, pname, data); } void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) { CALL_GL_API(glGetLightxv, light, pname, params); } void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) { CALL_GL_API(glGetMaterialxv, face, pname, params); } void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { CALL_GL_API(glGetPointerv, pname, params); } const GLubyte * API_ENTRY(__glGetString)(GLenum name) { CALL_GL_API_RETURN(glGetString, name); } void API_ENTRY(glGetTexEnviv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexEnviv, target, pname, params); } void API_ENTRY(glGetTexEnvxv)(GLenum target, GLenum pname, GLfixed *params) { CALL_GL_API(glGetTexEnvxv, target, pname, params); } void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetTexParameteriv, target, pname, params); } void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) { CALL_GL_API(glGetTexParameterxv, target, pname, params); } void API_ENTRY(glHint)(GLenum target, GLenum mode) { CALL_GL_API(glHint, target, mode); } GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { CALL_GL_API_RETURN(glIsBuffer, buffer); } GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { CALL_GL_API_RETURN(glIsEnabled, cap); } GLboolean API_ENTRY(glIsTexture)(GLuint texture) { CALL_GL_API_RETURN(glIsTexture, texture); } void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) { CALL_GL_API(glLightModelx, pname, param); } void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *param) { CALL_GL_API(glLightModelxv, pname, param); } void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) { CALL_GL_API(glLightx, light, pname, param); } void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) { CALL_GL_API(glLightxv, light, pname, params); } void API_ENTRY(glLineWidthx)(GLfixed width) { CALL_GL_API(glLineWidthx, width); } void API_ENTRY(glLoadIdentity)(void) { CALL_GL_API(glLoadIdentity); } void API_ENTRY(glLoadMatrixx)(const GLfixed *m) { CALL_GL_API(glLoadMatrixx, m); } void API_ENTRY(glLogicOp)(GLenum opcode) { CALL_GL_API(glLogicOp, opcode); } void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) { CALL_GL_API(glMaterialx, face, pname, param); } void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *param) { CALL_GL_API(glMaterialxv, face, pname, param); } void API_ENTRY(glMatrixMode)(GLenum mode) { CALL_GL_API(glMatrixMode, mode); } void API_ENTRY(glMultMatrixx)(const GLfixed *m) { CALL_GL_API(glMultMatrixx, m); } void API_ENTRY(glMultiTexCoord4x)(GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { CALL_GL_API(glMultiTexCoord4x, texture, s, t, r, q); } void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) { CALL_GL_API(glNormal3x, nx, ny, nz); } void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glNormalPointer, type, stride, pointer); } void API_ENTRY(glOrthox)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { CALL_GL_API(glOrthox, l, r, b, t, n, f); } void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { CALL_GL_API(glPixelStorei, pname, param); } void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) { CALL_GL_API(glPointParameterx, pname, param); } void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) { CALL_GL_API(glPointParameterxv, pname, params); } void API_ENTRY(glPointSizex)(GLfixed size) { CALL_GL_API(glPointSizex, size); } void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) { CALL_GL_API(glPolygonOffsetx, factor, units); } void API_ENTRY(glPopMatrix)(void) { CALL_GL_API(glPopMatrix); } void API_ENTRY(glPushMatrix)(void) { CALL_GL_API(glPushMatrix); } void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); } void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glRotatex, angle, x, y, z); } void API_ENTRY(glSampleCoverage)(GLfloat value, GLboolean invert) { CALL_GL_API(glSampleCoverage, value, invert); } void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) { CALL_GL_API(glSampleCoveragex, value, invert); } void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glScalex, x, y, z); } void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glScissor, x, y, width, height); } void API_ENTRY(glShadeModel)(GLenum mode) { CALL_GL_API(glShadeModel, mode); } void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { CALL_GL_API(glStencilFunc, func, ref, mask); } void API_ENTRY(glStencilMask)(GLuint mask) { CALL_GL_API(glStencilMask, mask); } void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { CALL_GL_API(glStencilOp, fail, zfail, zpass); } void API_ENTRY(glTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glTexCoordPointer, size, type, stride, pointer); } void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glTexEnvi, target, pname, param); } void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexEnvx, target, pname, param); } void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexEnviv, target, pname, params); } void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexEnvxv, target, pname, params); } void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels); } void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glTexParameteri, target, pname, param); } void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexParameterx, target, pname, param); } void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { CALL_GL_API(glTexParameteriv, target, pname, params); } void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexParameterxv, target, pname, params); } void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); } void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glTranslatex, x, y, z); } void API_ENTRY(glVertexPointer)(GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glVertexPointer, size, type, stride, pointer); } void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glViewport, x, y, width, height); } opengl/libs/GLES_CM/glext_api.in0100644 0000000 0000000 00000053557 13077405420 015460 0ustar000000000 0000000 void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); } void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); } void API_ENTRY(glBlendEquationSeparateOES)(GLenum modeRGB, GLenum modeAlpha) { CALL_GL_API(glBlendEquationSeparateOES, modeRGB, modeAlpha); } void API_ENTRY(glBlendFuncSeparateOES)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { CALL_GL_API(glBlendFuncSeparateOES, srcRGB, dstRGB, srcAlpha, dstAlpha); } void API_ENTRY(glBlendEquationOES)(GLenum mode) { CALL_GL_API(glBlendEquationOES, mode); } void API_ENTRY(glDrawTexsOES)(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) { CALL_GL_API(glDrawTexsOES, x, y, z, width, height); } void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint width, GLint height) { CALL_GL_API(glDrawTexiOES, x, y, z, width, height); } void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) { CALL_GL_API(glDrawTexxOES, x, y, z, width, height); } void API_ENTRY(glDrawTexsvOES)(const GLshort *coords) { CALL_GL_API(glDrawTexsvOES, coords); } void API_ENTRY(glDrawTexivOES)(const GLint *coords) { CALL_GL_API(glDrawTexivOES, coords); } void API_ENTRY(glDrawTexxvOES)(const GLfixed *coords) { CALL_GL_API(glDrawTexxvOES, coords); } void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) { CALL_GL_API(glDrawTexfOES, x, y, z, width, height); } void API_ENTRY(glDrawTexfvOES)(const GLfloat *coords) { CALL_GL_API(glDrawTexfvOES, coords); } void API_ENTRY(glAlphaFuncxOES)(GLenum func, GLfixed ref) { CALL_GL_API(glAlphaFuncxOES, func, ref); } void API_ENTRY(glClearColorxOES)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { CALL_GL_API(glClearColorxOES, red, green, blue, alpha); } void API_ENTRY(glClearDepthxOES)(GLfixed depth) { CALL_GL_API(glClearDepthxOES, depth); } void API_ENTRY(glClipPlanexOES)(GLenum plane, const GLfixed *equation) { CALL_GL_API(glClipPlanexOES, plane, equation); } void API_ENTRY(glColor4xOES)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { CALL_GL_API(glColor4xOES, red, green, blue, alpha); } void API_ENTRY(glDepthRangexOES)(GLfixed n, GLfixed f) { CALL_GL_API(glDepthRangexOES, n, f); } void API_ENTRY(glFogxOES)(GLenum pname, GLfixed param) { CALL_GL_API(glFogxOES, pname, param); } void API_ENTRY(glFogxvOES)(GLenum pname, const GLfixed *param) { CALL_GL_API(glFogxvOES, pname, param); } void API_ENTRY(glFrustumxOES)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { CALL_GL_API(glFrustumxOES, l, r, b, t, n, f); } void API_ENTRY(glGetClipPlanexOES)(GLenum plane, GLfixed *equation) { CALL_GL_API(glGetClipPlanexOES, plane, equation); } void API_ENTRY(glGetFixedvOES)(GLenum pname, GLfixed *params) { CALL_GL_API(glGetFixedvOES, pname, params); } void API_ENTRY(glGetTexEnvxvOES)(GLenum target, GLenum pname, GLfixed *params) { CALL_GL_API(glGetTexEnvxvOES, target, pname, params); } void API_ENTRY(glGetTexParameterxvOES)(GLenum target, GLenum pname, GLfixed *params) { CALL_GL_API(glGetTexParameterxvOES, target, pname, params); } void API_ENTRY(glLightModelxOES)(GLenum pname, GLfixed param) { CALL_GL_API(glLightModelxOES, pname, param); } void API_ENTRY(glLightModelxvOES)(GLenum pname, const GLfixed *param) { CALL_GL_API(glLightModelxvOES, pname, param); } void API_ENTRY(glLightxOES)(GLenum light, GLenum pname, GLfixed param) { CALL_GL_API(glLightxOES, light, pname, param); } void API_ENTRY(glLightxvOES)(GLenum light, GLenum pname, const GLfixed *params) { CALL_GL_API(glLightxvOES, light, pname, params); } void API_ENTRY(glLineWidthxOES)(GLfixed width) { CALL_GL_API(glLineWidthxOES, width); } void API_ENTRY(glLoadMatrixxOES)(const GLfixed *m) { CALL_GL_API(glLoadMatrixxOES, m); } void API_ENTRY(glMaterialxOES)(GLenum face, GLenum pname, GLfixed param) { CALL_GL_API(glMaterialxOES, face, pname, param); } void API_ENTRY(glMaterialxvOES)(GLenum face, GLenum pname, const GLfixed *param) { CALL_GL_API(glMaterialxvOES, face, pname, param); } void API_ENTRY(glMultMatrixxOES)(const GLfixed *m) { CALL_GL_API(glMultMatrixxOES, m); } void API_ENTRY(glMultiTexCoord4xOES)(GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { CALL_GL_API(glMultiTexCoord4xOES, texture, s, t, r, q); } void API_ENTRY(glNormal3xOES)(GLfixed nx, GLfixed ny, GLfixed nz) { CALL_GL_API(glNormal3xOES, nx, ny, nz); } void API_ENTRY(glOrthoxOES)(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { CALL_GL_API(glOrthoxOES, l, r, b, t, n, f); } void API_ENTRY(glPointParameterxvOES)(GLenum pname, const GLfixed *params) { CALL_GL_API(glPointParameterxvOES, pname, params); } void API_ENTRY(glPointSizexOES)(GLfixed size) { CALL_GL_API(glPointSizexOES, size); } void API_ENTRY(glPolygonOffsetxOES)(GLfixed factor, GLfixed units) { CALL_GL_API(glPolygonOffsetxOES, factor, units); } void API_ENTRY(glRotatexOES)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glRotatexOES, angle, x, y, z); } void API_ENTRY(glScalexOES)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glScalexOES, x, y, z); } void API_ENTRY(glTexEnvxOES)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexEnvxOES, target, pname, param); } void API_ENTRY(glTexEnvxvOES)(GLenum target, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexEnvxvOES, target, pname, params); } void API_ENTRY(glTexParameterxOES)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexParameterxOES, target, pname, param); } void API_ENTRY(glTexParameterxvOES)(GLenum target, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexParameterxvOES, target, pname, params); } void API_ENTRY(glTranslatexOES)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glTranslatexOES, x, y, z); } void API_ENTRY(glGetLightxvOES)(GLenum light, GLenum pname, GLfixed *params) { CALL_GL_API(glGetLightxvOES, light, pname, params); } void API_ENTRY(glGetMaterialxvOES)(GLenum face, GLenum pname, GLfixed *params) { CALL_GL_API(glGetMaterialxvOES, face, pname, params); } void API_ENTRY(glPointParameterxOES)(GLenum pname, GLfixed param) { CALL_GL_API(glPointParameterxOES, pname, param); } void API_ENTRY(glSampleCoveragexOES)(GLclampx value, GLboolean invert) { CALL_GL_API(glSampleCoveragexOES, value, invert); } void API_ENTRY(glGetTexGenxvOES)(GLenum coord, GLenum pname, GLfixed *params) { CALL_GL_API(glGetTexGenxvOES, coord, pname, params); } void API_ENTRY(glTexGenxOES)(GLenum coord, GLenum pname, GLfixed param) { CALL_GL_API(glTexGenxOES, coord, pname, param); } void API_ENTRY(glTexGenxvOES)(GLenum coord, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexGenxvOES, coord, pname, params); } GLboolean API_ENTRY(glIsRenderbufferOES)(GLuint renderbuffer) { CALL_GL_API_RETURN(glIsRenderbufferOES, renderbuffer); } void API_ENTRY(glBindRenderbufferOES)(GLenum target, GLuint renderbuffer) { CALL_GL_API(glBindRenderbufferOES, target, renderbuffer); } void API_ENTRY(glDeleteRenderbuffersOES)(GLsizei n, const GLuint *renderbuffers) { CALL_GL_API(glDeleteRenderbuffersOES, n, renderbuffers); } void API_ENTRY(glGenRenderbuffersOES)(GLsizei n, GLuint *renderbuffers) { CALL_GL_API(glGenRenderbuffersOES, n, renderbuffers); } void API_ENTRY(glRenderbufferStorageOES)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageOES, target, internalformat, width, height); } void API_ENTRY(glGetRenderbufferParameterivOES)(GLenum target, GLenum pname, GLint *params) { CALL_GL_API(glGetRenderbufferParameterivOES, target, pname, params); } GLboolean API_ENTRY(glIsFramebufferOES)(GLuint framebuffer) { CALL_GL_API_RETURN(glIsFramebufferOES, framebuffer); } void API_ENTRY(glBindFramebufferOES)(GLenum target, GLuint framebuffer) { CALL_GL_API(glBindFramebufferOES, target, framebuffer); } void API_ENTRY(glDeleteFramebuffersOES)(GLsizei n, const GLuint *framebuffers) { CALL_GL_API(glDeleteFramebuffersOES, n, framebuffers); } void API_ENTRY(glGenFramebuffersOES)(GLsizei n, GLuint *framebuffers) { CALL_GL_API(glGenFramebuffersOES, n, framebuffers); } GLenum API_ENTRY(glCheckFramebufferStatusOES)(GLenum target) { CALL_GL_API_RETURN(glCheckFramebufferStatusOES, target); } void API_ENTRY(glFramebufferRenderbufferOES)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { CALL_GL_API(glFramebufferRenderbufferOES, target, attachment, renderbuffertarget, renderbuffer); } void API_ENTRY(glFramebufferTexture2DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { CALL_GL_API(glFramebufferTexture2DOES, target, attachment, textarget, texture, level); } void API_ENTRY(glGetFramebufferAttachmentParameterivOES)(GLenum target, GLenum attachment, GLenum pname, GLint *params) { CALL_GL_API(glGetFramebufferAttachmentParameterivOES, target, attachment, pname, params); } void API_ENTRY(glGenerateMipmapOES)(GLenum target) { CALL_GL_API(glGenerateMipmapOES, target); } void * API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) { CALL_GL_API_RETURN(glMapBufferOES, target, access); } GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) { CALL_GL_API_RETURN(glUnmapBufferOES, target); } void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void **params) { CALL_GL_API(glGetBufferPointervOES, target, pname, params); } void API_ENTRY(glCurrentPaletteMatrixOES)(GLuint matrixpaletteindex) { CALL_GL_API(glCurrentPaletteMatrixOES, matrixpaletteindex); } void API_ENTRY(glLoadPaletteFromModelViewMatrixOES)(void) { CALL_GL_API(glLoadPaletteFromModelViewMatrixOES); } void API_ENTRY(glMatrixIndexPointerOES)(GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glMatrixIndexPointerOES, size, type, stride, pointer); } void API_ENTRY(glWeightPointerOES)(GLint size, GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glWeightPointerOES, size, type, stride, pointer); } void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const void *pointer) { CALL_GL_API(glPointSizePointerOES, type, stride, pointer); } GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed *mantissa, GLint *exponent) { CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent); } void API_ENTRY(glClearDepthfOES)(GLclampf depth) { CALL_GL_API(glClearDepthfOES, depth); } void API_ENTRY(glClipPlanefOES)(GLenum plane, const GLfloat *equation) { CALL_GL_API(glClipPlanefOES, plane, equation); } void API_ENTRY(glDepthRangefOES)(GLclampf n, GLclampf f) { CALL_GL_API(glDepthRangefOES, n, f); } void API_ENTRY(glFrustumfOES)(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { CALL_GL_API(glFrustumfOES, l, r, b, t, n, f); } void API_ENTRY(glGetClipPlanefOES)(GLenum plane, GLfloat *equation) { CALL_GL_API(glGetClipPlanefOES, plane, equation); } void API_ENTRY(glOrthofOES)(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { CALL_GL_API(glOrthofOES, l, r, b, t, n, f); } void API_ENTRY(glTexGenfOES)(GLenum coord, GLenum pname, GLfloat param) { CALL_GL_API(glTexGenfOES, coord, pname, param); } void API_ENTRY(glTexGenfvOES)(GLenum coord, GLenum pname, const GLfloat *params) { CALL_GL_API(glTexGenfvOES, coord, pname, params); } void API_ENTRY(glTexGeniOES)(GLenum coord, GLenum pname, GLint param) { CALL_GL_API(glTexGeniOES, coord, pname, param); } void API_ENTRY(glTexGenivOES)(GLenum coord, GLenum pname, const GLint *params) { CALL_GL_API(glTexGenivOES, coord, pname, params); } void API_ENTRY(glGetTexGenfvOES)(GLenum coord, GLenum pname, GLfloat *params) { CALL_GL_API(glGetTexGenfvOES, coord, pname, params); } void API_ENTRY(glGetTexGenivOES)(GLenum coord, GLenum pname, GLint *params) { CALL_GL_API(glGetTexGenivOES, coord, pname, params); } void API_ENTRY(glBindVertexArrayOES)(GLuint array) { CALL_GL_API(glBindVertexArrayOES, array); } void API_ENTRY(glDeleteVertexArraysOES)(GLsizei n, const GLuint *arrays) { CALL_GL_API(glDeleteVertexArraysOES, n, arrays); } void API_ENTRY(glGenVertexArraysOES)(GLsizei n, GLuint *arrays) { CALL_GL_API(glGenVertexArraysOES, n, arrays); } GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) { CALL_GL_API_RETURN(glIsVertexArrayOES, array); } void API_ENTRY(glCopyTextureLevelsAPPLE)(GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount) { CALL_GL_API(glCopyTextureLevelsAPPLE, destinationTexture, sourceTexture, sourceBaseLevel, sourceLevelCount); } void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height); } void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) { CALL_GL_API(glResolveMultisampleFramebufferAPPLE); } GLsync API_ENTRY(glFenceSyncAPPLE)(GLenum condition, GLbitfield flags) { CALL_GL_API_RETURN(glFenceSyncAPPLE, condition, flags); } GLboolean API_ENTRY(glIsSyncAPPLE)(GLsync sync) { CALL_GL_API_RETURN(glIsSyncAPPLE, sync); } void API_ENTRY(glDeleteSyncAPPLE)(GLsync sync) { CALL_GL_API(glDeleteSyncAPPLE, sync); } GLenum API_ENTRY(glClientWaitSyncAPPLE)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API_RETURN(glClientWaitSyncAPPLE, sync, flags, timeout); } void API_ENTRY(glWaitSyncAPPLE)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API(glWaitSyncAPPLE, sync, flags, timeout); } void API_ENTRY(glGetInteger64vAPPLE)(GLenum pname, GLint64 *params) { CALL_GL_API(glGetInteger64vAPPLE, pname, params); } void API_ENTRY(glGetSyncivAPPLE)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { CALL_GL_API(glGetSyncivAPPLE, sync, pname, bufSize, length, values); } void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments); } void * API_ENTRY(glMapBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { CALL_GL_API_RETURN(glMapBufferRangeEXT, target, offset, length, access); } void API_ENTRY(glFlushMappedBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length) { CALL_GL_API(glFlushMappedBufferRangeEXT, target, offset, length); } void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) { CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount); } void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount) { CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount); } void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height); } void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples); } GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) { CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT); } void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data); } void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params); } void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params); } void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width); } void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height); } void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth); } void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width); } void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height); } void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth); } void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height); } void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples); } void API_ENTRY(glClipPlanefIMG)(GLenum p, const GLfloat *eqn) { CALL_GL_API(glClipPlanefIMG, p, eqn); } void API_ENTRY(glClipPlanexIMG)(GLenum p, const GLfixed *eqn) { CALL_GL_API(glClipPlanexIMG, p, eqn); } void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) { CALL_GL_API(glDeleteFencesNV, n, fences); } void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) { CALL_GL_API(glGenFencesNV, n, fences); } GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) { CALL_GL_API_RETURN(glIsFenceNV, fence); } GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) { CALL_GL_API_RETURN(glTestFenceNV, fence); } void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) { CALL_GL_API(glGetFenceivNV, fence, pname, params); } void API_ENTRY(glFinishFenceNV)(GLuint fence) { CALL_GL_API(glFinishFenceNV, fence); } void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) { CALL_GL_API(glSetFenceNV, fence, condition); } void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) { CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls); } void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) { CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString); } void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) { CALL_GL_API(glEnableDriverControlQCOM, driverControl); } void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) { CALL_GL_API(glDisableDriverControlQCOM, driverControl); } void API_ENTRY(glExtGetTexturesQCOM)(GLuint *textures, GLint maxTextures, GLint *numTextures) { CALL_GL_API(glExtGetTexturesQCOM, textures, maxTextures, numTextures); } void API_ENTRY(glExtGetBuffersQCOM)(GLuint *buffers, GLint maxBuffers, GLint *numBuffers) { CALL_GL_API(glExtGetBuffersQCOM, buffers, maxBuffers, numBuffers); } void API_ENTRY(glExtGetRenderbuffersQCOM)(GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) { CALL_GL_API(glExtGetRenderbuffersQCOM, renderbuffers, maxRenderbuffers, numRenderbuffers); } void API_ENTRY(glExtGetFramebuffersQCOM)(GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) { CALL_GL_API(glExtGetFramebuffersQCOM, framebuffers, maxFramebuffers, numFramebuffers); } void API_ENTRY(glExtGetTexLevelParameterivQCOM)(GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) { CALL_GL_API(glExtGetTexLevelParameterivQCOM, texture, face, level, pname, params); } void API_ENTRY(glExtTexObjectStateOverrideiQCOM)(GLenum target, GLenum pname, GLint param) { CALL_GL_API(glExtTexObjectStateOverrideiQCOM, target, pname, param); } void API_ENTRY(glExtGetTexSubImageQCOM)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels) { CALL_GL_API(glExtGetTexSubImageQCOM, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels); } void API_ENTRY(glExtGetBufferPointervQCOM)(GLenum target, void **params) { CALL_GL_API(glExtGetBufferPointervQCOM, target, params); } void API_ENTRY(glExtGetShadersQCOM)(GLuint *shaders, GLint maxShaders, GLint *numShaders) { CALL_GL_API(glExtGetShadersQCOM, shaders, maxShaders, numShaders); } void API_ENTRY(glExtGetProgramsQCOM)(GLuint *programs, GLint maxPrograms, GLint *numPrograms) { CALL_GL_API(glExtGetProgramsQCOM, programs, maxPrograms, numPrograms); } GLboolean API_ENTRY(glExtIsProgramBinaryQCOM)(GLuint program) { CALL_GL_API_RETURN(glExtIsProgramBinaryQCOM, program); } void API_ENTRY(glExtGetProgramBinarySourceQCOM)(GLuint program, GLenum shadertype, GLchar *source, GLint *length) { CALL_GL_API(glExtGetProgramBinarySourceQCOM, program, shadertype, source, length); } void API_ENTRY(glStartTilingQCOM)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) { CALL_GL_API(glStartTilingQCOM, x, y, width, height, preserveMask); } void API_ENTRY(glEndTilingQCOM)(GLbitfield preserveMask) { CALL_GL_API(glEndTilingQCOM, preserveMask); } opengl/libs/egl_impl.h0100644 0000000 0000000 00000002713 13077405420 013770 0ustar000000000 0000000 /* ** Copyright 2007, 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_EGL_IMPL_H #define ANDROID_EGL_IMPL_H #include #include #include #include #include "hooks.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name); EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index); EGLAPI GLint egl_get_num_extensions_for_current_context(); // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif /* ANDROID_EGL_IMPL_H */ opengl/libs/entries.in0100644 0000000 0000000 00000236430 13077405420 014035 0ustar000000000 0000000 GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program) GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program) GL_ENTRY(void, glActiveTexture, GLenum texture) GL_ENTRY(void, glAlphaFunc, GLenum func, GLfloat ref) GL_ENTRY(void, glAlphaFuncQCOM, GLenum func, GLclampf ref) GL_ENTRY(void, glAlphaFuncx, GLenum func, GLfixed ref) GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLfixed ref) GL_ENTRY(void, glApplyFramebufferAttachmentCMAAINTEL, void) GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader) GL_ENTRY(void, glBeginConditionalRenderNV, GLuint id, GLenum mode) GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor) GL_ENTRY(void, glBeginPerfQueryINTEL, GLuint queryHandle) GL_ENTRY(void, glBeginQuery, GLenum target, GLuint id) GL_ENTRY(void, glBeginQueryEXT, GLenum target, GLuint id) GL_ENTRY(void, glBeginTransformFeedback, GLenum primitiveMode) GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar *name) GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) GL_ENTRY(void, glBindBufferBase, GLenum target, GLuint index, GLuint buffer) GL_ENTRY(void, glBindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) GL_ENTRY(void, glBindFragDataLocationEXT, GLuint program, GLuint color, const GLchar *name) GL_ENTRY(void, glBindFragDataLocationIndexedEXT, GLuint program, GLuint colorNumber, GLuint index, const GLchar *name) GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer) GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer) GL_ENTRY(void, glBindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) GL_ENTRY(void, glBindProgramPipeline, GLuint pipeline) GL_ENTRY(void, glBindProgramPipelineEXT, GLuint pipeline) GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer) GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer) GL_ENTRY(void, glBindSampler, GLuint unit, GLuint sampler) GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) GL_ENTRY(void, glBindTransformFeedback, GLenum target, GLuint id) GL_ENTRY(void, glBindVertexArray, GLuint array) GL_ENTRY(void, glBindVertexArrayOES, GLuint array) GL_ENTRY(void, glBindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) GL_ENTRY(void, glBlendBarrier, void) GL_ENTRY(void, glBlendBarrierKHR, void) GL_ENTRY(void, glBlendBarrierNV, void) GL_ENTRY(void, glBlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) GL_ENTRY(void, glBlendEquation, GLenum mode) GL_ENTRY(void, glBlendEquationOES, GLenum mode) GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha) GL_ENTRY(void, glBlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) GL_ENTRY(void, glBlendEquationSeparateiEXT, GLuint buf, GLenum modeRGB, GLenum modeAlpha) GL_ENTRY(void, glBlendEquationSeparateiOES, GLuint buf, GLenum modeRGB, GLenum modeAlpha) GL_ENTRY(void, glBlendEquationi, GLuint buf, GLenum mode) GL_ENTRY(void, glBlendEquationiEXT, GLuint buf, GLenum mode) GL_ENTRY(void, glBlendEquationiOES, GLuint buf, GLenum mode) GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) GL_ENTRY(void, glBlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) GL_ENTRY(void, glBlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) GL_ENTRY(void, glBlendFuncSeparateiEXT, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) GL_ENTRY(void, glBlendFuncSeparateiOES, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) GL_ENTRY(void, glBlendFunci, GLuint buf, GLenum src, GLenum dst) GL_ENTRY(void, glBlendFunciEXT, GLuint buf, GLenum src, GLenum dst) GL_ENTRY(void, glBlendFunciOES, GLuint buf, GLenum src, GLenum dst) GL_ENTRY(void, glBlendParameteriNV, GLenum pname, GLint value) GL_ENTRY(void, glBlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) GL_ENTRY(void, glBlitFramebufferANGLE, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) GL_ENTRY(void, glBlitFramebufferNV, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage) GL_ENTRY(void, glBufferStorageEXT, GLenum target, GLsizeiptr size, const void *data, GLbitfield flags) GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target) GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target) GL_ENTRY(void, glClear, GLbitfield mask) GL_ENTRY(void, glClearBufferfi, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) GL_ENTRY(void, glClearBufferfv, GLenum buffer, GLint drawbuffer, const GLfloat *value) GL_ENTRY(void, glClearBufferiv, GLenum buffer, GLint drawbuffer, const GLint *value) GL_ENTRY(void, glClearBufferuiv, GLenum buffer, GLint drawbuffer, const GLuint *value) GL_ENTRY(void, glClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) GL_ENTRY(void, glClearColorx, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) GL_ENTRY(void, glClearColorxOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) GL_ENTRY(void, glClearDepthf, GLfloat d) GL_ENTRY(void, glClearDepthfOES, GLclampf depth) GL_ENTRY(void, glClearDepthx, GLfixed depth) GL_ENTRY(void, glClearDepthxOES, GLfixed depth) GL_ENTRY(void, glClearStencil, GLint s) GL_ENTRY(void, glClientActiveTexture, GLenum texture) GL_ENTRY(GLenum, glClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) GL_ENTRY(GLenum, glClientWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout) GL_ENTRY(void, glClipPlanef, GLenum p, const GLfloat *eqn) GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn) GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation) GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation) GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn) GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation) GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) GL_ENTRY(void, glColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) GL_ENTRY(void, glColorMaskiEXT, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) GL_ENTRY(void, glColorMaskiOES, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glCompileShader, GLuint shader) GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) GL_ENTRY(void, glCompressedTexImage3D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) GL_ENTRY(void, glCompressedTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) GL_ENTRY(void, glCopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) GL_ENTRY(void, glCopyBufferSubDataNV, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) GL_ENTRY(void, glCopyImageSubData, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) GL_ENTRY(void, glCopyImageSubDataEXT, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) GL_ENTRY(void, glCopyImageSubDataOES, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) GL_ENTRY(void, glCopyPathNV, GLuint resultPath, GLuint srcPath) GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(void, glCopyTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(void, glCopyTextureLevelsAPPLE, GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount) GL_ENTRY(void, glCoverFillPathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glCoverFillPathNV, GLuint path, GLenum coverMode) GL_ENTRY(void, glCoverStrokePathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glCoverStrokePathNV, GLuint path, GLenum coverMode) GL_ENTRY(void, glCoverageMaskNV, GLboolean mask) GL_ENTRY(void, glCoverageModulationNV, GLenum components) GL_ENTRY(void, glCoverageModulationTableNV, GLsizei n, const GLfloat *v) GL_ENTRY(void, glCoverageOperationNV, GLenum operation) GL_ENTRY(void, glCreatePerfQueryINTEL, GLuint queryId, GLuint *queryHandle) GL_ENTRY(GLuint, glCreateProgram, void) GL_ENTRY(GLuint, glCreateShader, GLenum type) GL_ENTRY(GLuint, glCreateShaderProgramv, GLenum type, GLsizei count, const GLchar *const*strings) GL_ENTRY(GLuint, glCreateShaderProgramvEXT, GLenum type, GLsizei count, const GLchar **strings) GL_ENTRY(void, glCullFace, GLenum mode) GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex) GL_ENTRY(void, glDebugMessageCallback, GLDEBUGPROC callback, const void *userParam) GL_ENTRY(void, glDebugMessageCallbackKHR, GLDEBUGPROCKHR callback, const void *userParam) GL_ENTRY(void, glDebugMessageControl, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) GL_ENTRY(void, glDebugMessageControlKHR, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) GL_ENTRY(void, glDebugMessageInsert, GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) GL_ENTRY(void, glDebugMessageInsertKHR, GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers) GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences) GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint *framebuffers) GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint *framebuffers) GL_ENTRY(void, glDeletePathsNV, GLuint path, GLsizei range) GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors) GL_ENTRY(void, glDeletePerfQueryINTEL, GLuint queryHandle) GL_ENTRY(void, glDeleteProgram, GLuint program) GL_ENTRY(void, glDeleteProgramPipelines, GLsizei n, const GLuint *pipelines) GL_ENTRY(void, glDeleteProgramPipelinesEXT, GLsizei n, const GLuint *pipelines) GL_ENTRY(void, glDeleteQueries, GLsizei n, const GLuint *ids) GL_ENTRY(void, glDeleteQueriesEXT, GLsizei n, const GLuint *ids) GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint *renderbuffers) GL_ENTRY(void, glDeleteSamplers, GLsizei count, const GLuint *samplers) GL_ENTRY(void, glDeleteShader, GLuint shader) GL_ENTRY(void, glDeleteSync, GLsync sync) GL_ENTRY(void, glDeleteSyncAPPLE, GLsync sync) GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) GL_ENTRY(void, glDeleteTransformFeedbacks, GLsizei n, const GLuint *ids) GL_ENTRY(void, glDeleteVertexArrays, GLsizei n, const GLuint *arrays) GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays) GL_ENTRY(void, glDepthFunc, GLenum func) GL_ENTRY(void, glDepthMask, GLboolean flag) GL_ENTRY(void, glDepthRangeArrayfvNV, GLuint first, GLsizei count, const GLfloat *v) GL_ENTRY(void, glDepthRangeIndexedfNV, GLuint index, GLfloat n, GLfloat f) GL_ENTRY(void, glDepthRangef, GLfloat n, GLfloat f) GL_ENTRY(void, glDepthRangefOES, GLclampf n, GLclampf f) GL_ENTRY(void, glDepthRangex, GLfixed n, GLfixed f) GL_ENTRY(void, glDepthRangexOES, GLfixed n, GLfixed f) GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader) GL_ENTRY(void, glDisable, GLenum cap) GL_ENTRY(void, glDisableClientState, GLenum array) GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl) GL_ENTRY(void, glDisableVertexAttribArray, GLuint index) GL_ENTRY(void, glDisablei, GLenum target, GLuint index) GL_ENTRY(void, glDisableiEXT, GLenum target, GLuint index) GL_ENTRY(void, glDisableiNV, GLenum target, GLuint index) GL_ENTRY(void, glDisableiOES, GLenum target, GLuint index) GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments) GL_ENTRY(void, glDispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) GL_ENTRY(void, glDispatchComputeIndirect, GLintptr indirect) GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) GL_ENTRY(void, glDrawArraysIndirect, GLenum mode, const void *indirect) GL_ENTRY(void, glDrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) GL_ENTRY(void, glDrawArraysInstancedANGLE, GLenum mode, GLint first, GLsizei count, GLsizei primcount) GL_ENTRY(void, glDrawArraysInstancedBaseInstanceEXT, GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) GL_ENTRY(void, glDrawArraysInstancedEXT, GLenum mode, GLint start, GLsizei count, GLsizei primcount) GL_ENTRY(void, glDrawArraysInstancedNV, GLenum mode, GLint first, GLsizei count, GLsizei primcount) GL_ENTRY(void, glDrawBuffers, GLsizei n, const GLenum *bufs) GL_ENTRY(void, glDrawBuffersEXT, GLsizei n, const GLenum *bufs) GL_ENTRY(void, glDrawBuffersIndexedEXT, GLint n, const GLenum *location, const GLint *indices) GL_ENTRY(void, glDrawBuffersNV, GLsizei n, const GLenum *bufs) GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void *indices) GL_ENTRY(void, glDrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawElementsBaseVertexEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawElementsBaseVertexOES, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawElementsIndirect, GLenum mode, GLenum type, const void *indirect) GL_ENTRY(void, glDrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount) GL_ENTRY(void, glDrawElementsInstancedANGLE, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) GL_ENTRY(void, glDrawElementsInstancedBaseInstanceEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance) GL_ENTRY(void, glDrawElementsInstancedBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) GL_ENTRY(void, glDrawElementsInstancedBaseVertexBaseInstanceEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) GL_ENTRY(void, glDrawElementsInstancedBaseVertexEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) GL_ENTRY(void, glDrawElementsInstancedBaseVertexOES, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) GL_ENTRY(void, glDrawElementsInstancedEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) GL_ENTRY(void, glDrawElementsInstancedNV, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) GL_ENTRY(void, glDrawRangeElements, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) GL_ENTRY(void, glDrawRangeElementsBaseVertex, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawRangeElementsBaseVertexEXT, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawRangeElementsBaseVertexOES, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords) GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height) GL_ENTRY(void, glDrawTexivOES, const GLint *coords) GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords) GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords) GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) GL_ENTRY(void, glEnable, GLenum cap) GL_ENTRY(void, glEnableClientState, GLenum array) GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl) GL_ENTRY(void, glEnableVertexAttribArray, GLuint index) GL_ENTRY(void, glEnablei, GLenum target, GLuint index) GL_ENTRY(void, glEnableiEXT, GLenum target, GLuint index) GL_ENTRY(void, glEnableiNV, GLenum target, GLuint index) GL_ENTRY(void, glEnableiOES, GLenum target, GLuint index) GL_ENTRY(void, glEndConditionalRenderNV, void) GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor) GL_ENTRY(void, glEndPerfQueryINTEL, GLuint queryHandle) GL_ENTRY(void, glEndQuery, GLenum target) GL_ENTRY(void, glEndQueryEXT, GLenum target) GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask) GL_ENTRY(void, glEndTransformFeedback, void) GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, void **params) GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers) GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length) GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms) GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders) GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels) GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures) GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program) GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param) GL_ENTRY(GLsync, glFenceSync, GLenum condition, GLbitfield flags) GL_ENTRY(GLsync, glFenceSyncAPPLE, GLenum condition, GLbitfield flags) GL_ENTRY(void, glFinish, void) GL_ENTRY(void, glFinishFenceNV, GLuint fence) GL_ENTRY(void, glFlush, void) GL_ENTRY(void, glFlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length) GL_ENTRY(void, glFlushMappedBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length) GL_ENTRY(void, glFogf, GLenum pname, GLfloat param) GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params) GL_ENTRY(void, glFogx, GLenum pname, GLfixed param) GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param) GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *param) GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *param) GL_ENTRY(void, glFragmentCoverageColorNV, GLuint color) GL_ENTRY(void, glFramebufferParameteri, GLenum target, GLenum pname, GLint param) GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) GL_ENTRY(void, glFramebufferSampleLocationsfvNV, GLenum target, GLuint start, GLsizei count, const GLfloat *v) GL_ENTRY(void, glFramebufferTexture, GLenum target, GLenum attachment, GLuint texture, GLint level) GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) GL_ENTRY(void, glFramebufferTextureEXT, GLenum target, GLenum attachment, GLuint texture, GLint level) GL_ENTRY(void, glFramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) GL_ENTRY(void, glFramebufferTextureMultisampleMultiviewOVR, GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews) GL_ENTRY(void, glFramebufferTextureMultiviewOVR, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews) GL_ENTRY(void, glFramebufferTextureOES, GLenum target, GLenum attachment, GLuint texture, GLint level) GL_ENTRY(void, glFrontFace, GLenum mode) GL_ENTRY(void, glFrustumf, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) GL_ENTRY(void, glFrustumfOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) GL_ENTRY(void, glFrustumx, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) GL_ENTRY(void, glFrustumxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers) GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences) GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint *framebuffers) GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint *framebuffers) GL_ENTRY(GLuint, glGenPathsNV, GLsizei range) GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors) GL_ENTRY(void, glGenProgramPipelines, GLsizei n, GLuint *pipelines) GL_ENTRY(void, glGenProgramPipelinesEXT, GLsizei n, GLuint *pipelines) GL_ENTRY(void, glGenQueries, GLsizei n, GLuint *ids) GL_ENTRY(void, glGenQueriesEXT, GLsizei n, GLuint *ids) GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint *renderbuffers) GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint *renderbuffers) GL_ENTRY(void, glGenSamplers, GLsizei count, GLuint *samplers) GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) GL_ENTRY(void, glGenTransformFeedbacks, GLsizei n, GLuint *ids) GL_ENTRY(void, glGenVertexArrays, GLsizei n, GLuint *arrays) GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays) GL_ENTRY(void, glGenerateMipmap, GLenum target) GL_ENTRY(void, glGenerateMipmapOES, GLenum target) GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) GL_ENTRY(void, glGetActiveUniformBlockName, GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) GL_ENTRY(void, glGetActiveUniformBlockiv, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) GL_ENTRY(void, glGetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) GL_ENTRY(GLint, glGetAttribLocation, GLuint program, const GLchar *name) GL_ENTRY(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean *data) GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *data) GL_ENTRY(void, glGetBufferParameteri64v, GLenum target, GLenum pname, GLint64 *params) GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetBufferPointerv, GLenum target, GLenum pname, void **params) GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void **params) GL_ENTRY(void, glGetClipPlanef, GLenum plane, GLfloat *equation) GL_ENTRY(void, glGetClipPlanefOES, GLenum plane, GLfloat *equation) GL_ENTRY(void, glGetClipPlanex, GLenum plane, GLfixed *equation) GL_ENTRY(void, glGetClipPlanexOES, GLenum plane, GLfixed *equation) GL_ENTRY(void, glGetCoverageModulationTableNV, GLsizei bufsize, GLfloat *v) GL_ENTRY(GLuint, glGetDebugMessageLog, GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) GL_ENTRY(GLuint, glGetDebugMessageLogKHR, GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls) GL_ENTRY(GLenum, glGetError, void) GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params) GL_ENTRY(void, glGetFirstPerfQueryIdINTEL, GLuint *queryId) GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetFloati_vNV, GLenum target, GLuint index, GLfloat *data) GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *data) GL_ENTRY(GLint, glGetFragDataIndexEXT, GLuint program, const GLchar *name) GL_ENTRY(GLint, glGetFragDataLocation, GLuint program, const GLchar *name) GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint *params) GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint *params) GL_ENTRY(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(GLenum, glGetGraphicsResetStatus, void) GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void) GL_ENTRY(GLenum, glGetGraphicsResetStatusKHR, void) GL_ENTRY(GLuint64, glGetImageHandleNV, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format) GL_ENTRY(void, glGetInteger64i_v, GLenum target, GLuint index, GLint64 *data) GL_ENTRY(void, glGetInteger64v, GLenum pname, GLint64 *data) GL_ENTRY(void, glGetInteger64vAPPLE, GLenum pname, GLint64 *params) GL_ENTRY(void, glGetIntegeri_v, GLenum target, GLuint index, GLint *data) GL_ENTRY(void, glGetIntegeri_vEXT, GLenum target, GLuint index, GLint *data) GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *data) GL_ENTRY(void, glGetInternalformatSampleivNV, GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params) GL_ENTRY(void, glGetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val) GL_ENTRY(void, glGetNextPerfQueryIdINTEL, GLuint queryId, GLuint *nextQueryId) GL_ENTRY(void, glGetObjectLabel, GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) GL_ENTRY(void, glGetObjectLabelEXT, GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) GL_ENTRY(void, glGetObjectLabelKHR, GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) GL_ENTRY(void, glGetObjectPtrLabel, const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) GL_ENTRY(void, glGetObjectPtrLabelKHR, const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) GL_ENTRY(void, glGetPathCommandsNV, GLuint path, GLubyte *commands) GL_ENTRY(void, glGetPathCoordsNV, GLuint path, GLfloat *coords) GL_ENTRY(void, glGetPathDashArrayNV, GLuint path, GLfloat *dashArray) GL_ENTRY(GLfloat, glGetPathLengthNV, GLuint path, GLsizei startSegment, GLsizei numSegments) GL_ENTRY(void, glGetPathMetricRangeNV, GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics) GL_ENTRY(void, glGetPathMetricsNV, GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics) GL_ENTRY(void, glGetPathParameterfvNV, GLuint path, GLenum pname, GLfloat *value) GL_ENTRY(void, glGetPathParameterivNV, GLuint path, GLenum pname, GLint *value) GL_ENTRY(void, glGetPathSpacingNV, GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing) GL_ENTRY(void, glGetPerfCounterInfoINTEL, GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue) GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, void *data) GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString) GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString) GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups) GL_ENTRY(void, glGetPerfQueryDataINTEL, GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten) GL_ENTRY(void, glGetPerfQueryIdByNameINTEL, GLchar *queryName, GLuint *queryId) GL_ENTRY(void, glGetPerfQueryInfoINTEL, GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask) GL_ENTRY(void, glGetPointerv, GLenum pname, void **params) GL_ENTRY(void, glGetPointervKHR, GLenum pname, void **params) GL_ENTRY(void, glGetProgramBinary, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) GL_ENTRY(void, glGetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint *params) GL_ENTRY(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) GL_ENTRY(void, glGetProgramPipelineInfoLogEXT, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) GL_ENTRY(void, glGetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint *params) GL_ENTRY(void, glGetProgramPipelineivEXT, GLuint pipeline, GLenum pname, GLint *params) GL_ENTRY(GLuint, glGetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar *name) GL_ENTRY(GLint, glGetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar *name) GL_ENTRY(GLint, glGetProgramResourceLocationIndexEXT, GLuint program, GLenum programInterface, const GLchar *name) GL_ENTRY(void, glGetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) GL_ENTRY(void, glGetProgramResourcefvNV, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params) GL_ENTRY(void, glGetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint *params) GL_ENTRY(void, glGetQueryObjecti64vEXT, GLuint id, GLenum pname, GLint64 *params) GL_ENTRY(void, glGetQueryObjectivEXT, GLuint id, GLenum pname, GLint *params) GL_ENTRY(void, glGetQueryObjectui64vEXT, GLuint id, GLenum pname, GLuint64 *params) GL_ENTRY(void, glGetQueryObjectuiv, GLuint id, GLenum pname, GLuint *params) GL_ENTRY(void, glGetQueryObjectuivEXT, GLuint id, GLenum pname, GLuint *params) GL_ENTRY(void, glGetQueryiv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetQueryivEXT, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetSamplerParameterIiv, GLuint sampler, GLenum pname, GLint *params) GL_ENTRY(void, glGetSamplerParameterIivEXT, GLuint sampler, GLenum pname, GLint *params) GL_ENTRY(void, glGetSamplerParameterIivOES, GLuint sampler, GLenum pname, GLint *params) GL_ENTRY(void, glGetSamplerParameterIuiv, GLuint sampler, GLenum pname, GLuint *params) GL_ENTRY(void, glGetSamplerParameterIuivEXT, GLuint sampler, GLenum pname, GLuint *params) GL_ENTRY(void, glGetSamplerParameterIuivOES, GLuint sampler, GLenum pname, GLuint *params) GL_ENTRY(void, glGetSamplerParameterfv, GLuint sampler, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetSamplerParameteriv, GLuint sampler, GLenum pname, GLint *params) GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision) GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint *params) GL_ENTRY(const GLubyte *, glGetString, GLenum name) GL_ENTRY(const GLubyte *, glGetStringi, GLenum name, GLuint index) GL_ENTRY(void, glGetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) GL_ENTRY(void, glGetSyncivAPPLE, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) GL_ENTRY(void, glGetTexEnvfv, GLenum target, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetTexEnviv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexEnvxv, GLenum target, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetTexEnvxvOES, GLenum target, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetTexLevelParameterfv, GLenum target, GLint level, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetTexLevelParameteriv, GLenum target, GLint level, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexParameterIiv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexParameterIivEXT, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexParameterIivOES, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexParameterIuiv, GLenum target, GLenum pname, GLuint *params) GL_ENTRY(void, glGetTexParameterIuivEXT, GLenum target, GLenum pname, GLuint *params) GL_ENTRY(void, glGetTexParameterIuivOES, GLenum target, GLenum pname, GLuint *params) GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params) GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params) GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params) GL_ENTRY(GLuint64, glGetTextureHandleNV, GLuint texture) GL_ENTRY(GLuint64, glGetTextureSamplerHandleNV, GLuint texture, GLuint sampler) GL_ENTRY(void, glGetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) GL_ENTRY(void, glGetTranslatedShaderSourceANGLE, GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) GL_ENTRY(GLuint, glGetUniformBlockIndex, GLuint program, const GLchar *uniformBlockName) GL_ENTRY(void, glGetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices) GL_ENTRY(GLint, glGetUniformLocation, GLuint program, const GLchar *name) GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat *params) GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint *params) GL_ENTRY(void, glGetUniformuiv, GLuint program, GLint location, GLuint *params) GL_ENTRY(void, glGetVertexAttribIiv, GLuint index, GLenum pname, GLint *params) GL_ENTRY(void, glGetVertexAttribIuiv, GLuint index, GLenum pname, GLuint *params) GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void **pointer) GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat *params) GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint *params) GL_ENTRY(void, glGetnUniformfv, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) GL_ENTRY(void, glGetnUniformfvKHR, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) GL_ENTRY(void, glGetnUniformiv, GLuint program, GLint location, GLsizei bufSize, GLint *params) GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params) GL_ENTRY(void, glGetnUniformivKHR, GLuint program, GLint location, GLsizei bufSize, GLint *params) GL_ENTRY(void, glGetnUniformuiv, GLuint program, GLint location, GLsizei bufSize, GLuint *params) GL_ENTRY(void, glGetnUniformuivKHR, GLuint program, GLint location, GLsizei bufSize, GLuint *params) GL_ENTRY(void, glHint, GLenum target, GLenum mode) GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker) GL_ENTRY(void, glInterpolatePathsNV, GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight) GL_ENTRY(void, glInvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments) GL_ENTRY(void, glInvalidateSubFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) GL_ENTRY(GLboolean, glIsEnabledi, GLenum target, GLuint index) GL_ENTRY(GLboolean, glIsEnablediEXT, GLenum target, GLuint index) GL_ENTRY(GLboolean, glIsEnablediNV, GLenum target, GLuint index) GL_ENTRY(GLboolean, glIsEnablediOES, GLenum target, GLuint index) GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence) GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer) GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer) GL_ENTRY(GLboolean, glIsImageHandleResidentNV, GLuint64 handle) GL_ENTRY(GLboolean, glIsPathNV, GLuint path) GL_ENTRY(GLboolean, glIsPointInFillPathNV, GLuint path, GLuint mask, GLfloat x, GLfloat y) GL_ENTRY(GLboolean, glIsPointInStrokePathNV, GLuint path, GLfloat x, GLfloat y) GL_ENTRY(GLboolean, glIsProgram, GLuint program) GL_ENTRY(GLboolean, glIsProgramPipeline, GLuint pipeline) GL_ENTRY(GLboolean, glIsProgramPipelineEXT, GLuint pipeline) GL_ENTRY(GLboolean, glIsQuery, GLuint id) GL_ENTRY(GLboolean, glIsQueryEXT, GLuint id) GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer) GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer) GL_ENTRY(GLboolean, glIsSampler, GLuint sampler) GL_ENTRY(GLboolean, glIsShader, GLuint shader) GL_ENTRY(GLboolean, glIsSync, GLsync sync) GL_ENTRY(GLboolean, glIsSyncAPPLE, GLsync sync) GL_ENTRY(GLboolean, glIsTexture, GLuint texture) GL_ENTRY(GLboolean, glIsTextureHandleResidentNV, GLuint64 handle) GL_ENTRY(GLboolean, glIsTransformFeedback, GLuint id) GL_ENTRY(GLboolean, glIsVertexArray, GLuint array) GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array) GL_ENTRY(void, glLabelObjectEXT, GLenum type, GLuint object, GLsizei length, const GLchar *label) GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param) GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params) GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param) GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param) GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *param) GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *param) GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param) GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params) GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param) GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param) GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params) GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params) GL_ENTRY(void, glLineWidth, GLfloat width) GL_ENTRY(void, glLineWidthx, GLfixed width) GL_ENTRY(void, glLineWidthxOES, GLfixed width) GL_ENTRY(void, glLinkProgram, GLuint program) GL_ENTRY(void, glLoadIdentity, void) GL_ENTRY(void, glLoadMatrixf, const GLfloat *m) GL_ENTRY(void, glLoadMatrixx, const GLfixed *m) GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m) GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void) GL_ENTRY(void, glLogicOp, GLenum opcode) GL_ENTRY(void, glMakeImageHandleNonResidentNV, GLuint64 handle) GL_ENTRY(void, glMakeImageHandleResidentNV, GLuint64 handle, GLenum access) GL_ENTRY(void, glMakeTextureHandleNonResidentNV, GLuint64 handle) GL_ENTRY(void, glMakeTextureHandleResidentNV, GLuint64 handle) GL_ENTRY(void *, glMapBufferOES, GLenum target, GLenum access) GL_ENTRY(void *, glMapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) GL_ENTRY(void *, glMapBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param) GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params) GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param) GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param) GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *param) GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *param) GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glMatrixLoad3x2fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMatrixLoad3x3fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMatrixLoadTranspose3x3fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMatrixMode, GLenum mode) GL_ENTRY(void, glMatrixMult3x2fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMatrixMult3x3fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMatrixMultTranspose3x3fNV, GLenum matrixMode, const GLfloat *m) GL_ENTRY(void, glMemoryBarrier, GLbitfield barriers) GL_ENTRY(void, glMemoryBarrierByRegion, GLbitfield barriers) GL_ENTRY(void, glMinSampleShading, GLfloat value) GL_ENTRY(void, glMinSampleShadingOES, GLfloat value) GL_ENTRY(void, glMultMatrixf, const GLfloat *m) GL_ENTRY(void, glMultMatrixx, const GLfixed *m) GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m) GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) GL_ENTRY(void, glMultiDrawArraysIndirectEXT, GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride) GL_ENTRY(void, glMultiDrawElementsBaseVertexEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) GL_ENTRY(void, glMultiDrawElementsBaseVertexOES, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount) GL_ENTRY(void, glMultiDrawElementsIndirectEXT, GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride) GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) GL_ENTRY(void, glMultiTexCoord4x, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q) GL_ENTRY(void, glMultiTexCoord4xOES, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q) GL_ENTRY(void, glNamedFramebufferSampleLocationsfvNV, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v) GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz) GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz) GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz) GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glObjectLabel, GLenum identifier, GLuint name, GLsizei length, const GLchar *label) GL_ENTRY(void, glObjectLabelKHR, GLenum identifier, GLuint name, GLsizei length, const GLchar *label) GL_ENTRY(void, glObjectPtrLabel, const void *ptr, GLsizei length, const GLchar *label) GL_ENTRY(void, glObjectPtrLabelKHR, const void *ptr, GLsizei length, const GLchar *label) GL_ENTRY(void, glOrthof, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) GL_ENTRY(void, glOrthofOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) GL_ENTRY(void, glOrthox, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) GL_ENTRY(void, glOrthoxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) GL_ENTRY(void, glPatchParameteri, GLenum pname, GLint value) GL_ENTRY(void, glPatchParameteriEXT, GLenum pname, GLint value) GL_ENTRY(void, glPatchParameteriOES, GLenum pname, GLint value) GL_ENTRY(void, glPathCommandsNV, GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords) GL_ENTRY(void, glPathCoordsNV, GLuint path, GLsizei numCoords, GLenum coordType, const void *coords) GL_ENTRY(void, glPathCoverDepthFuncNV, GLenum func) GL_ENTRY(void, glPathDashArrayNV, GLuint path, GLsizei dashCount, const GLfloat *dashArray) GL_ENTRY(GLenum, glPathGlyphIndexArrayNV, GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale) GL_ENTRY(GLenum, glPathGlyphIndexRangeNV, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]) GL_ENTRY(void, glPathGlyphRangeNV, GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale) GL_ENTRY(void, glPathGlyphsNV, GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale) GL_ENTRY(GLenum, glPathMemoryGlyphIndexArrayNV, GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale) GL_ENTRY(void, glPathParameterfNV, GLuint path, GLenum pname, GLfloat value) GL_ENTRY(void, glPathParameterfvNV, GLuint path, GLenum pname, const GLfloat *value) GL_ENTRY(void, glPathParameteriNV, GLuint path, GLenum pname, GLint value) GL_ENTRY(void, glPathParameterivNV, GLuint path, GLenum pname, const GLint *value) GL_ENTRY(void, glPathStencilDepthOffsetNV, GLfloat factor, GLfloat units) GL_ENTRY(void, glPathStencilFuncNV, GLenum func, GLint ref, GLuint mask) GL_ENTRY(void, glPathStringNV, GLuint path, GLenum format, GLsizei length, const void *pathString) GL_ENTRY(void, glPathSubCommandsNV, GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords) GL_ENTRY(void, glPathSubCoordsNV, GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords) GL_ENTRY(void, glPauseTransformFeedback, void) GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) GL_ENTRY(GLboolean, glPointAlongPathNV, GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY) GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param) GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params) GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param) GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param) GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params) GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params) GL_ENTRY(void, glPointSize, GLfloat size) GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glPointSizex, GLfixed size) GL_ENTRY(void, glPointSizexOES, GLfixed size) GL_ENTRY(void, glPolygonModeNV, GLenum face, GLenum mode) GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units) GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units) GL_ENTRY(void, glPopDebugGroup, void) GL_ENTRY(void, glPopDebugGroupKHR, void) GL_ENTRY(void, glPopGroupMarkerEXT, void) GL_ENTRY(void, glPopMatrix, void) GL_ENTRY(void, glPrimitiveBoundingBox, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) GL_ENTRY(void, glPrimitiveBoundingBoxEXT, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) GL_ENTRY(void, glPrimitiveBoundingBoxOES, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) GL_ENTRY(void, glProgramBinary, GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length) GL_ENTRY(void, glProgramParameteri, GLuint program, GLenum pname, GLint value) GL_ENTRY(void, glProgramParameteriEXT, GLuint program, GLenum pname, GLint value) GL_ENTRY(void, glProgramPathFragmentInputGenNV, GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs) GL_ENTRY(void, glProgramUniform1f, GLuint program, GLint location, GLfloat v0) GL_ENTRY(void, glProgramUniform1fEXT, GLuint program, GLint location, GLfloat v0) GL_ENTRY(void, glProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform1i, GLuint program, GLint location, GLint v0) GL_ENTRY(void, glProgramUniform1iEXT, GLuint program, GLint location, GLint v0) GL_ENTRY(void, glProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform1ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform1ui, GLuint program, GLint location, GLuint v0) GL_ENTRY(void, glProgramUniform1uiEXT, GLuint program, GLint location, GLuint v0) GL_ENTRY(void, glProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform1uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) GL_ENTRY(void, glProgramUniform2fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1) GL_ENTRY(void, glProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform2fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) GL_ENTRY(void, glProgramUniform2iEXT, GLuint program, GLint location, GLint v0, GLint v1) GL_ENTRY(void, glProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform2ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) GL_ENTRY(void, glProgramUniform2uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1) GL_ENTRY(void, glProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform2uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) GL_ENTRY(void, glProgramUniform3fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) GL_ENTRY(void, glProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform3fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) GL_ENTRY(void, glProgramUniform3iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) GL_ENTRY(void, glProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform3ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) GL_ENTRY(void, glProgramUniform3uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) GL_ENTRY(void, glProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform3uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) GL_ENTRY(void, glProgramUniform4fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) GL_ENTRY(void, glProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform4fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) GL_ENTRY(void, glProgramUniform4iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) GL_ENTRY(void, glProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform4ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) GL_ENTRY(void, glProgramUniform4uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) GL_ENTRY(void, glProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniform4uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glProgramUniformHandleui64NV, GLuint program, GLint location, GLuint64 value) GL_ENTRY(void, glProgramUniformHandleui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64 *values) GL_ENTRY(void, glProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix2x3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix2x4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3x2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix3x4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4x2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glProgramUniformMatrix4x3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glPushDebugGroup, GLenum source, GLuint id, GLsizei length, const GLchar *message) GL_ENTRY(void, glPushDebugGroupKHR, GLenum source, GLuint id, GLsizei length, const GLchar *message) GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker) GL_ENTRY(void, glPushMatrix, void) GL_ENTRY(void, glQueryCounterEXT, GLuint id, GLenum target) GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed *mantissa, GLint *exponent) GL_ENTRY(void, glRasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) GL_ENTRY(void, glReadBuffer, GLenum src) GL_ENTRY(void, glReadBufferIndexedEXT, GLenum src, GLint index) GL_ENTRY(void, glReadBufferNV, GLenum mode) GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) GL_ENTRY(void, glReadnPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) GL_ENTRY(void, glReadnPixelsKHR, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) GL_ENTRY(void, glReleaseShaderCompiler, void) GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisampleANGLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisampleAPPLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageMultisampleNV, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glResolveDepthValuesNV, void) GL_ENTRY(void, glResolveMultisampleFramebufferAPPLE, void) GL_ENTRY(void, glResumeTransformFeedback, void) GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glSampleCoverage, GLfloat value, GLboolean invert) GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert) GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert) GL_ENTRY(void, glSampleMaski, GLuint maskNumber, GLbitfield mask) GL_ENTRY(void, glSamplerParameterIiv, GLuint sampler, GLenum pname, const GLint *param) GL_ENTRY(void, glSamplerParameterIivEXT, GLuint sampler, GLenum pname, const GLint *param) GL_ENTRY(void, glSamplerParameterIivOES, GLuint sampler, GLenum pname, const GLint *param) GL_ENTRY(void, glSamplerParameterIuiv, GLuint sampler, GLenum pname, const GLuint *param) GL_ENTRY(void, glSamplerParameterIuivEXT, GLuint sampler, GLenum pname, const GLuint *param) GL_ENTRY(void, glSamplerParameterIuivOES, GLuint sampler, GLenum pname, const GLuint *param) GL_ENTRY(void, glSamplerParameterf, GLuint sampler, GLenum pname, GLfloat param) GL_ENTRY(void, glSamplerParameterfv, GLuint sampler, GLenum pname, const GLfloat *param) GL_ENTRY(void, glSamplerParameteri, GLuint sampler, GLenum pname, GLint param) GL_ENTRY(void, glSamplerParameteriv, GLuint sampler, GLenum pname, const GLint *param) GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z) GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(void, glScissorArrayvNV, GLuint first, GLsizei count, const GLint *v) GL_ENTRY(void, glScissorIndexedNV, GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) GL_ENTRY(void, glScissorIndexedvNV, GLuint index, const GLint *v) GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList) GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition) GL_ENTRY(void, glShadeModel, GLenum mode) GL_ENTRY(void, glShaderBinary, GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) GL_ENTRY(void, glStencilFillPathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glStencilFillPathNV, GLuint path, GLenum fillMode, GLuint mask) GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask) GL_ENTRY(void, glStencilMask, GLuint mask) GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask) GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) GL_ENTRY(void, glStencilStrokePathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glStencilStrokePathNV, GLuint path, GLint reference, GLuint mask) GL_ENTRY(void, glStencilThenCoverFillPathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glStencilThenCoverFillPathNV, GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode) GL_ENTRY(void, glStencilThenCoverStrokePathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glStencilThenCoverStrokePathNV, GLuint path, GLint reference, GLuint mask, GLenum coverMode) GL_ENTRY(void, glSubpixelPrecisionBiasNV, GLuint xbits, GLuint ybits) GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence) GL_ENTRY(void, glTexBuffer, GLenum target, GLenum internalformat, GLuint buffer) GL_ENTRY(void, glTexBufferEXT, GLenum target, GLenum internalformat, GLuint buffer) GL_ENTRY(void, glTexBufferOES, GLenum target, GLenum internalformat, GLuint buffer) GL_ENTRY(void, glTexBufferRange, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) GL_ENTRY(void, glTexBufferRangeEXT, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) GL_ENTRY(void, glTexBufferRangeOES, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param) GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params) GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param) GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params) GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param) GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param) GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params) GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params) GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param) GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params) GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param) GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params) GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param) GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params) GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTexImage3D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTexPageCommitmentEXT, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit) GL_ENTRY(void, glTexParameterIiv, GLenum target, GLenum pname, const GLint *params) GL_ENTRY(void, glTexParameterIivEXT, GLenum target, GLenum pname, const GLint *params) GL_ENTRY(void, glTexParameterIivOES, GLenum target, GLenum pname, const GLint *params) GL_ENTRY(void, glTexParameterIuiv, GLenum target, GLenum pname, const GLuint *params) GL_ENTRY(void, glTexParameterIuivEXT, GLenum target, GLenum pname, const GLuint *params) GL_ENTRY(void, glTexParameterIuivOES, GLenum target, GLenum pname, const GLuint *params) GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params) GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params) GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param) GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param) GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params) GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params) GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) GL_ENTRY(void, glTexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glTexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) GL_ENTRY(void, glTexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) GL_ENTRY(void, glTexStorage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) GL_ENTRY(void, glTexStorage3DMultisampleOES, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) GL_ENTRY(void, glTextureViewEXT, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) GL_ENTRY(void, glTextureViewOES, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) GL_ENTRY(void, glTransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode) GL_ENTRY(void, glTransformPathNV, GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues) GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z) GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z) GL_ENTRY(void, glUniform1f, GLint location, GLfloat v0) GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glUniform1i, GLint location, GLint v0) GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glUniform1ui, GLint location, GLuint v0) GL_ENTRY(void, glUniform1uiv, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glUniform2f, GLint location, GLfloat v0, GLfloat v1) GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glUniform2i, GLint location, GLint v0, GLint v1) GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glUniform2ui, GLint location, GLuint v0, GLuint v1) GL_ENTRY(void, glUniform2uiv, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glUniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glUniform3i, GLint location, GLint v0, GLint v1, GLint v2) GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glUniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) GL_ENTRY(void, glUniform3uiv, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glUniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat *value) GL_ENTRY(void, glUniform4i, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint *value) GL_ENTRY(void, glUniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) GL_ENTRY(void, glUniform4uiv, GLint location, GLsizei count, const GLuint *value) GL_ENTRY(void, glUniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) GL_ENTRY(void, glUniformHandleui64NV, GLint location, GLuint64 value) GL_ENTRY(void, glUniformHandleui64vNV, GLint location, GLsizei count, const GLuint64 *value) GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix2x3fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix2x4fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix3x2fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix3x4fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix4x2fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(void, glUniformMatrix4x3fvNV, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_ENTRY(GLboolean, glUnmapBuffer, GLenum target) GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) GL_ENTRY(void, glUseProgram, GLuint program) GL_ENTRY(void, glUseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) GL_ENTRY(void, glUseProgramStagesEXT, GLuint pipeline, GLbitfield stages, GLuint program) GL_ENTRY(void, glValidateProgram, GLuint program) GL_ENTRY(void, glValidateProgramPipeline, GLuint pipeline) GL_ENTRY(void, glValidateProgramPipelineEXT, GLuint pipeline) GL_ENTRY(void, glVertexAttrib1f, GLuint index, GLfloat x) GL_ENTRY(void, glVertexAttrib1fv, GLuint index, const GLfloat *v) GL_ENTRY(void, glVertexAttrib2f, GLuint index, GLfloat x, GLfloat y) GL_ENTRY(void, glVertexAttrib2fv, GLuint index, const GLfloat *v) GL_ENTRY(void, glVertexAttrib3f, GLuint index, GLfloat x, GLfloat y, GLfloat z) GL_ENTRY(void, glVertexAttrib3fv, GLuint index, const GLfloat *v) GL_ENTRY(void, glVertexAttrib4f, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) GL_ENTRY(void, glVertexAttrib4fv, GLuint index, const GLfloat *v) GL_ENTRY(void, glVertexAttribBinding, GLuint attribindex, GLuint bindingindex) GL_ENTRY(void, glVertexAttribDivisor, GLuint index, GLuint divisor) GL_ENTRY(void, glVertexAttribDivisorANGLE, GLuint index, GLuint divisor) GL_ENTRY(void, glVertexAttribDivisorEXT, GLuint index, GLuint divisor) GL_ENTRY(void, glVertexAttribDivisorNV, GLuint index, GLuint divisor) GL_ENTRY(void, glVertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) GL_ENTRY(void, glVertexAttribI4i, GLuint index, GLint x, GLint y, GLint z, GLint w) GL_ENTRY(void, glVertexAttribI4iv, GLuint index, const GLint *v) GL_ENTRY(void, glVertexAttribI4ui, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) GL_ENTRY(void, glVertexAttribI4uiv, GLuint index, const GLuint *v) GL_ENTRY(void, glVertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) GL_ENTRY(void, glVertexAttribIPointer, GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glVertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) GL_ENTRY(void, glVertexBindingDivisor, GLuint bindingindex, GLuint divisor) GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const void *pointer) GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) GL_ENTRY(void, glViewportArrayvNV, GLuint first, GLsizei count, const GLfloat *v) GL_ENTRY(void, glViewportIndexedfNV, GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) GL_ENTRY(void, glViewportIndexedfvNV, GLuint index, const GLfloat *v) GL_ENTRY(void, glWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) GL_ENTRY(void, glWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout) GL_ENTRY(void, glWeightPathsNV, GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights) GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer) opengl/libs/enums.in0100644 0000000 0000000 00000172006 13077405420 013511 0ustar000000000 0000000 GL_ENUM(0x0000,GL_POINTS) GL_ENUM(0x0001,GL_LINES) GL_ENUM(0x0002,GL_LINE_LOOP) GL_ENUM(0x0003,GL_LINE_STRIP) GL_ENUM(0x0004,GL_TRIANGLES) GL_ENUM(0x0005,GL_TRIANGLE_STRIP) GL_ENUM(0x0006,GL_TRIANGLE_FAN) GL_ENUM(0x0200,GL_NEVER) GL_ENUM(0x0201,GL_LESS) GL_ENUM(0x0202,GL_EQUAL) GL_ENUM(0x0203,GL_LEQUAL) GL_ENUM(0x0204,GL_GREATER) GL_ENUM(0x0205,GL_NOTEQUAL) GL_ENUM(0x0206,GL_GEQUAL) GL_ENUM(0x0207,GL_ALWAYS) GL_ENUM(0x0300,GL_SRC_COLOR) GL_ENUM(0x0301,GL_ONE_MINUS_SRC_COLOR) GL_ENUM(0x0302,GL_SRC_ALPHA) GL_ENUM(0x0303,GL_ONE_MINUS_SRC_ALPHA) GL_ENUM(0x0304,GL_DST_ALPHA) GL_ENUM(0x0305,GL_ONE_MINUS_DST_ALPHA) GL_ENUM(0x0306,GL_DST_COLOR) GL_ENUM(0x0307,GL_ONE_MINUS_DST_COLOR) GL_ENUM(0x0308,GL_SRC_ALPHA_SATURATE) GL_ENUM(0x3000,GL_CLIP_PLANE0) GL_ENUM(0x3001,GL_CLIP_PLANE1) GL_ENUM(0x3002,GL_CLIP_PLANE2) GL_ENUM(0x3003,GL_CLIP_PLANE3) GL_ENUM(0x3004,GL_CLIP_PLANE4) GL_ENUM(0x3005,GL_CLIP_PLANE5) GL_ENUM(0x0404,GL_FRONT) GL_ENUM(0x0405,GL_BACK) GL_ENUM(0x0408,GL_FRONT_AND_BACK) GL_ENUM(0x0B60,GL_FOG) GL_ENUM(0x0B50,GL_LIGHTING) GL_ENUM(0x0DE1,GL_TEXTURE_2D) GL_ENUM(0x0B44,GL_CULL_FACE) GL_ENUM(0x0BC0,GL_ALPHA_TEST) GL_ENUM(0x0BE2,GL_BLEND) GL_ENUM(0x0BF2,GL_COLOR_LOGIC_OP) GL_ENUM(0x0BD0,GL_DITHER) GL_ENUM(0x0B90,GL_STENCIL_TEST) GL_ENUM(0x0B71,GL_DEPTH_TEST) GL_ENUM(0x0B10,GL_POINT_SMOOTH) GL_ENUM(0x0B20,GL_LINE_SMOOTH) GL_ENUM(0x0C11,GL_SCISSOR_TEST) GL_ENUM(0x0B57,GL_COLOR_MATERIAL) GL_ENUM(0x0BA1,GL_NORMALIZE) GL_ENUM(0x803A,GL_RESCALE_NORMAL) GL_ENUM(0x8074,GL_VERTEX_ARRAY) GL_ENUM(0x8075,GL_NORMAL_ARRAY) GL_ENUM(0x8076,GL_COLOR_ARRAY) GL_ENUM(0x8078,GL_TEXTURE_COORD_ARRAY) GL_ENUM(0x809D,GL_MULTISAMPLE) GL_ENUM(0x809E,GL_SAMPLE_ALPHA_TO_COVERAGE) GL_ENUM(0x809F,GL_SAMPLE_ALPHA_TO_ONE) GL_ENUM(0x80A0,GL_SAMPLE_COVERAGE) GL_ENUM(0x0500,GL_INVALID_ENUM) GL_ENUM(0x0501,GL_INVALID_VALUE) GL_ENUM(0x0502,GL_INVALID_OPERATION) GL_ENUM(0x0503,GL_STACK_OVERFLOW) GL_ENUM(0x0504,GL_STACK_UNDERFLOW) GL_ENUM(0x0505,GL_OUT_OF_MEMORY) GL_ENUM(0x0800,GL_EXP) GL_ENUM(0x0801,GL_EXP2) GL_ENUM(0x0B62,GL_FOG_DENSITY) GL_ENUM(0x0B63,GL_FOG_START) GL_ENUM(0x0B64,GL_FOG_END) GL_ENUM(0x0B65,GL_FOG_MODE) GL_ENUM(0x0B66,GL_FOG_COLOR) GL_ENUM(0x0900,GL_CW) GL_ENUM(0x0901,GL_CCW) GL_ENUM(0x0B00,GL_CURRENT_COLOR) GL_ENUM(0x0B02,GL_CURRENT_NORMAL) GL_ENUM(0x0B03,GL_CURRENT_TEXTURE_COORDS) GL_ENUM(0x0B11,GL_POINT_SIZE) GL_ENUM(0x8126,GL_POINT_SIZE_MIN) GL_ENUM(0x8127,GL_POINT_SIZE_MAX) GL_ENUM(0x8128,GL_POINT_FADE_THRESHOLD_SIZE) GL_ENUM(0x8129,GL_POINT_DISTANCE_ATTENUATION) GL_ENUM(0x0B12,GL_SMOOTH_POINT_SIZE_RANGE) GL_ENUM(0x0B21,GL_LINE_WIDTH) GL_ENUM(0x0B22,GL_SMOOTH_LINE_WIDTH_RANGE) GL_ENUM(0x846D,GL_ALIASED_POINT_SIZE_RANGE) GL_ENUM(0x846E,GL_ALIASED_LINE_WIDTH_RANGE) GL_ENUM(0x0B45,GL_CULL_FACE_MODE) GL_ENUM(0x0B46,GL_FRONT_FACE) GL_ENUM(0x0B54,GL_SHADE_MODEL) GL_ENUM(0x0B70,GL_DEPTH_RANGE) GL_ENUM(0x0B72,GL_DEPTH_WRITEMASK) GL_ENUM(0x0B73,GL_DEPTH_CLEAR_VALUE) GL_ENUM(0x0B74,GL_DEPTH_FUNC) GL_ENUM(0x0B91,GL_STENCIL_CLEAR_VALUE) GL_ENUM(0x0B92,GL_STENCIL_FUNC) GL_ENUM(0x0B93,GL_STENCIL_VALUE_MASK) GL_ENUM(0x0B94,GL_STENCIL_FAIL) GL_ENUM(0x0B95,GL_STENCIL_PASS_DEPTH_FAIL) GL_ENUM(0x0B96,GL_STENCIL_PASS_DEPTH_PASS) GL_ENUM(0x0B97,GL_STENCIL_REF) GL_ENUM(0x0B98,GL_STENCIL_WRITEMASK) GL_ENUM(0x0BA0,GL_MATRIX_MODE) GL_ENUM(0x0BA2,GL_VIEWPORT) GL_ENUM(0x0BA3,GL_MODELVIEW_STACK_DEPTH) GL_ENUM(0x0BA4,GL_PROJECTION_STACK_DEPTH) GL_ENUM(0x0BA5,GL_TEXTURE_STACK_DEPTH) GL_ENUM(0x0BA6,GL_MODELVIEW_MATRIX) GL_ENUM(0x0BA7,GL_PROJECTION_MATRIX) GL_ENUM(0x0BA8,GL_TEXTURE_MATRIX) GL_ENUM(0x0BC1,GL_ALPHA_TEST_FUNC) GL_ENUM(0x0BC2,GL_ALPHA_TEST_REF) GL_ENUM(0x0BE0,GL_BLEND_DST) GL_ENUM(0x0BE1,GL_BLEND_SRC) GL_ENUM(0x0BF0,GL_LOGIC_OP_MODE) GL_ENUM(0x0C10,GL_SCISSOR_BOX) GL_ENUM(0x0C22,GL_COLOR_CLEAR_VALUE) GL_ENUM(0x0C23,GL_COLOR_WRITEMASK) GL_ENUM(0x0D31,GL_MAX_LIGHTS) GL_ENUM(0x0D32,GL_MAX_CLIP_PLANES) GL_ENUM(0x0D33,GL_MAX_TEXTURE_SIZE) GL_ENUM(0x0D36,GL_MAX_MODELVIEW_STACK_DEPTH) GL_ENUM(0x0D38,GL_MAX_PROJECTION_STACK_DEPTH) GL_ENUM(0x0D39,GL_MAX_TEXTURE_STACK_DEPTH) GL_ENUM(0x0D3A,GL_MAX_VIEWPORT_DIMS) GL_ENUM(0x84E2,GL_MAX_TEXTURE_UNITS) GL_ENUM(0x0D50,GL_SUBPIXEL_BITS) GL_ENUM(0x0D52,GL_RED_BITS) GL_ENUM(0x0D53,GL_GREEN_BITS) GL_ENUM(0x0D54,GL_BLUE_BITS) GL_ENUM(0x0D55,GL_ALPHA_BITS) GL_ENUM(0x0D56,GL_DEPTH_BITS) GL_ENUM(0x0D57,GL_STENCIL_BITS) GL_ENUM(0x2A00,GL_POLYGON_OFFSET_UNITS) GL_ENUM(0x8037,GL_POLYGON_OFFSET_FILL) GL_ENUM(0x8038,GL_POLYGON_OFFSET_FACTOR) GL_ENUM(0x8069,GL_TEXTURE_BINDING_2D) GL_ENUM(0x807A,GL_VERTEX_ARRAY_SIZE) GL_ENUM(0x807B,GL_VERTEX_ARRAY_TYPE) GL_ENUM(0x807C,GL_VERTEX_ARRAY_STRIDE) GL_ENUM(0x807E,GL_NORMAL_ARRAY_TYPE) GL_ENUM(0x807F,GL_NORMAL_ARRAY_STRIDE) GL_ENUM(0x8081,GL_COLOR_ARRAY_SIZE) GL_ENUM(0x8082,GL_COLOR_ARRAY_TYPE) GL_ENUM(0x8083,GL_COLOR_ARRAY_STRIDE) GL_ENUM(0x8088,GL_TEXTURE_COORD_ARRAY_SIZE) GL_ENUM(0x8089,GL_TEXTURE_COORD_ARRAY_TYPE) GL_ENUM(0x808A,GL_TEXTURE_COORD_ARRAY_STRIDE) GL_ENUM(0x808E,GL_VERTEX_ARRAY_POINTER) GL_ENUM(0x808F,GL_NORMAL_ARRAY_POINTER) GL_ENUM(0x8090,GL_COLOR_ARRAY_POINTER) GL_ENUM(0x8092,GL_TEXTURE_COORD_ARRAY_POINTER) GL_ENUM(0x80A8,GL_SAMPLE_BUFFERS) GL_ENUM(0x80A9,GL_SAMPLES) GL_ENUM(0x80AA,GL_SAMPLE_COVERAGE_VALUE) GL_ENUM(0x80AB,GL_SAMPLE_COVERAGE_INVERT) GL_ENUM(0x86A2,GL_NUM_COMPRESSED_TEXTURE_FORMATS) GL_ENUM(0x86A3,GL_COMPRESSED_TEXTURE_FORMATS) GL_ENUM(0x1100,GL_DONT_CARE) GL_ENUM(0x1101,GL_FASTEST) GL_ENUM(0x1102,GL_NICEST) GL_ENUM(0x0C50,GL_PERSPECTIVE_CORRECTION_HINT) GL_ENUM(0x0C51,GL_POINT_SMOOTH_HINT) GL_ENUM(0x0C52,GL_LINE_SMOOTH_HINT) GL_ENUM(0x0C54,GL_FOG_HINT) GL_ENUM(0x8192,GL_GENERATE_MIPMAP_HINT) GL_ENUM(0x0B53,GL_LIGHT_MODEL_AMBIENT) GL_ENUM(0x0B52,GL_LIGHT_MODEL_TWO_SIDE) GL_ENUM(0x1200,GL_AMBIENT) GL_ENUM(0x1201,GL_DIFFUSE) GL_ENUM(0x1202,GL_SPECULAR) GL_ENUM(0x1203,GL_POSITION) GL_ENUM(0x1204,GL_SPOT_DIRECTION) GL_ENUM(0x1205,GL_SPOT_EXPONENT) GL_ENUM(0x1206,GL_SPOT_CUTOFF) GL_ENUM(0x1207,GL_CONSTANT_ATTENUATION) GL_ENUM(0x1208,GL_LINEAR_ATTENUATION) GL_ENUM(0x1209,GL_QUADRATIC_ATTENUATION) GL_ENUM(0x1400,GL_BYTE) GL_ENUM(0x1401,GL_UNSIGNED_BYTE) GL_ENUM(0x1402,GL_SHORT) GL_ENUM(0x1403,GL_UNSIGNED_SHORT) GL_ENUM(0x1406,GL_FLOAT) GL_ENUM(0x140C,GL_FIXED) GL_ENUM(0x1500,GL_CLEAR) GL_ENUM(0x1501,GL_AND) GL_ENUM(0x1502,GL_AND_REVERSE) GL_ENUM(0x1503,GL_COPY) GL_ENUM(0x1504,GL_AND_INVERTED) GL_ENUM(0x1505,GL_NOOP) GL_ENUM(0x1506,GL_XOR) GL_ENUM(0x1507,GL_OR) GL_ENUM(0x1508,GL_NOR) GL_ENUM(0x1509,GL_EQUIV) GL_ENUM(0x150A,GL_INVERT) GL_ENUM(0x150B,GL_OR_REVERSE) GL_ENUM(0x150C,GL_COPY_INVERTED) GL_ENUM(0x150D,GL_OR_INVERTED) GL_ENUM(0x150E,GL_NAND) GL_ENUM(0x150F,GL_SET) GL_ENUM(0x1600,GL_EMISSION) GL_ENUM(0x1601,GL_SHININESS) GL_ENUM(0x1602,GL_AMBIENT_AND_DIFFUSE) GL_ENUM(0x1700,GL_MODELVIEW) GL_ENUM(0x1701,GL_PROJECTION) GL_ENUM(0x1702,GL_TEXTURE) GL_ENUM(0x1906,GL_ALPHA) GL_ENUM(0x1907,GL_RGB) GL_ENUM(0x1908,GL_RGBA) GL_ENUM(0x1909,GL_LUMINANCE) GL_ENUM(0x190A,GL_LUMINANCE_ALPHA) GL_ENUM(0x0CF5,GL_UNPACK_ALIGNMENT) GL_ENUM(0x0D05,GL_PACK_ALIGNMENT) GL_ENUM(0x8033,GL_UNSIGNED_SHORT_4_4_4_4) GL_ENUM(0x8034,GL_UNSIGNED_SHORT_5_5_5_1) GL_ENUM(0x8363,GL_UNSIGNED_SHORT_5_6_5) GL_ENUM(0x1D00,GL_FLAT) GL_ENUM(0x1D01,GL_SMOOTH) GL_ENUM(0x1E00,GL_KEEP) GL_ENUM(0x1E01,GL_REPLACE) GL_ENUM(0x1E02,GL_INCR) GL_ENUM(0x1E03,GL_DECR) GL_ENUM(0x1F00,GL_VENDOR) GL_ENUM(0x1F01,GL_RENDERER) GL_ENUM(0x1F02,GL_VERSION) GL_ENUM(0x1F03,GL_EXTENSIONS) GL_ENUM(0x2100,GL_MODULATE) GL_ENUM(0x2101,GL_DECAL) GL_ENUM(0x0104,GL_ADD) GL_ENUM(0x2200,GL_TEXTURE_ENV_MODE) GL_ENUM(0x2201,GL_TEXTURE_ENV_COLOR) GL_ENUM(0x2300,GL_TEXTURE_ENV) GL_ENUM(0x2600,GL_NEAREST) GL_ENUM(0x2601,GL_LINEAR) GL_ENUM(0x2700,GL_NEAREST_MIPMAP_NEAREST) GL_ENUM(0x2701,GL_LINEAR_MIPMAP_NEAREST) GL_ENUM(0x2702,GL_NEAREST_MIPMAP_LINEAR) GL_ENUM(0x2703,GL_LINEAR_MIPMAP_LINEAR) GL_ENUM(0x2800,GL_TEXTURE_MAG_FILTER) GL_ENUM(0x2801,GL_TEXTURE_MIN_FILTER) GL_ENUM(0x2802,GL_TEXTURE_WRAP_S) GL_ENUM(0x2803,GL_TEXTURE_WRAP_T) GL_ENUM(0x8191,GL_GENERATE_MIPMAP) GL_ENUM(0x84C0,GL_TEXTURE0) GL_ENUM(0x84C1,GL_TEXTURE1) GL_ENUM(0x84C2,GL_TEXTURE2) GL_ENUM(0x84C3,GL_TEXTURE3) GL_ENUM(0x84C4,GL_TEXTURE4) GL_ENUM(0x84C5,GL_TEXTURE5) GL_ENUM(0x84C6,GL_TEXTURE6) GL_ENUM(0x84C7,GL_TEXTURE7) GL_ENUM(0x84C8,GL_TEXTURE8) GL_ENUM(0x84C9,GL_TEXTURE9) GL_ENUM(0x84CA,GL_TEXTURE10) GL_ENUM(0x84CB,GL_TEXTURE11) GL_ENUM(0x84CC,GL_TEXTURE12) GL_ENUM(0x84CD,GL_TEXTURE13) GL_ENUM(0x84CE,GL_TEXTURE14) GL_ENUM(0x84CF,GL_TEXTURE15) GL_ENUM(0x84D0,GL_TEXTURE16) GL_ENUM(0x84D1,GL_TEXTURE17) GL_ENUM(0x84D2,GL_TEXTURE18) GL_ENUM(0x84D3,GL_TEXTURE19) GL_ENUM(0x84D4,GL_TEXTURE20) GL_ENUM(0x84D5,GL_TEXTURE21) GL_ENUM(0x84D6,GL_TEXTURE22) GL_ENUM(0x84D7,GL_TEXTURE23) GL_ENUM(0x84D8,GL_TEXTURE24) GL_ENUM(0x84D9,GL_TEXTURE25) GL_ENUM(0x84DA,GL_TEXTURE26) GL_ENUM(0x84DB,GL_TEXTURE27) GL_ENUM(0x84DC,GL_TEXTURE28) GL_ENUM(0x84DD,GL_TEXTURE29) GL_ENUM(0x84DE,GL_TEXTURE30) GL_ENUM(0x84DF,GL_TEXTURE31) GL_ENUM(0x84E0,GL_ACTIVE_TEXTURE) GL_ENUM(0x84E1,GL_CLIENT_ACTIVE_TEXTURE) GL_ENUM(0x2901,GL_REPEAT) GL_ENUM(0x812F,GL_CLAMP_TO_EDGE) GL_ENUM(0x4000,GL_LIGHT0) GL_ENUM(0x4001,GL_LIGHT1) GL_ENUM(0x4002,GL_LIGHT2) GL_ENUM(0x4003,GL_LIGHT3) GL_ENUM(0x4004,GL_LIGHT4) GL_ENUM(0x4005,GL_LIGHT5) GL_ENUM(0x4006,GL_LIGHT6) GL_ENUM(0x4007,GL_LIGHT7) GL_ENUM(0x8892,GL_ARRAY_BUFFER) GL_ENUM(0x8893,GL_ELEMENT_ARRAY_BUFFER) GL_ENUM(0x8894,GL_ARRAY_BUFFER_BINDING) GL_ENUM(0x8895,GL_ELEMENT_ARRAY_BUFFER_BINDING) GL_ENUM(0x8896,GL_VERTEX_ARRAY_BUFFER_BINDING) GL_ENUM(0x8897,GL_NORMAL_ARRAY_BUFFER_BINDING) GL_ENUM(0x8898,GL_COLOR_ARRAY_BUFFER_BINDING) GL_ENUM(0x889A,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) GL_ENUM(0x88E4,GL_STATIC_DRAW) GL_ENUM(0x88E8,GL_DYNAMIC_DRAW) GL_ENUM(0x8764,GL_BUFFER_SIZE) GL_ENUM(0x8765,GL_BUFFER_USAGE) GL_ENUM(0x84E7,GL_SUBTRACT) GL_ENUM(0x8570,GL_COMBINE) GL_ENUM(0x8571,GL_COMBINE_RGB) GL_ENUM(0x8572,GL_COMBINE_ALPHA) GL_ENUM(0x8573,GL_RGB_SCALE) GL_ENUM(0x8574,GL_ADD_SIGNED) GL_ENUM(0x8575,GL_INTERPOLATE) GL_ENUM(0x8576,GL_CONSTANT) GL_ENUM(0x8577,GL_PRIMARY_COLOR) GL_ENUM(0x8578,GL_PREVIOUS) GL_ENUM(0x8590,GL_OPERAND0_RGB) GL_ENUM(0x8591,GL_OPERAND1_RGB) GL_ENUM(0x8592,GL_OPERAND2_RGB) GL_ENUM(0x8598,GL_OPERAND0_ALPHA) GL_ENUM(0x8599,GL_OPERAND1_ALPHA) GL_ENUM(0x859A,GL_OPERAND2_ALPHA) GL_ENUM(0x0D1C,GL_ALPHA_SCALE) GL_ENUM(0x8580,GL_SRC0_RGB) GL_ENUM(0x8581,GL_SRC1_RGB) GL_ENUM(0x8582,GL_SRC2_RGB) GL_ENUM(0x8588,GL_SRC0_ALPHA) GL_ENUM(0x8589,GL_SRC1_ALPHA) GL_ENUM(0x858A,GL_SRC2_ALPHA) GL_ENUM(0x86AE,GL_DOT3_RGB) GL_ENUM(0x86AF,GL_DOT3_RGBA) GL_ENUM(0x8006,GL_FUNC_ADD) GL_ENUM(0x8009,GL_BLEND_EQUATION) GL_ENUM(0x883D,GL_BLEND_EQUATION_ALPHA) GL_ENUM(0x800A,GL_FUNC_SUBTRACT) GL_ENUM(0x800B,GL_FUNC_REVERSE_SUBTRACT) GL_ENUM(0x80C8,GL_BLEND_DST_RGB) GL_ENUM(0x80C9,GL_BLEND_SRC_RGB) GL_ENUM(0x80CA,GL_BLEND_DST_ALPHA) GL_ENUM(0x80CB,GL_BLEND_SRC_ALPHA) GL_ENUM(0x8001,GL_CONSTANT_COLOR) GL_ENUM(0x8002,GL_ONE_MINUS_CONSTANT_COLOR) GL_ENUM(0x8003,GL_CONSTANT_ALPHA) GL_ENUM(0x8004,GL_ONE_MINUS_CONSTANT_ALPHA) GL_ENUM(0x8005,GL_BLEND_COLOR) GL_ENUM(0x88E0,GL_STREAM_DRAW) GL_ENUM(0x8626,GL_CURRENT_VERTEX_ATTRIB) GL_ENUM(0x8800,GL_STENCIL_BACK_FUNC) GL_ENUM(0x8801,GL_STENCIL_BACK_FAIL) GL_ENUM(0x8802,GL_STENCIL_BACK_PASS_DEPTH_FAIL) GL_ENUM(0x8803,GL_STENCIL_BACK_PASS_DEPTH_PASS) GL_ENUM(0x8CA3,GL_STENCIL_BACK_REF) GL_ENUM(0x8CA4,GL_STENCIL_BACK_VALUE_MASK) GL_ENUM(0x8CA5,GL_STENCIL_BACK_WRITEMASK) GL_ENUM(0x1404,GL_INT) GL_ENUM(0x1405,GL_UNSIGNED_INT) GL_ENUM(0x1902,GL_DEPTH_COMPONENT) GL_ENUM(0x8B30,GL_FRAGMENT_SHADER) GL_ENUM(0x8B31,GL_VERTEX_SHADER) GL_ENUM(0x8869,GL_MAX_VERTEX_ATTRIBS) GL_ENUM(0x8DFB,GL_MAX_VERTEX_UNIFORM_VECTORS) GL_ENUM(0x8DFC,GL_MAX_VARYING_VECTORS) GL_ENUM(0x8B4D,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) GL_ENUM(0x8B4C,GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS) GL_ENUM(0x8872,GL_MAX_TEXTURE_IMAGE_UNITS) GL_ENUM(0x8DFD,GL_MAX_FRAGMENT_UNIFORM_VECTORS) GL_ENUM(0x8B4F,GL_SHADER_TYPE) GL_ENUM(0x8B80,GL_DELETE_STATUS) GL_ENUM(0x8B82,GL_LINK_STATUS) GL_ENUM(0x8B83,GL_VALIDATE_STATUS) GL_ENUM(0x8B85,GL_ATTACHED_SHADERS) GL_ENUM(0x8B86,GL_ACTIVE_UNIFORMS) GL_ENUM(0x8B87,GL_ACTIVE_UNIFORM_MAX_LENGTH) GL_ENUM(0x8B89,GL_ACTIVE_ATTRIBUTES) GL_ENUM(0x8B8A,GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) GL_ENUM(0x8B8C,GL_SHADING_LANGUAGE_VERSION) GL_ENUM(0x8B8D,GL_CURRENT_PROGRAM) GL_ENUM(0x8507,GL_INCR_WRAP) GL_ENUM(0x8508,GL_DECR_WRAP) GL_ENUM(0x8513,GL_TEXTURE_CUBE_MAP) GL_ENUM(0x8514,GL_TEXTURE_BINDING_CUBE_MAP) GL_ENUM(0x8515,GL_TEXTURE_CUBE_MAP_POSITIVE_X) GL_ENUM(0x8516,GL_TEXTURE_CUBE_MAP_NEGATIVE_X) GL_ENUM(0x8517,GL_TEXTURE_CUBE_MAP_POSITIVE_Y) GL_ENUM(0x8518,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) GL_ENUM(0x8519,GL_TEXTURE_CUBE_MAP_POSITIVE_Z) GL_ENUM(0x851A,GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) GL_ENUM(0x851C,GL_MAX_CUBE_MAP_TEXTURE_SIZE) GL_ENUM(0x8370,GL_MIRRORED_REPEAT) GL_ENUM(0x8B50,GL_FLOAT_VEC2) GL_ENUM(0x8B51,GL_FLOAT_VEC3) GL_ENUM(0x8B52,GL_FLOAT_VEC4) GL_ENUM(0x8B53,GL_INT_VEC2) GL_ENUM(0x8B54,GL_INT_VEC3) GL_ENUM(0x8B55,GL_INT_VEC4) GL_ENUM(0x8B56,GL_BOOL) GL_ENUM(0x8B57,GL_BOOL_VEC2) GL_ENUM(0x8B58,GL_BOOL_VEC3) GL_ENUM(0x8B59,GL_BOOL_VEC4) GL_ENUM(0x8B5A,GL_FLOAT_MAT2) GL_ENUM(0x8B5B,GL_FLOAT_MAT3) GL_ENUM(0x8B5C,GL_FLOAT_MAT4) GL_ENUM(0x8B5E,GL_SAMPLER_2D) GL_ENUM(0x8B60,GL_SAMPLER_CUBE) GL_ENUM(0x8622,GL_VERTEX_ATTRIB_ARRAY_ENABLED) GL_ENUM(0x8623,GL_VERTEX_ATTRIB_ARRAY_SIZE) GL_ENUM(0x8624,GL_VERTEX_ATTRIB_ARRAY_STRIDE) GL_ENUM(0x8625,GL_VERTEX_ATTRIB_ARRAY_TYPE) GL_ENUM(0x886A,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED) GL_ENUM(0x8645,GL_VERTEX_ATTRIB_ARRAY_POINTER) GL_ENUM(0x889F,GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) GL_ENUM(0x8B9A,GL_IMPLEMENTATION_COLOR_READ_TYPE) GL_ENUM(0x8B9B,GL_IMPLEMENTATION_COLOR_READ_FORMAT) GL_ENUM(0x8B81,GL_COMPILE_STATUS) GL_ENUM(0x8B84,GL_INFO_LOG_LENGTH) GL_ENUM(0x8B88,GL_SHADER_SOURCE_LENGTH) GL_ENUM(0x8DFA,GL_SHADER_COMPILER) GL_ENUM(0x8DF8,GL_SHADER_BINARY_FORMATS) GL_ENUM(0x8DF9,GL_NUM_SHADER_BINARY_FORMATS) GL_ENUM(0x8DF0,GL_LOW_FLOAT) GL_ENUM(0x8DF1,GL_MEDIUM_FLOAT) GL_ENUM(0x8DF2,GL_HIGH_FLOAT) GL_ENUM(0x8DF3,GL_LOW_INT) GL_ENUM(0x8DF4,GL_MEDIUM_INT) GL_ENUM(0x8DF5,GL_HIGH_INT) GL_ENUM(0x8D40,GL_FRAMEBUFFER) GL_ENUM(0x8D41,GL_RENDERBUFFER) GL_ENUM(0x8056,GL_RGBA4) GL_ENUM(0x8057,GL_RGB5_A1) GL_ENUM(0x8D62,GL_RGB565) GL_ENUM(0x81A5,GL_DEPTH_COMPONENT16) GL_ENUM(0x8D48,GL_STENCIL_INDEX8) GL_ENUM(0x8D42,GL_RENDERBUFFER_WIDTH) GL_ENUM(0x8D43,GL_RENDERBUFFER_HEIGHT) GL_ENUM(0x8D44,GL_RENDERBUFFER_INTERNAL_FORMAT) GL_ENUM(0x8D50,GL_RENDERBUFFER_RED_SIZE) GL_ENUM(0x8D51,GL_RENDERBUFFER_GREEN_SIZE) GL_ENUM(0x8D52,GL_RENDERBUFFER_BLUE_SIZE) GL_ENUM(0x8D53,GL_RENDERBUFFER_ALPHA_SIZE) GL_ENUM(0x8D54,GL_RENDERBUFFER_DEPTH_SIZE) GL_ENUM(0x8D55,GL_RENDERBUFFER_STENCIL_SIZE) GL_ENUM(0x8CD0,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) GL_ENUM(0x8CD1,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) GL_ENUM(0x8CD2,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL) GL_ENUM(0x8CD3,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE) GL_ENUM(0x8CE0,GL_COLOR_ATTACHMENT0) GL_ENUM(0x8D00,GL_DEPTH_ATTACHMENT) GL_ENUM(0x8D20,GL_STENCIL_ATTACHMENT) GL_ENUM(0x8CD5,GL_FRAMEBUFFER_COMPLETE) GL_ENUM(0x8CD6,GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) GL_ENUM(0x8CD7,GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) GL_ENUM(0x8CD9,GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) GL_ENUM(0x8CDD,GL_FRAMEBUFFER_UNSUPPORTED) GL_ENUM(0x8CA6,GL_FRAMEBUFFER_BINDING) GL_ENUM(0x8CA7,GL_RENDERBUFFER_BINDING) GL_ENUM(0x84E8,GL_MAX_RENDERBUFFER_SIZE) GL_ENUM(0x0506,GL_INVALID_FRAMEBUFFER_OPERATION) GL_ENUM(0x0C02,GL_READ_BUFFER) GL_ENUM(0x0CF2,GL_UNPACK_ROW_LENGTH) GL_ENUM(0x0CF3,GL_UNPACK_SKIP_ROWS) GL_ENUM(0x0CF4,GL_UNPACK_SKIP_PIXELS) GL_ENUM(0x0D02,GL_PACK_ROW_LENGTH) GL_ENUM(0x0D03,GL_PACK_SKIP_ROWS) GL_ENUM(0x0D04,GL_PACK_SKIP_PIXELS) GL_ENUM(0x1800,GL_COLOR) GL_ENUM(0x1801,GL_DEPTH) GL_ENUM(0x1802,GL_STENCIL) GL_ENUM(0x1903,GL_RED) GL_ENUM(0x8051,GL_RGB8) GL_ENUM(0x8058,GL_RGBA8) GL_ENUM(0x8059,GL_RGB10_A2) GL_ENUM(0x806A,GL_TEXTURE_BINDING_3D) GL_ENUM(0x806D,GL_UNPACK_SKIP_IMAGES) GL_ENUM(0x806E,GL_UNPACK_IMAGE_HEIGHT) GL_ENUM(0x806F,GL_TEXTURE_3D) GL_ENUM(0x8072,GL_TEXTURE_WRAP_R) GL_ENUM(0x8073,GL_MAX_3D_TEXTURE_SIZE) GL_ENUM(0x8368,GL_UNSIGNED_INT_2_10_10_10_REV) GL_ENUM(0x80E8,GL_MAX_ELEMENTS_VERTICES) GL_ENUM(0x80E9,GL_MAX_ELEMENTS_INDICES) GL_ENUM(0x813A,GL_TEXTURE_MIN_LOD) GL_ENUM(0x813B,GL_TEXTURE_MAX_LOD) GL_ENUM(0x813C,GL_TEXTURE_BASE_LEVEL) GL_ENUM(0x813D,GL_TEXTURE_MAX_LEVEL) GL_ENUM(0x8007,GL_MIN) GL_ENUM(0x8008,GL_MAX) GL_ENUM(0x81A6,GL_DEPTH_COMPONENT24) GL_ENUM(0x84FD,GL_MAX_TEXTURE_LOD_BIAS) GL_ENUM(0x884C,GL_TEXTURE_COMPARE_MODE) GL_ENUM(0x884D,GL_TEXTURE_COMPARE_FUNC) GL_ENUM(0x8865,GL_CURRENT_QUERY) GL_ENUM(0x8866,GL_QUERY_RESULT) GL_ENUM(0x8867,GL_QUERY_RESULT_AVAILABLE) GL_ENUM(0x88BC,GL_BUFFER_MAPPED) GL_ENUM(0x88BD,GL_BUFFER_MAP_POINTER) GL_ENUM(0x88E1,GL_STREAM_READ) GL_ENUM(0x88E2,GL_STREAM_COPY) GL_ENUM(0x88E5,GL_STATIC_READ) GL_ENUM(0x88E6,GL_STATIC_COPY) GL_ENUM(0x88E9,GL_DYNAMIC_READ) GL_ENUM(0x88EA,GL_DYNAMIC_COPY) GL_ENUM(0x8824,GL_MAX_DRAW_BUFFERS) GL_ENUM(0x8825,GL_DRAW_BUFFER0) GL_ENUM(0x8826,GL_DRAW_BUFFER1) GL_ENUM(0x8827,GL_DRAW_BUFFER2) GL_ENUM(0x8828,GL_DRAW_BUFFER3) GL_ENUM(0x8829,GL_DRAW_BUFFER4) GL_ENUM(0x882A,GL_DRAW_BUFFER5) GL_ENUM(0x882B,GL_DRAW_BUFFER6) GL_ENUM(0x882C,GL_DRAW_BUFFER7) GL_ENUM(0x882D,GL_DRAW_BUFFER8) GL_ENUM(0x882E,GL_DRAW_BUFFER9) GL_ENUM(0x882F,GL_DRAW_BUFFER10) GL_ENUM(0x8830,GL_DRAW_BUFFER11) GL_ENUM(0x8831,GL_DRAW_BUFFER12) GL_ENUM(0x8832,GL_DRAW_BUFFER13) GL_ENUM(0x8833,GL_DRAW_BUFFER14) GL_ENUM(0x8834,GL_DRAW_BUFFER15) GL_ENUM(0x8B49,GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) GL_ENUM(0x8B4A,GL_MAX_VERTEX_UNIFORM_COMPONENTS) GL_ENUM(0x8B5F,GL_SAMPLER_3D) GL_ENUM(0x8B62,GL_SAMPLER_2D_SHADOW) GL_ENUM(0x8B8B,GL_FRAGMENT_SHADER_DERIVATIVE_HINT) GL_ENUM(0x88EB,GL_PIXEL_PACK_BUFFER) GL_ENUM(0x88EC,GL_PIXEL_UNPACK_BUFFER) GL_ENUM(0x88ED,GL_PIXEL_PACK_BUFFER_BINDING) GL_ENUM(0x88EF,GL_PIXEL_UNPACK_BUFFER_BINDING) GL_ENUM(0x8B65,GL_FLOAT_MAT2x3) GL_ENUM(0x8B66,GL_FLOAT_MAT2x4) GL_ENUM(0x8B67,GL_FLOAT_MAT3x2) GL_ENUM(0x8B68,GL_FLOAT_MAT3x4) GL_ENUM(0x8B69,GL_FLOAT_MAT4x2) GL_ENUM(0x8B6A,GL_FLOAT_MAT4x3) GL_ENUM(0x8C40,GL_SRGB) GL_ENUM(0x8C41,GL_SRGB8) GL_ENUM(0x8C43,GL_SRGB8_ALPHA8) GL_ENUM(0x884E,GL_COMPARE_REF_TO_TEXTURE) GL_ENUM(0x821B,GL_MAJOR_VERSION) GL_ENUM(0x821C,GL_MINOR_VERSION) GL_ENUM(0x821D,GL_NUM_EXTENSIONS) GL_ENUM(0x8814,GL_RGBA32F) GL_ENUM(0x8815,GL_RGB32F) GL_ENUM(0x881A,GL_RGBA16F) GL_ENUM(0x881B,GL_RGB16F) GL_ENUM(0x88FD,GL_VERTEX_ATTRIB_ARRAY_INTEGER) GL_ENUM(0x88FF,GL_MAX_ARRAY_TEXTURE_LAYERS) GL_ENUM(0x8904,GL_MIN_PROGRAM_TEXEL_OFFSET) GL_ENUM(0x8905,GL_MAX_PROGRAM_TEXEL_OFFSET) GL_ENUM(0x8B4B,GL_MAX_VARYING_COMPONENTS) GL_ENUM(0x8C1A,GL_TEXTURE_2D_ARRAY) GL_ENUM(0x8C1D,GL_TEXTURE_BINDING_2D_ARRAY) GL_ENUM(0x8C3A,GL_R11F_G11F_B10F) GL_ENUM(0x8C3B,GL_UNSIGNED_INT_10F_11F_11F_REV) GL_ENUM(0x8C3D,GL_RGB9_E5) GL_ENUM(0x8C3E,GL_UNSIGNED_INT_5_9_9_9_REV) GL_ENUM(0x8C76,GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH) GL_ENUM(0x8C7F,GL_TRANSFORM_FEEDBACK_BUFFER_MODE) GL_ENUM(0x8C80,GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS) GL_ENUM(0x8C83,GL_TRANSFORM_FEEDBACK_VARYINGS) GL_ENUM(0x8C84,GL_TRANSFORM_FEEDBACK_BUFFER_START) GL_ENUM(0x8C85,GL_TRANSFORM_FEEDBACK_BUFFER_SIZE) GL_ENUM(0x8C88,GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) GL_ENUM(0x8C89,GL_RASTERIZER_DISCARD) GL_ENUM(0x8C8A,GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) GL_ENUM(0x8C8B,GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS) GL_ENUM(0x8C8C,GL_INTERLEAVED_ATTRIBS) GL_ENUM(0x8C8D,GL_SEPARATE_ATTRIBS) GL_ENUM(0x8C8E,GL_TRANSFORM_FEEDBACK_BUFFER) GL_ENUM(0x8C8F,GL_TRANSFORM_FEEDBACK_BUFFER_BINDING) GL_ENUM(0x8D70,GL_RGBA32UI) GL_ENUM(0x8D71,GL_RGB32UI) GL_ENUM(0x8D76,GL_RGBA16UI) GL_ENUM(0x8D77,GL_RGB16UI) GL_ENUM(0x8D7C,GL_RGBA8UI) GL_ENUM(0x8D7D,GL_RGB8UI) GL_ENUM(0x8D82,GL_RGBA32I) GL_ENUM(0x8D83,GL_RGB32I) GL_ENUM(0x8D88,GL_RGBA16I) GL_ENUM(0x8D89,GL_RGB16I) GL_ENUM(0x8D8E,GL_RGBA8I) GL_ENUM(0x8D8F,GL_RGB8I) GL_ENUM(0x8D94,GL_RED_INTEGER) GL_ENUM(0x8D98,GL_RGB_INTEGER) GL_ENUM(0x8D99,GL_RGBA_INTEGER) GL_ENUM(0x8DC1,GL_SAMPLER_2D_ARRAY) GL_ENUM(0x8DC4,GL_SAMPLER_2D_ARRAY_SHADOW) GL_ENUM(0x8DC5,GL_SAMPLER_CUBE_SHADOW) GL_ENUM(0x8DC6,GL_UNSIGNED_INT_VEC2) GL_ENUM(0x8DC7,GL_UNSIGNED_INT_VEC3) GL_ENUM(0x8DC8,GL_UNSIGNED_INT_VEC4) GL_ENUM(0x8DCA,GL_INT_SAMPLER_2D) GL_ENUM(0x8DCB,GL_INT_SAMPLER_3D) GL_ENUM(0x8DCC,GL_INT_SAMPLER_CUBE) GL_ENUM(0x8DCF,GL_INT_SAMPLER_2D_ARRAY) GL_ENUM(0x8DD2,GL_UNSIGNED_INT_SAMPLER_2D) GL_ENUM(0x8DD3,GL_UNSIGNED_INT_SAMPLER_3D) GL_ENUM(0x8DD4,GL_UNSIGNED_INT_SAMPLER_CUBE) GL_ENUM(0x8DD7,GL_UNSIGNED_INT_SAMPLER_2D_ARRAY) GL_ENUM(0x911F,GL_BUFFER_ACCESS_FLAGS) GL_ENUM(0x9120,GL_BUFFER_MAP_LENGTH) GL_ENUM(0x9121,GL_BUFFER_MAP_OFFSET) GL_ENUM(0x8CAC,GL_DEPTH_COMPONENT32F) GL_ENUM(0x8CAD,GL_DEPTH32F_STENCIL8) GL_ENUM(0x8DAD,GL_FLOAT_32_UNSIGNED_INT_24_8_REV) GL_ENUM(0x8210,GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING) GL_ENUM(0x8211,GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) GL_ENUM(0x8212,GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE) GL_ENUM(0x8213,GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE) GL_ENUM(0x8214,GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE) GL_ENUM(0x8215,GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE) GL_ENUM(0x8216,GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE) GL_ENUM(0x8217,GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE) GL_ENUM(0x8218,GL_FRAMEBUFFER_DEFAULT) GL_ENUM(0x8219,GL_FRAMEBUFFER_UNDEFINED) GL_ENUM(0x821A,GL_DEPTH_STENCIL_ATTACHMENT) GL_ENUM(0x84F9,GL_DEPTH_STENCIL) GL_ENUM(0x84FA,GL_UNSIGNED_INT_24_8) GL_ENUM(0x88F0,GL_DEPTH24_STENCIL8) GL_ENUM(0x8C17,GL_UNSIGNED_NORMALIZED) GL_ENUM(0x8CA8,GL_READ_FRAMEBUFFER) GL_ENUM(0x8CA9,GL_DRAW_FRAMEBUFFER) GL_ENUM(0x8CAA,GL_READ_FRAMEBUFFER_BINDING) GL_ENUM(0x8CAB,GL_RENDERBUFFER_SAMPLES) GL_ENUM(0x8CD4,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER) GL_ENUM(0x8CDF,GL_MAX_COLOR_ATTACHMENTS) GL_ENUM(0x8CE1,GL_COLOR_ATTACHMENT1) GL_ENUM(0x8CE2,GL_COLOR_ATTACHMENT2) GL_ENUM(0x8CE3,GL_COLOR_ATTACHMENT3) GL_ENUM(0x8CE4,GL_COLOR_ATTACHMENT4) GL_ENUM(0x8CE5,GL_COLOR_ATTACHMENT5) GL_ENUM(0x8CE6,GL_COLOR_ATTACHMENT6) GL_ENUM(0x8CE7,GL_COLOR_ATTACHMENT7) GL_ENUM(0x8CE8,GL_COLOR_ATTACHMENT8) GL_ENUM(0x8CE9,GL_COLOR_ATTACHMENT9) GL_ENUM(0x8CEA,GL_COLOR_ATTACHMENT10) GL_ENUM(0x8CEB,GL_COLOR_ATTACHMENT11) GL_ENUM(0x8CEC,GL_COLOR_ATTACHMENT12) GL_ENUM(0x8CED,GL_COLOR_ATTACHMENT13) GL_ENUM(0x8CEE,GL_COLOR_ATTACHMENT14) GL_ENUM(0x8CEF,GL_COLOR_ATTACHMENT15) GL_ENUM(0x8CF0,GL_COLOR_ATTACHMENT16) GL_ENUM(0x8CF1,GL_COLOR_ATTACHMENT17) GL_ENUM(0x8CF2,GL_COLOR_ATTACHMENT18) GL_ENUM(0x8CF3,GL_COLOR_ATTACHMENT19) GL_ENUM(0x8CF4,GL_COLOR_ATTACHMENT20) GL_ENUM(0x8CF5,GL_COLOR_ATTACHMENT21) GL_ENUM(0x8CF6,GL_COLOR_ATTACHMENT22) GL_ENUM(0x8CF7,GL_COLOR_ATTACHMENT23) GL_ENUM(0x8CF8,GL_COLOR_ATTACHMENT24) GL_ENUM(0x8CF9,GL_COLOR_ATTACHMENT25) GL_ENUM(0x8CFA,GL_COLOR_ATTACHMENT26) GL_ENUM(0x8CFB,GL_COLOR_ATTACHMENT27) GL_ENUM(0x8CFC,GL_COLOR_ATTACHMENT28) GL_ENUM(0x8CFD,GL_COLOR_ATTACHMENT29) GL_ENUM(0x8CFE,GL_COLOR_ATTACHMENT30) GL_ENUM(0x8CFF,GL_COLOR_ATTACHMENT31) GL_ENUM(0x8D56,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) GL_ENUM(0x8D57,GL_MAX_SAMPLES) GL_ENUM(0x140B,GL_HALF_FLOAT) GL_ENUM(0x8227,GL_RG) GL_ENUM(0x8228,GL_RG_INTEGER) GL_ENUM(0x8229,GL_R8) GL_ENUM(0x822B,GL_RG8) GL_ENUM(0x822D,GL_R16F) GL_ENUM(0x822E,GL_R32F) GL_ENUM(0x822F,GL_RG16F) GL_ENUM(0x8230,GL_RG32F) GL_ENUM(0x8231,GL_R8I) GL_ENUM(0x8232,GL_R8UI) GL_ENUM(0x8233,GL_R16I) GL_ENUM(0x8234,GL_R16UI) GL_ENUM(0x8235,GL_R32I) GL_ENUM(0x8236,GL_R32UI) GL_ENUM(0x8237,GL_RG8I) GL_ENUM(0x8238,GL_RG8UI) GL_ENUM(0x8239,GL_RG16I) GL_ENUM(0x823A,GL_RG16UI) GL_ENUM(0x823B,GL_RG32I) GL_ENUM(0x823C,GL_RG32UI) GL_ENUM(0x85B5,GL_VERTEX_ARRAY_BINDING) GL_ENUM(0x8F94,GL_R8_SNORM) GL_ENUM(0x8F95,GL_RG8_SNORM) GL_ENUM(0x8F96,GL_RGB8_SNORM) GL_ENUM(0x8F97,GL_RGBA8_SNORM) GL_ENUM(0x8F9C,GL_SIGNED_NORMALIZED) GL_ENUM(0x8D69,GL_PRIMITIVE_RESTART_FIXED_INDEX) GL_ENUM(0x8F36,GL_COPY_READ_BUFFER) GL_ENUM(0x8F37,GL_COPY_WRITE_BUFFER) GL_ENUM(0x8A11,GL_UNIFORM_BUFFER) GL_ENUM(0x8A28,GL_UNIFORM_BUFFER_BINDING) GL_ENUM(0x8A29,GL_UNIFORM_BUFFER_START) GL_ENUM(0x8A2A,GL_UNIFORM_BUFFER_SIZE) GL_ENUM(0x8A2B,GL_MAX_VERTEX_UNIFORM_BLOCKS) GL_ENUM(0x8A2D,GL_MAX_FRAGMENT_UNIFORM_BLOCKS) GL_ENUM(0x8A2E,GL_MAX_COMBINED_UNIFORM_BLOCKS) GL_ENUM(0x8A2F,GL_MAX_UNIFORM_BUFFER_BINDINGS) GL_ENUM(0x8A30,GL_MAX_UNIFORM_BLOCK_SIZE) GL_ENUM(0x8A31,GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS) GL_ENUM(0x8A33,GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS) GL_ENUM(0x8A34,GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT) GL_ENUM(0x8A35,GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) GL_ENUM(0x8A36,GL_ACTIVE_UNIFORM_BLOCKS) GL_ENUM(0x8A37,GL_UNIFORM_TYPE) GL_ENUM(0x8A38,GL_UNIFORM_SIZE) GL_ENUM(0x8A39,GL_UNIFORM_NAME_LENGTH) GL_ENUM(0x8A3A,GL_UNIFORM_BLOCK_INDEX) GL_ENUM(0x8A3B,GL_UNIFORM_OFFSET) GL_ENUM(0x8A3C,GL_UNIFORM_ARRAY_STRIDE) GL_ENUM(0x8A3D,GL_UNIFORM_MATRIX_STRIDE) GL_ENUM(0x8A3E,GL_UNIFORM_IS_ROW_MAJOR) GL_ENUM(0x8A3F,GL_UNIFORM_BLOCK_BINDING) GL_ENUM(0x8A40,GL_UNIFORM_BLOCK_DATA_SIZE) GL_ENUM(0x8A41,GL_UNIFORM_BLOCK_NAME_LENGTH) GL_ENUM(0x8A42,GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS) GL_ENUM(0x8A43,GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) GL_ENUM(0x8A44,GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER) GL_ENUM(0x8A46,GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER) GL_ENUM(0xFFFFFFFFu,GL_INVALID_INDEX) GL_ENUM(0x9122,GL_MAX_VERTEX_OUTPUT_COMPONENTS) GL_ENUM(0x9125,GL_MAX_FRAGMENT_INPUT_COMPONENTS) GL_ENUM(0x9111,GL_MAX_SERVER_WAIT_TIMEOUT) GL_ENUM(0x9112,GL_OBJECT_TYPE) GL_ENUM(0x9113,GL_SYNC_CONDITION) GL_ENUM(0x9114,GL_SYNC_STATUS) GL_ENUM(0x9115,GL_SYNC_FLAGS) GL_ENUM(0x9116,GL_SYNC_FENCE) GL_ENUM(0x9117,GL_SYNC_GPU_COMMANDS_COMPLETE) GL_ENUM(0x9118,GL_UNSIGNALED) GL_ENUM(0x9119,GL_SIGNALED) GL_ENUM(0x911A,GL_ALREADY_SIGNALED) GL_ENUM(0x911B,GL_TIMEOUT_EXPIRED) GL_ENUM(0x911C,GL_CONDITION_SATISFIED) GL_ENUM(0x911D,GL_WAIT_FAILED) GL_ENUM(0xFFFFFFFFFFFFFFFFull,GL_TIMEOUT_IGNORED) GL_ENUM(0x88FE,GL_VERTEX_ATTRIB_ARRAY_DIVISOR) GL_ENUM(0x8C2F,GL_ANY_SAMPLES_PASSED) GL_ENUM(0x8D6A,GL_ANY_SAMPLES_PASSED_CONSERVATIVE) GL_ENUM(0x8919,GL_SAMPLER_BINDING) GL_ENUM(0x906F,GL_RGB10_A2UI) GL_ENUM(0x8E42,GL_TEXTURE_SWIZZLE_R) GL_ENUM(0x8E43,GL_TEXTURE_SWIZZLE_G) GL_ENUM(0x8E44,GL_TEXTURE_SWIZZLE_B) GL_ENUM(0x8E45,GL_TEXTURE_SWIZZLE_A) GL_ENUM(0x1904,GL_GREEN) GL_ENUM(0x1905,GL_BLUE) GL_ENUM(0x8D9F,GL_INT_2_10_10_10_REV) GL_ENUM(0x8E22,GL_TRANSFORM_FEEDBACK) GL_ENUM(0x8E23,GL_TRANSFORM_FEEDBACK_PAUSED) GL_ENUM(0x8E24,GL_TRANSFORM_FEEDBACK_ACTIVE) GL_ENUM(0x8E25,GL_TRANSFORM_FEEDBACK_BINDING) GL_ENUM(0x8257,GL_PROGRAM_BINARY_RETRIEVABLE_HINT) GL_ENUM(0x8741,GL_PROGRAM_BINARY_LENGTH) GL_ENUM(0x87FE,GL_NUM_PROGRAM_BINARY_FORMATS) GL_ENUM(0x87FF,GL_PROGRAM_BINARY_FORMATS) GL_ENUM(0x9270,GL_COMPRESSED_R11_EAC) GL_ENUM(0x9271,GL_COMPRESSED_SIGNED_R11_EAC) GL_ENUM(0x9272,GL_COMPRESSED_RG11_EAC) GL_ENUM(0x9273,GL_COMPRESSED_SIGNED_RG11_EAC) GL_ENUM(0x9274,GL_COMPRESSED_RGB8_ETC2) GL_ENUM(0x9275,GL_COMPRESSED_SRGB8_ETC2) GL_ENUM(0x9276,GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) GL_ENUM(0x9277,GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) GL_ENUM(0x9278,GL_COMPRESSED_RGBA8_ETC2_EAC) GL_ENUM(0x9279,GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) GL_ENUM(0x912F,GL_TEXTURE_IMMUTABLE_FORMAT) GL_ENUM(0x8D6B,GL_MAX_ELEMENT_INDEX) GL_ENUM(0x9380,GL_NUM_SAMPLE_COUNTS) GL_ENUM(0x82DF,GL_TEXTURE_IMMUTABLE_LEVELS) GL_ENUM(0x91B9,GL_COMPUTE_SHADER) GL_ENUM(0x91BB,GL_MAX_COMPUTE_UNIFORM_BLOCKS) GL_ENUM(0x91BC,GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS) GL_ENUM(0x91BD,GL_MAX_COMPUTE_IMAGE_UNIFORMS) GL_ENUM(0x8262,GL_MAX_COMPUTE_SHARED_MEMORY_SIZE) GL_ENUM(0x8263,GL_MAX_COMPUTE_UNIFORM_COMPONENTS) GL_ENUM(0x8264,GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x8265,GL_MAX_COMPUTE_ATOMIC_COUNTERS) GL_ENUM(0x8266,GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS) GL_ENUM(0x90EB,GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS) GL_ENUM(0x91BE,GL_MAX_COMPUTE_WORK_GROUP_COUNT) GL_ENUM(0x91BF,GL_MAX_COMPUTE_WORK_GROUP_SIZE) GL_ENUM(0x8267,GL_COMPUTE_WORK_GROUP_SIZE) GL_ENUM(0x90EE,GL_DISPATCH_INDIRECT_BUFFER) GL_ENUM(0x90EF,GL_DISPATCH_INDIRECT_BUFFER_BINDING) GL_ENUM(0x8F3F,GL_DRAW_INDIRECT_BUFFER) GL_ENUM(0x8F43,GL_DRAW_INDIRECT_BUFFER_BINDING) GL_ENUM(0x826E,GL_MAX_UNIFORM_LOCATIONS) GL_ENUM(0x9310,GL_FRAMEBUFFER_DEFAULT_WIDTH) GL_ENUM(0x9311,GL_FRAMEBUFFER_DEFAULT_HEIGHT) GL_ENUM(0x9313,GL_FRAMEBUFFER_DEFAULT_SAMPLES) GL_ENUM(0x9314,GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS) GL_ENUM(0x9315,GL_MAX_FRAMEBUFFER_WIDTH) GL_ENUM(0x9316,GL_MAX_FRAMEBUFFER_HEIGHT) GL_ENUM(0x9318,GL_MAX_FRAMEBUFFER_SAMPLES) GL_ENUM(0x92E1,GL_UNIFORM) GL_ENUM(0x92E2,GL_UNIFORM_BLOCK) GL_ENUM(0x92E3,GL_PROGRAM_INPUT) GL_ENUM(0x92E4,GL_PROGRAM_OUTPUT) GL_ENUM(0x92E5,GL_BUFFER_VARIABLE) GL_ENUM(0x92E6,GL_SHADER_STORAGE_BLOCK) GL_ENUM(0x92C0,GL_ATOMIC_COUNTER_BUFFER) GL_ENUM(0x92F4,GL_TRANSFORM_FEEDBACK_VARYING) GL_ENUM(0x92F5,GL_ACTIVE_RESOURCES) GL_ENUM(0x92F6,GL_MAX_NAME_LENGTH) GL_ENUM(0x92F7,GL_MAX_NUM_ACTIVE_VARIABLES) GL_ENUM(0x92F9,GL_NAME_LENGTH) GL_ENUM(0x92FA,GL_TYPE) GL_ENUM(0x92FB,GL_ARRAY_SIZE) GL_ENUM(0x92FC,GL_OFFSET) GL_ENUM(0x92FD,GL_BLOCK_INDEX) GL_ENUM(0x92FE,GL_ARRAY_STRIDE) GL_ENUM(0x92FF,GL_MATRIX_STRIDE) GL_ENUM(0x9300,GL_IS_ROW_MAJOR) GL_ENUM(0x9301,GL_ATOMIC_COUNTER_BUFFER_INDEX) GL_ENUM(0x9302,GL_BUFFER_BINDING) GL_ENUM(0x9303,GL_BUFFER_DATA_SIZE) GL_ENUM(0x9304,GL_NUM_ACTIVE_VARIABLES) GL_ENUM(0x9305,GL_ACTIVE_VARIABLES) GL_ENUM(0x9306,GL_REFERENCED_BY_VERTEX_SHADER) GL_ENUM(0x930A,GL_REFERENCED_BY_FRAGMENT_SHADER) GL_ENUM(0x930B,GL_REFERENCED_BY_COMPUTE_SHADER) GL_ENUM(0x930C,GL_TOP_LEVEL_ARRAY_SIZE) GL_ENUM(0x930D,GL_TOP_LEVEL_ARRAY_STRIDE) GL_ENUM(0x930E,GL_LOCATION) GL_ENUM(0xFFFFFFFF,GL_ALL_SHADER_BITS) GL_ENUM(0x8258,GL_PROGRAM_SEPARABLE) GL_ENUM(0x8259,GL_ACTIVE_PROGRAM) GL_ENUM(0x825A,GL_PROGRAM_PIPELINE_BINDING) GL_ENUM(0x92C1,GL_ATOMIC_COUNTER_BUFFER_BINDING) GL_ENUM(0x92C2,GL_ATOMIC_COUNTER_BUFFER_START) GL_ENUM(0x92C3,GL_ATOMIC_COUNTER_BUFFER_SIZE) GL_ENUM(0x92CC,GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92D0,GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92D1,GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92D2,GL_MAX_VERTEX_ATOMIC_COUNTERS) GL_ENUM(0x92D6,GL_MAX_FRAGMENT_ATOMIC_COUNTERS) GL_ENUM(0x92D7,GL_MAX_COMBINED_ATOMIC_COUNTERS) GL_ENUM(0x92D8,GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE) GL_ENUM(0x92DC,GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS) GL_ENUM(0x92D9,GL_ACTIVE_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92DB,GL_UNSIGNED_INT_ATOMIC_COUNTER) GL_ENUM(0x8F38,GL_MAX_IMAGE_UNITS) GL_ENUM(0x90CA,GL_MAX_VERTEX_IMAGE_UNIFORMS) GL_ENUM(0x90CE,GL_MAX_FRAGMENT_IMAGE_UNIFORMS) GL_ENUM(0x90CF,GL_MAX_COMBINED_IMAGE_UNIFORMS) GL_ENUM(0x8F3A,GL_IMAGE_BINDING_NAME) GL_ENUM(0x8F3B,GL_IMAGE_BINDING_LEVEL) GL_ENUM(0x8F3C,GL_IMAGE_BINDING_LAYERED) GL_ENUM(0x8F3D,GL_IMAGE_BINDING_LAYER) GL_ENUM(0x8F3E,GL_IMAGE_BINDING_ACCESS) GL_ENUM(0x906E,GL_IMAGE_BINDING_FORMAT) GL_ENUM(0x904D,GL_IMAGE_2D) GL_ENUM(0x904E,GL_IMAGE_3D) GL_ENUM(0x9050,GL_IMAGE_CUBE) GL_ENUM(0x9053,GL_IMAGE_2D_ARRAY) GL_ENUM(0x9058,GL_INT_IMAGE_2D) GL_ENUM(0x9059,GL_INT_IMAGE_3D) GL_ENUM(0x905B,GL_INT_IMAGE_CUBE) GL_ENUM(0x905E,GL_INT_IMAGE_2D_ARRAY) GL_ENUM(0x9063,GL_UNSIGNED_INT_IMAGE_2D) GL_ENUM(0x9064,GL_UNSIGNED_INT_IMAGE_3D) GL_ENUM(0x9066,GL_UNSIGNED_INT_IMAGE_CUBE) GL_ENUM(0x9069,GL_UNSIGNED_INT_IMAGE_2D_ARRAY) GL_ENUM(0x90C7,GL_IMAGE_FORMAT_COMPATIBILITY_TYPE) GL_ENUM(0x90C8,GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE) GL_ENUM(0x90C9,GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS) GL_ENUM(0x88B8,GL_READ_ONLY) GL_ENUM(0x88B9,GL_WRITE_ONLY) GL_ENUM(0x88BA,GL_READ_WRITE) GL_ENUM(0x90D2,GL_SHADER_STORAGE_BUFFER) GL_ENUM(0x90D3,GL_SHADER_STORAGE_BUFFER_BINDING) GL_ENUM(0x90D4,GL_SHADER_STORAGE_BUFFER_START) GL_ENUM(0x90D5,GL_SHADER_STORAGE_BUFFER_SIZE) GL_ENUM(0x90D6,GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS) GL_ENUM(0x90DA,GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS) GL_ENUM(0x90DB,GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS) GL_ENUM(0x90DC,GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS) GL_ENUM(0x90DD,GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS) GL_ENUM(0x90DE,GL_MAX_SHADER_STORAGE_BLOCK_SIZE) GL_ENUM(0x90DF,GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) GL_ENUM(0x8F39,GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES) GL_ENUM(0x90EA,GL_DEPTH_STENCIL_TEXTURE_MODE) GL_ENUM(0x1901,GL_STENCIL_INDEX) GL_ENUM(0x8E5E,GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET) GL_ENUM(0x8E5F,GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET) GL_ENUM(0x8E50,GL_SAMPLE_POSITION) GL_ENUM(0x8E51,GL_SAMPLE_MASK) GL_ENUM(0x8E52,GL_SAMPLE_MASK_VALUE) GL_ENUM(0x9100,GL_TEXTURE_2D_MULTISAMPLE) GL_ENUM(0x8E59,GL_MAX_SAMPLE_MASK_WORDS) GL_ENUM(0x910E,GL_MAX_COLOR_TEXTURE_SAMPLES) GL_ENUM(0x910F,GL_MAX_DEPTH_TEXTURE_SAMPLES) GL_ENUM(0x9110,GL_MAX_INTEGER_SAMPLES) GL_ENUM(0x9104,GL_TEXTURE_BINDING_2D_MULTISAMPLE) GL_ENUM(0x9106,GL_TEXTURE_SAMPLES) GL_ENUM(0x9107,GL_TEXTURE_FIXED_SAMPLE_LOCATIONS) GL_ENUM(0x1000,GL_TEXTURE_WIDTH) GL_ENUM(0x1001,GL_TEXTURE_HEIGHT) GL_ENUM(0x8071,GL_TEXTURE_DEPTH) GL_ENUM(0x1003,GL_TEXTURE_INTERNAL_FORMAT) GL_ENUM(0x805C,GL_TEXTURE_RED_SIZE) GL_ENUM(0x805D,GL_TEXTURE_GREEN_SIZE) GL_ENUM(0x805E,GL_TEXTURE_BLUE_SIZE) GL_ENUM(0x805F,GL_TEXTURE_ALPHA_SIZE) GL_ENUM(0x884A,GL_TEXTURE_DEPTH_SIZE) GL_ENUM(0x88F1,GL_TEXTURE_STENCIL_SIZE) GL_ENUM(0x8C3F,GL_TEXTURE_SHARED_SIZE) GL_ENUM(0x8C10,GL_TEXTURE_RED_TYPE) GL_ENUM(0x8C11,GL_TEXTURE_GREEN_TYPE) GL_ENUM(0x8C12,GL_TEXTURE_BLUE_TYPE) GL_ENUM(0x8C13,GL_TEXTURE_ALPHA_TYPE) GL_ENUM(0x8C16,GL_TEXTURE_DEPTH_TYPE) GL_ENUM(0x86A1,GL_TEXTURE_COMPRESSED) GL_ENUM(0x9108,GL_SAMPLER_2D_MULTISAMPLE) GL_ENUM(0x9109,GL_INT_SAMPLER_2D_MULTISAMPLE) GL_ENUM(0x910A,GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE) GL_ENUM(0x82D4,GL_VERTEX_ATTRIB_BINDING) GL_ENUM(0x82D5,GL_VERTEX_ATTRIB_RELATIVE_OFFSET) GL_ENUM(0x82D6,GL_VERTEX_BINDING_DIVISOR) GL_ENUM(0x82D7,GL_VERTEX_BINDING_OFFSET) GL_ENUM(0x82D8,GL_VERTEX_BINDING_STRIDE) GL_ENUM(0x8F4F,GL_VERTEX_BINDING_BUFFER) GL_ENUM(0x82D9,GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET) GL_ENUM(0x82DA,GL_MAX_VERTEX_ATTRIB_BINDINGS) GL_ENUM(0x82E5,GL_MAX_VERTEX_ATTRIB_STRIDE) GL_ENUM(0x9381,GL_MULTISAMPLE_LINE_WIDTH_RANGE) GL_ENUM(0x9382,GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY) GL_ENUM(0x9294,GL_MULTIPLY) GL_ENUM(0x9295,GL_SCREEN) GL_ENUM(0x9296,GL_OVERLAY) GL_ENUM(0x9297,GL_DARKEN) GL_ENUM(0x9298,GL_LIGHTEN) GL_ENUM(0x9299,GL_COLORDODGE) GL_ENUM(0x929A,GL_COLORBURN) GL_ENUM(0x929B,GL_HARDLIGHT) GL_ENUM(0x929C,GL_SOFTLIGHT) GL_ENUM(0x929E,GL_DIFFERENCE) GL_ENUM(0x92A0,GL_EXCLUSION) GL_ENUM(0x92AD,GL_HSL_HUE) GL_ENUM(0x92AE,GL_HSL_SATURATION) GL_ENUM(0x92AF,GL_HSL_COLOR) GL_ENUM(0x92B0,GL_HSL_LUMINOSITY) GL_ENUM(0x8242,GL_DEBUG_OUTPUT_SYNCHRONOUS) GL_ENUM(0x8243,GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH) GL_ENUM(0x8244,GL_DEBUG_CALLBACK_FUNCTION) GL_ENUM(0x8245,GL_DEBUG_CALLBACK_USER_PARAM) GL_ENUM(0x8246,GL_DEBUG_SOURCE_API) GL_ENUM(0x8247,GL_DEBUG_SOURCE_WINDOW_SYSTEM) GL_ENUM(0x8248,GL_DEBUG_SOURCE_SHADER_COMPILER) GL_ENUM(0x8249,GL_DEBUG_SOURCE_THIRD_PARTY) GL_ENUM(0x824A,GL_DEBUG_SOURCE_APPLICATION) GL_ENUM(0x824B,GL_DEBUG_SOURCE_OTHER) GL_ENUM(0x824C,GL_DEBUG_TYPE_ERROR) GL_ENUM(0x824D,GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) GL_ENUM(0x824E,GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR) GL_ENUM(0x824F,GL_DEBUG_TYPE_PORTABILITY) GL_ENUM(0x8250,GL_DEBUG_TYPE_PERFORMANCE) GL_ENUM(0x8251,GL_DEBUG_TYPE_OTHER) GL_ENUM(0x8268,GL_DEBUG_TYPE_MARKER) GL_ENUM(0x8269,GL_DEBUG_TYPE_PUSH_GROUP) GL_ENUM(0x826A,GL_DEBUG_TYPE_POP_GROUP) GL_ENUM(0x826B,GL_DEBUG_SEVERITY_NOTIFICATION) GL_ENUM(0x826C,GL_MAX_DEBUG_GROUP_STACK_DEPTH) GL_ENUM(0x826D,GL_DEBUG_GROUP_STACK_DEPTH) GL_ENUM(0x82E0,GL_BUFFER) GL_ENUM(0x82E1,GL_SHADER) GL_ENUM(0x82E2,GL_PROGRAM) GL_ENUM(0x82E3,GL_QUERY) GL_ENUM(0x82E4,GL_PROGRAM_PIPELINE) GL_ENUM(0x82E6,GL_SAMPLER) GL_ENUM(0x82E8,GL_MAX_LABEL_LENGTH) GL_ENUM(0x9143,GL_MAX_DEBUG_MESSAGE_LENGTH) GL_ENUM(0x9144,GL_MAX_DEBUG_LOGGED_MESSAGES) GL_ENUM(0x9145,GL_DEBUG_LOGGED_MESSAGES) GL_ENUM(0x9146,GL_DEBUG_SEVERITY_HIGH) GL_ENUM(0x9147,GL_DEBUG_SEVERITY_MEDIUM) GL_ENUM(0x9148,GL_DEBUG_SEVERITY_LOW) GL_ENUM(0x92E0,GL_DEBUG_OUTPUT) GL_ENUM(0x8DD9,GL_GEOMETRY_SHADER) GL_ENUM(0x8916,GL_GEOMETRY_VERTICES_OUT) GL_ENUM(0x8917,GL_GEOMETRY_INPUT_TYPE) GL_ENUM(0x8918,GL_GEOMETRY_OUTPUT_TYPE) GL_ENUM(0x887F,GL_GEOMETRY_SHADER_INVOCATIONS) GL_ENUM(0x825E,GL_LAYER_PROVOKING_VERTEX) GL_ENUM(0x000A,GL_LINES_ADJACENCY) GL_ENUM(0x000B,GL_LINE_STRIP_ADJACENCY) GL_ENUM(0x000C,GL_TRIANGLES_ADJACENCY) GL_ENUM(0x000D,GL_TRIANGLE_STRIP_ADJACENCY) GL_ENUM(0x8DDF,GL_MAX_GEOMETRY_UNIFORM_COMPONENTS) GL_ENUM(0x8A2C,GL_MAX_GEOMETRY_UNIFORM_BLOCKS) GL_ENUM(0x8A32,GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS) GL_ENUM(0x9123,GL_MAX_GEOMETRY_INPUT_COMPONENTS) GL_ENUM(0x9124,GL_MAX_GEOMETRY_OUTPUT_COMPONENTS) GL_ENUM(0x8DE0,GL_MAX_GEOMETRY_OUTPUT_VERTICES) GL_ENUM(0x8DE1,GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS) GL_ENUM(0x8E5A,GL_MAX_GEOMETRY_SHADER_INVOCATIONS) GL_ENUM(0x8C29,GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS) GL_ENUM(0x92CF,GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92D5,GL_MAX_GEOMETRY_ATOMIC_COUNTERS) GL_ENUM(0x90CD,GL_MAX_GEOMETRY_IMAGE_UNIFORMS) GL_ENUM(0x90D7,GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS) GL_ENUM(0x8E4D,GL_FIRST_VERTEX_CONVENTION) GL_ENUM(0x8E4E,GL_LAST_VERTEX_CONVENTION) GL_ENUM(0x8260,GL_UNDEFINED_VERTEX) GL_ENUM(0x8C87,GL_PRIMITIVES_GENERATED) GL_ENUM(0x9312,GL_FRAMEBUFFER_DEFAULT_LAYERS) GL_ENUM(0x9317,GL_MAX_FRAMEBUFFER_LAYERS) GL_ENUM(0x8DA8,GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS) GL_ENUM(0x8DA7,GL_FRAMEBUFFER_ATTACHMENT_LAYERED) GL_ENUM(0x9309,GL_REFERENCED_BY_GEOMETRY_SHADER) GL_ENUM(0x92BE,GL_PRIMITIVE_BOUNDING_BOX) GL_ENUM(0x821E,GL_CONTEXT_FLAGS) GL_ENUM(0x8252,GL_LOSE_CONTEXT_ON_RESET) GL_ENUM(0x8253,GL_GUILTY_CONTEXT_RESET) GL_ENUM(0x8254,GL_INNOCENT_CONTEXT_RESET) GL_ENUM(0x8255,GL_UNKNOWN_CONTEXT_RESET) GL_ENUM(0x8256,GL_RESET_NOTIFICATION_STRATEGY) GL_ENUM(0x8261,GL_NO_RESET_NOTIFICATION) GL_ENUM(0x0507,GL_CONTEXT_LOST) GL_ENUM(0x8C36,GL_SAMPLE_SHADING) GL_ENUM(0x8C37,GL_MIN_SAMPLE_SHADING_VALUE) GL_ENUM(0x8E5B,GL_MIN_FRAGMENT_INTERPOLATION_OFFSET) GL_ENUM(0x8E5C,GL_MAX_FRAGMENT_INTERPOLATION_OFFSET) GL_ENUM(0x8E5D,GL_FRAGMENT_INTERPOLATION_OFFSET_BITS) GL_ENUM(0x000E,GL_PATCHES) GL_ENUM(0x8E72,GL_PATCH_VERTICES) GL_ENUM(0x8E75,GL_TESS_CONTROL_OUTPUT_VERTICES) GL_ENUM(0x8E76,GL_TESS_GEN_MODE) GL_ENUM(0x8E77,GL_TESS_GEN_SPACING) GL_ENUM(0x8E78,GL_TESS_GEN_VERTEX_ORDER) GL_ENUM(0x8E79,GL_TESS_GEN_POINT_MODE) GL_ENUM(0x8E7A,GL_ISOLINES) GL_ENUM(0x0007,GL_QUADS) GL_ENUM(0x8E7B,GL_FRACTIONAL_ODD) GL_ENUM(0x8E7C,GL_FRACTIONAL_EVEN) GL_ENUM(0x8E7D,GL_MAX_PATCH_VERTICES) GL_ENUM(0x8E7E,GL_MAX_TESS_GEN_LEVEL) GL_ENUM(0x8E7F,GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS) GL_ENUM(0x8E80,GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS) GL_ENUM(0x8E81,GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS) GL_ENUM(0x8E82,GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS) GL_ENUM(0x8E83,GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS) GL_ENUM(0x8E84,GL_MAX_TESS_PATCH_COMPONENTS) GL_ENUM(0x8E85,GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS) GL_ENUM(0x8E86,GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS) GL_ENUM(0x8E89,GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS) GL_ENUM(0x8E8A,GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS) GL_ENUM(0x886C,GL_MAX_TESS_CONTROL_INPUT_COMPONENTS) GL_ENUM(0x886D,GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS) GL_ENUM(0x8E1E,GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS) GL_ENUM(0x8E1F,GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS) GL_ENUM(0x92CD,GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92CE,GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS) GL_ENUM(0x92D3,GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS) GL_ENUM(0x92D4,GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS) GL_ENUM(0x90CB,GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS) GL_ENUM(0x90CC,GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS) GL_ENUM(0x90D8,GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS) GL_ENUM(0x90D9,GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS) GL_ENUM(0x8221,GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED) GL_ENUM(0x92E7,GL_IS_PER_PATCH) GL_ENUM(0x9307,GL_REFERENCED_BY_TESS_CONTROL_SHADER) GL_ENUM(0x9308,GL_REFERENCED_BY_TESS_EVALUATION_SHADER) GL_ENUM(0x8E88,GL_TESS_CONTROL_SHADER) GL_ENUM(0x8E87,GL_TESS_EVALUATION_SHADER) GL_ENUM(0x1004,GL_TEXTURE_BORDER_COLOR) GL_ENUM(0x812D,GL_CLAMP_TO_BORDER) GL_ENUM(0x8C2A,GL_TEXTURE_BUFFER) GL_ENUM(0x8C2B,GL_MAX_TEXTURE_BUFFER_SIZE) GL_ENUM(0x8C2C,GL_TEXTURE_BINDING_BUFFER) GL_ENUM(0x8C2D,GL_TEXTURE_BUFFER_DATA_STORE_BINDING) GL_ENUM(0x919F,GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT) GL_ENUM(0x8DC2,GL_SAMPLER_BUFFER) GL_ENUM(0x8DD0,GL_INT_SAMPLER_BUFFER) GL_ENUM(0x8DD8,GL_UNSIGNED_INT_SAMPLER_BUFFER) GL_ENUM(0x9051,GL_IMAGE_BUFFER) GL_ENUM(0x905C,GL_INT_IMAGE_BUFFER) GL_ENUM(0x9067,GL_UNSIGNED_INT_IMAGE_BUFFER) GL_ENUM(0x919D,GL_TEXTURE_BUFFER_OFFSET) GL_ENUM(0x919E,GL_TEXTURE_BUFFER_SIZE) GL_ENUM(0x93B0,GL_COMPRESSED_RGBA_ASTC_4x4) GL_ENUM(0x93B1,GL_COMPRESSED_RGBA_ASTC_5x4) GL_ENUM(0x93B2,GL_COMPRESSED_RGBA_ASTC_5x5) GL_ENUM(0x93B3,GL_COMPRESSED_RGBA_ASTC_6x5) GL_ENUM(0x93B4,GL_COMPRESSED_RGBA_ASTC_6x6) GL_ENUM(0x93B5,GL_COMPRESSED_RGBA_ASTC_8x5) GL_ENUM(0x93B6,GL_COMPRESSED_RGBA_ASTC_8x6) GL_ENUM(0x93B7,GL_COMPRESSED_RGBA_ASTC_8x8) GL_ENUM(0x93B8,GL_COMPRESSED_RGBA_ASTC_10x5) GL_ENUM(0x93B9,GL_COMPRESSED_RGBA_ASTC_10x6) GL_ENUM(0x93BA,GL_COMPRESSED_RGBA_ASTC_10x8) GL_ENUM(0x93BB,GL_COMPRESSED_RGBA_ASTC_10x10) GL_ENUM(0x93BC,GL_COMPRESSED_RGBA_ASTC_12x10) GL_ENUM(0x93BD,GL_COMPRESSED_RGBA_ASTC_12x12) GL_ENUM(0x93D0,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4) GL_ENUM(0x93D1,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4) GL_ENUM(0x93D2,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5) GL_ENUM(0x93D3,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5) GL_ENUM(0x93D4,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6) GL_ENUM(0x93D5,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5) GL_ENUM(0x93D6,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6) GL_ENUM(0x93D7,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8) GL_ENUM(0x93D8,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5) GL_ENUM(0x93D9,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6) GL_ENUM(0x93DA,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8) GL_ENUM(0x93DB,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10) GL_ENUM(0x93DC,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10) GL_ENUM(0x93DD,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12) GL_ENUM(0x9009,GL_TEXTURE_CUBE_MAP_ARRAY) GL_ENUM(0x900A,GL_TEXTURE_BINDING_CUBE_MAP_ARRAY) GL_ENUM(0x900C,GL_SAMPLER_CUBE_MAP_ARRAY) GL_ENUM(0x900D,GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW) GL_ENUM(0x900E,GL_INT_SAMPLER_CUBE_MAP_ARRAY) GL_ENUM(0x900F,GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY) GL_ENUM(0x9054,GL_IMAGE_CUBE_MAP_ARRAY) GL_ENUM(0x905F,GL_INT_IMAGE_CUBE_MAP_ARRAY) GL_ENUM(0x906A,GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY) GL_ENUM(0x9102,GL_TEXTURE_2D_MULTISAMPLE_ARRAY) GL_ENUM(0x9105,GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY) GL_ENUM(0x910B,GL_SAMPLER_2D_MULTISAMPLE_ARRAY) GL_ENUM(0x910C,GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) GL_ENUM(0x910D,GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) GL_ENUM(0x8D65,GL_TEXTURE_EXTERNAL_OES) GL_ENUM(0x8D67,GL_TEXTURE_BINDING_EXTERNAL_OES) GL_ENUM(0x8D68,GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES) GL_ENUM(0x8D64,GL_ETC1_RGB8_OES) GL_ENUM(0x8B90,GL_PALETTE4_RGB8_OES) GL_ENUM(0x8B91,GL_PALETTE4_RGBA8_OES) GL_ENUM(0x8B92,GL_PALETTE4_R5_G6_B5_OES) GL_ENUM(0x8B93,GL_PALETTE4_RGBA4_OES) GL_ENUM(0x8B94,GL_PALETTE4_RGB5_A1_OES) GL_ENUM(0x8B95,GL_PALETTE8_RGB8_OES) GL_ENUM(0x8B96,GL_PALETTE8_RGBA8_OES) GL_ENUM(0x8B97,GL_PALETTE8_R5_G6_B5_OES) GL_ENUM(0x8B98,GL_PALETTE8_RGBA4_OES) GL_ENUM(0x8B99,GL_PALETTE8_RGB5_A1_OES) GL_ENUM(0x81A7,GL_DEPTH_COMPONENT32_OES) GL_ENUM(0x8B9D,GL_TEXTURE_CROP_RECT_OES) GL_ENUM(0x8CDA,GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES) GL_ENUM(0x88BB,GL_BUFFER_ACCESS_OES) GL_ENUM(0x898D,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES) GL_ENUM(0x898E,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES) GL_ENUM(0x898F,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES) GL_ENUM(0x86A4,GL_MAX_VERTEX_UNITS_OES) GL_ENUM(0x8842,GL_MAX_PALETTE_MATRICES_OES) GL_ENUM(0x8840,GL_MATRIX_PALETTE_OES) GL_ENUM(0x8844,GL_MATRIX_INDEX_ARRAY_OES) GL_ENUM(0x86AD,GL_WEIGHT_ARRAY_OES) GL_ENUM(0x8843,GL_CURRENT_PALETTE_MATRIX_OES) GL_ENUM(0x8846,GL_MATRIX_INDEX_ARRAY_SIZE_OES) GL_ENUM(0x8847,GL_MATRIX_INDEX_ARRAY_TYPE_OES) GL_ENUM(0x8848,GL_MATRIX_INDEX_ARRAY_STRIDE_OES) GL_ENUM(0x8849,GL_MATRIX_INDEX_ARRAY_POINTER_OES) GL_ENUM(0x8B9E,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES) GL_ENUM(0x86AB,GL_WEIGHT_ARRAY_SIZE_OES) GL_ENUM(0x86A9,GL_WEIGHT_ARRAY_TYPE_OES) GL_ENUM(0x86AA,GL_WEIGHT_ARRAY_STRIDE_OES) GL_ENUM(0x86AC,GL_WEIGHT_ARRAY_POINTER_OES) GL_ENUM(0x889E,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES) GL_ENUM(0x8B9C,GL_POINT_SIZE_ARRAY_OES) GL_ENUM(0x898A,GL_POINT_SIZE_ARRAY_TYPE_OES) GL_ENUM(0x898B,GL_POINT_SIZE_ARRAY_STRIDE_OES) GL_ENUM(0x898C,GL_POINT_SIZE_ARRAY_POINTER_OES) GL_ENUM(0x8B9F,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES) GL_ENUM(0x8861,GL_POINT_SPRITE_OES) GL_ENUM(0x8862,GL_COORD_REPLACE_OES) GL_ENUM(0x803C,GL_ALPHA8_OES) GL_ENUM(0x8043,GL_LUMINANCE4_ALPHA4_OES) GL_ENUM(0x8045,GL_LUMINANCE8_ALPHA8_OES) GL_ENUM(0x8040,GL_LUMINANCE8_OES) GL_ENUM(0x8052,GL_RGB10_EXT) GL_ENUM(0x8D46,GL_STENCIL_INDEX1_OES) GL_ENUM(0x8D47,GL_STENCIL_INDEX4_OES) GL_ENUM(0x8511,GL_NORMAL_MAP_OES) GL_ENUM(0x8512,GL_REFLECTION_MAP_OES) GL_ENUM(0x2500,GL_TEXTURE_GEN_MODE_OES) GL_ENUM(0x8D60,GL_TEXTURE_GEN_STR_OES) GL_ENUM(0x87F9,GL_3DC_X_AMD) GL_ENUM(0x87FA,GL_3DC_XY_AMD) GL_ENUM(0x8C92,GL_ATC_RGB_AMD) GL_ENUM(0x8C93,GL_ATC_RGBA_EXPLICIT_ALPHA_AMD) GL_ENUM(0x87EE,GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD) GL_ENUM(0x8A53,GL_SYNC_OBJECT_APPLE) GL_ENUM(0x80E1,GL_BGRA_EXT) GL_ENUM(0x93A1,GL_BGRA8_EXT) GL_ENUM(0x8D6C,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT) GL_ENUM(0x8365,GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) GL_ENUM(0x8366,GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT) GL_ENUM(0x90F3,GL_CONTEXT_ROBUST_ACCESS_EXT) GL_ENUM(0x8C42,GL_SRGB_ALPHA_EXT) GL_ENUM(0x83F0,GL_COMPRESSED_RGB_S3TC_DXT1_EXT) GL_ENUM(0x83F1,GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) GL_ENUM(0x84FE,GL_TEXTURE_MAX_ANISOTROPY_EXT) GL_ENUM(0x84FF,GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) GL_ENUM(0x8500,GL_TEXTURE_FILTER_CONTROL_EXT) GL_ENUM(0x8501,GL_TEXTURE_LOD_BIAS_EXT) GL_ENUM(0x8816,GL_ALPHA32F_EXT) GL_ENUM(0x8818,GL_LUMINANCE32F_EXT) GL_ENUM(0x8819,GL_LUMINANCE_ALPHA32F_EXT) GL_ENUM(0x881C,GL_ALPHA16F_EXT) GL_ENUM(0x881E,GL_LUMINANCE16F_EXT) GL_ENUM(0x881F,GL_LUMINANCE_ALPHA16F_EXT) GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_IMG) GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG) GL_ENUM(0x9135,GL_MAX_SAMPLES_IMG) GL_ENUM(0x9136,GL_TEXTURE_SAMPLES_IMG) GL_ENUM(0x8C00,GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG) GL_ENUM(0x8C01,GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG) GL_ENUM(0x8C02,GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG) GL_ENUM(0x8C03,GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) GL_ENUM(0x8C04,GL_MODULATE_COLOR_IMG) GL_ENUM(0x8C05,GL_RECIP_ADD_SIGNED_ALPHA_IMG) GL_ENUM(0x8C06,GL_TEXTURE_ALPHA_MODULATE_IMG) GL_ENUM(0x8C07,GL_FACTOR_ALPHA_MODULATE_IMG) GL_ENUM(0x8C08,GL_FRAGMENT_ALPHA_MODULATE_IMG) GL_ENUM(0x8C09,GL_ADD_BLEND_IMG) GL_ENUM(0x84F2,GL_ALL_COMPLETED_NV) GL_ENUM(0x84F3,GL_FENCE_STATUS_NV) GL_ENUM(0x84F4,GL_FENCE_CONDITION_NV) GL_ENUM(0x8BD2,GL_TEXTURE_WIDTH_QCOM) GL_ENUM(0x8BD3,GL_TEXTURE_HEIGHT_QCOM) GL_ENUM(0x8BD4,GL_TEXTURE_DEPTH_QCOM) GL_ENUM(0x8BD5,GL_TEXTURE_INTERNAL_FORMAT_QCOM) GL_ENUM(0x8BD6,GL_TEXTURE_FORMAT_QCOM) GL_ENUM(0x8BD7,GL_TEXTURE_TYPE_QCOM) GL_ENUM(0x8BD8,GL_TEXTURE_IMAGE_VALID_QCOM) GL_ENUM(0x8BD9,GL_TEXTURE_NUM_LEVELS_QCOM) GL_ENUM(0x8BDA,GL_TEXTURE_TARGET_QCOM) GL_ENUM(0x8BDB,GL_TEXTURE_OBJECT_VALID_QCOM) GL_ENUM(0x8BDC,GL_STATE_RESTORE) GL_ENUM(0x8FA0,GL_PERFMON_GLOBAL_MODE_QCOM) GL_ENUM(0x8823,GL_WRITEONLY_RENDERING_QCOM) GL_ENUM(0x9285,GL_BLEND_ADVANCED_COHERENT_KHR) GL_ENUM(0x82FB,GL_CONTEXT_RELEASE_BEHAVIOR_KHR) GL_ENUM(0x82FC,GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR) GL_ENUM(0x8D66,GL_SAMPLER_EXTERNAL_OES) GL_ENUM(0x93C0,GL_COMPRESSED_RGBA_ASTC_3x3x3_OES) GL_ENUM(0x93C1,GL_COMPRESSED_RGBA_ASTC_4x3x3_OES) GL_ENUM(0x93C2,GL_COMPRESSED_RGBA_ASTC_4x4x3_OES) GL_ENUM(0x93C3,GL_COMPRESSED_RGBA_ASTC_4x4x4_OES) GL_ENUM(0x93C4,GL_COMPRESSED_RGBA_ASTC_5x4x4_OES) GL_ENUM(0x93C5,GL_COMPRESSED_RGBA_ASTC_5x5x4_OES) GL_ENUM(0x93C6,GL_COMPRESSED_RGBA_ASTC_5x5x5_OES) GL_ENUM(0x93C7,GL_COMPRESSED_RGBA_ASTC_6x5x5_OES) GL_ENUM(0x93C8,GL_COMPRESSED_RGBA_ASTC_6x6x5_OES) GL_ENUM(0x93C9,GL_COMPRESSED_RGBA_ASTC_6x6x6_OES) GL_ENUM(0x93E0,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES) GL_ENUM(0x93E1,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES) GL_ENUM(0x93E2,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES) GL_ENUM(0x93E3,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES) GL_ENUM(0x93E4,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES) GL_ENUM(0x93E5,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES) GL_ENUM(0x93E6,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES) GL_ENUM(0x93E7,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES) GL_ENUM(0x93E8,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES) GL_ENUM(0x93E9,GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES) GL_ENUM(0x8D61,GL_HALF_FLOAT_OES) GL_ENUM(0x82DB,GL_TEXTURE_VIEW_MIN_LEVEL_OES) GL_ENUM(0x82DC,GL_TEXTURE_VIEW_NUM_LEVELS_OES) GL_ENUM(0x82DD,GL_TEXTURE_VIEW_MIN_LAYER_OES) GL_ENUM(0x82DE,GL_TEXTURE_VIEW_NUM_LAYERS_OES) GL_ENUM(0x8DF6,GL_UNSIGNED_INT_10_10_10_2_OES) GL_ENUM(0x8DF7,GL_INT_10_10_10_2_OES) GL_ENUM(0x8BC0,GL_COUNTER_TYPE_AMD) GL_ENUM(0x8BC1,GL_COUNTER_RANGE_AMD) GL_ENUM(0x8BC2,GL_UNSIGNED_INT64_AMD) GL_ENUM(0x8BC3,GL_PERCENTAGE_AMD) GL_ENUM(0x8BC4,GL_PERFMON_RESULT_AVAILABLE_AMD) GL_ENUM(0x8BC5,GL_PERFMON_RESULT_SIZE_AMD) GL_ENUM(0x8BC6,GL_PERFMON_RESULT_AMD) GL_ENUM(0x8740,GL_Z400_BINARY_AMD) GL_ENUM(0x93A4,GL_PACK_REVERSE_ROW_ORDER_ANGLE) GL_ENUM(0x93A6,GL_PROGRAM_BINARY_ANGLE) GL_ENUM(0x83F2,GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) GL_ENUM(0x83F3,GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) GL_ENUM(0x93A2,GL_TEXTURE_USAGE_ANGLE) GL_ENUM(0x93A3,GL_FRAMEBUFFER_ATTACHMENT_ANGLE) GL_ENUM(0x93A0,GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE) GL_ENUM(0x3006,GL_CLIP_DISTANCE6_APPLE) GL_ENUM(0x3007,GL_CLIP_DISTANCE7_APPLE) GL_ENUM(0x8A1F,GL_RGB_422_APPLE) GL_ENUM(0x85BA,GL_UNSIGNED_SHORT_8_8_APPLE) GL_ENUM(0x85BB,GL_UNSIGNED_SHORT_8_8_REV_APPLE) GL_ENUM(0x8A51,GL_RGB_RAW_422_APPLE) GL_ENUM(0x8F61,GL_MALI_PROGRAM_BINARY_ARM) GL_ENUM(0x8F60,GL_MALI_SHADER_BINARY_ARM) GL_ENUM(0x8F65,GL_FETCH_PER_SAMPLE_ARM) GL_ENUM(0x8F66,GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM) GL_ENUM(0x9251,GL_SMAPHS30_PROGRAM_BINARY_DMP) GL_ENUM(0x9252,GL_SMAPHS_PROGRAM_BINARY_DMP) GL_ENUM(0x9253,GL_DMP_PROGRAM_BINARY_DMP) GL_ENUM(0x9250,GL_SHADER_BINARY_DMP) GL_ENUM(0x8BE7,GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT) GL_ENUM(0x88F9,GL_SRC1_COLOR_EXT) GL_ENUM(0x88FA,GL_ONE_MINUS_SRC1_COLOR_EXT) GL_ENUM(0x88FB,GL_ONE_MINUS_SRC1_ALPHA_EXT) GL_ENUM(0x930F,GL_LOCATION_INDEX_EXT) GL_ENUM(0x88FC,GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT) GL_ENUM(0x821F,GL_BUFFER_IMMUTABLE_STORAGE_EXT) GL_ENUM(0x8220,GL_BUFFER_STORAGE_FLAGS_EXT) GL_ENUM(0x8A4F,GL_PROGRAM_PIPELINE_OBJECT_EXT) GL_ENUM(0x8B40,GL_PROGRAM_OBJECT_EXT) GL_ENUM(0x8B48,GL_SHADER_OBJECT_EXT) GL_ENUM(0x9151,GL_BUFFER_OBJECT_EXT) GL_ENUM(0x9153,GL_QUERY_OBJECT_EXT) GL_ENUM(0x9154,GL_VERTEX_ARRAY_OBJECT_EXT) GL_ENUM(0x8864,GL_QUERY_COUNTER_BITS_EXT) GL_ENUM(0x88BF,GL_TIME_ELAPSED_EXT) GL_ENUM(0x8E28,GL_TIMESTAMP_EXT) GL_ENUM(0x8FBB,GL_GPU_DISJOINT_EXT) GL_ENUM(0x90F0,GL_COLOR_ATTACHMENT_EXT) GL_ENUM(0x90F1,GL_MULTIVIEW_EXT) GL_ENUM(0x0C01,GL_DRAW_BUFFER_EXT) GL_ENUM(0x90F2,GL_MAX_MULTIVIEW_BUFFERS_EXT) GL_ENUM(0x8A54,GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT) GL_ENUM(0x8A55,GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT) GL_ENUM(0x8A56,GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT) GL_ENUM(0x8A57,GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT) GL_ENUM(0x93F0,GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG) GL_ENUM(0x93F1,GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG) GL_ENUM(0x9327,GL_RASTER_MULTISAMPLE_EXT) GL_ENUM(0x9328,GL_RASTER_SAMPLES_EXT) GL_ENUM(0x9329,GL_MAX_RASTER_SAMPLES_EXT) GL_ENUM(0x932A,GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT) GL_ENUM(0x932B,GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT) GL_ENUM(0x932C,GL_EFFECTIVE_RASTER_SAMPLES_EXT) GL_ENUM(0x8F98,GL_R16_SNORM_EXT) GL_ENUM(0x8F99,GL_RG16_SNORM_EXT) GL_ENUM(0x8F9B,GL_RGBA16_SNORM_EXT) GL_ENUM(0x8DB9,GL_FRAMEBUFFER_SRGB_EXT) GL_ENUM(0x8A52,GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT) GL_ENUM(0x8F63,GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT) GL_ENUM(0x8F67,GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT) GL_ENUM(0x8F64,GL_SHADER_PIXEL_LOCAL_STORAGE_EXT) GL_ENUM(0x91A6,GL_TEXTURE_SPARSE_EXT) GL_ENUM(0x91A7,GL_VIRTUAL_PAGE_SIZE_INDEX_EXT) GL_ENUM(0x91AA,GL_NUM_SPARSE_LEVELS_EXT) GL_ENUM(0x91A8,GL_NUM_VIRTUAL_PAGE_SIZES_EXT) GL_ENUM(0x9195,GL_VIRTUAL_PAGE_SIZE_X_EXT) GL_ENUM(0x9196,GL_VIRTUAL_PAGE_SIZE_Y_EXT) GL_ENUM(0x9197,GL_VIRTUAL_PAGE_SIZE_Z_EXT) GL_ENUM(0x9198,GL_MAX_SPARSE_TEXTURE_SIZE_EXT) GL_ENUM(0x9199,GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT) GL_ENUM(0x919A,GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT) GL_ENUM(0x91A9,GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT) GL_ENUM(0x822A,GL_R16_EXT) GL_ENUM(0x822C,GL_RG16_EXT) GL_ENUM(0x805B,GL_RGBA16_EXT) GL_ENUM(0x8054,GL_RGB16_EXT) GL_ENUM(0x8F9A,GL_RGB16_SNORM_EXT) GL_ENUM(0x8FBD,GL_SR8_EXT) GL_ENUM(0x8FBE,GL_SRG8_EXT) GL_ENUM(0x8A48,GL_TEXTURE_SRGB_DECODE_EXT) GL_ENUM(0x8A49,GL_DECODE_EXT) GL_ENUM(0x8A4A,GL_SKIP_DECODE_EXT) GL_ENUM(0x9260,GL_GCCSO_SHADER_BINARY_FJ) GL_ENUM(0x9130,GL_SGX_PROGRAM_BINARY_IMG) GL_ENUM(0x8C0A,GL_SGX_BINARY_IMG) GL_ENUM(0x9137,GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG) GL_ENUM(0x9138,GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG) GL_ENUM(0x9139,GL_CUBIC_IMG) GL_ENUM(0x913A,GL_CUBIC_MIPMAP_NEAREST_IMG) GL_ENUM(0x913B,GL_CUBIC_MIPMAP_LINEAR_IMG) GL_ENUM(0x00000000,GL_PERFQUERY_SINGLE_CONTEXT_INTEL) GL_ENUM(0x00000001,GL_PERFQUERY_GLOBAL_CONTEXT_INTEL) GL_ENUM(0x83FB,GL_PERFQUERY_WAIT_INTEL) GL_ENUM(0x83FA,GL_PERFQUERY_FLUSH_INTEL) GL_ENUM(0x83F9,GL_PERFQUERY_DONOT_FLUSH_INTEL) GL_ENUM(0x94F0,GL_PERFQUERY_COUNTER_EVENT_INTEL) GL_ENUM(0x94F1,GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL) GL_ENUM(0x94F2,GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL) GL_ENUM(0x94F3,GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL) GL_ENUM(0x94F4,GL_PERFQUERY_COUNTER_RAW_INTEL) GL_ENUM(0x94F5,GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL) GL_ENUM(0x94F8,GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL) GL_ENUM(0x94F9,GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL) GL_ENUM(0x94FA,GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL) GL_ENUM(0x94FB,GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL) GL_ENUM(0x94FC,GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL) GL_ENUM(0x94FD,GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL) GL_ENUM(0x94FE,GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL) GL_ENUM(0x94FF,GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL) GL_ENUM(0x9500,GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL) GL_ENUM(0x9281,GL_BLEND_OVERLAP_NV) GL_ENUM(0x9280,GL_BLEND_PREMULTIPLIED_SRC_NV) GL_ENUM(0x9284,GL_CONJOINT_NV) GL_ENUM(0x92A1,GL_CONTRAST_NV) GL_ENUM(0x9283,GL_DISJOINT_NV) GL_ENUM(0x928F,GL_DST_ATOP_NV) GL_ENUM(0x928B,GL_DST_IN_NV) GL_ENUM(0x9287,GL_DST_NV) GL_ENUM(0x928D,GL_DST_OUT_NV) GL_ENUM(0x9289,GL_DST_OVER_NV) GL_ENUM(0x92A9,GL_HARDMIX_NV) GL_ENUM(0x92B4,GL_INVERT_OVG_NV) GL_ENUM(0x92A3,GL_INVERT_RGB_NV) GL_ENUM(0x92A5,GL_LINEARBURN_NV) GL_ENUM(0x92A4,GL_LINEARDODGE_NV) GL_ENUM(0x92A7,GL_LINEARLIGHT_NV) GL_ENUM(0x92B3,GL_MINUS_CLAMPED_NV) GL_ENUM(0x929F,GL_MINUS_NV) GL_ENUM(0x92A8,GL_PINLIGHT_NV) GL_ENUM(0x92B2,GL_PLUS_CLAMPED_ALPHA_NV) GL_ENUM(0x92B1,GL_PLUS_CLAMPED_NV) GL_ENUM(0x9292,GL_PLUS_DARKER_NV) GL_ENUM(0x9291,GL_PLUS_NV) GL_ENUM(0x928E,GL_SRC_ATOP_NV) GL_ENUM(0x928A,GL_SRC_IN_NV) GL_ENUM(0x9286,GL_SRC_NV) GL_ENUM(0x928C,GL_SRC_OUT_NV) GL_ENUM(0x9288,GL_SRC_OVER_NV) GL_ENUM(0x9282,GL_UNCORRELATED_NV) GL_ENUM(0x92A6,GL_VIVIDLIGHT_NV) GL_ENUM(0x8E13,GL_QUERY_WAIT_NV) GL_ENUM(0x8E14,GL_QUERY_NO_WAIT_NV) GL_ENUM(0x8E15,GL_QUERY_BY_REGION_WAIT_NV) GL_ENUM(0x8E16,GL_QUERY_BY_REGION_NO_WAIT_NV) GL_ENUM(0x9346,GL_CONSERVATIVE_RASTERIZATION_NV) GL_ENUM(0x9347,GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV) GL_ENUM(0x9348,GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV) GL_ENUM(0x9349,GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV) GL_ENUM(0x8ED0,GL_COVERAGE_COMPONENT_NV) GL_ENUM(0x8ED1,GL_COVERAGE_COMPONENT4_NV) GL_ENUM(0x8ED2,GL_COVERAGE_ATTACHMENT_NV) GL_ENUM(0x8ED3,GL_COVERAGE_BUFFERS_NV) GL_ENUM(0x8ED4,GL_COVERAGE_SAMPLES_NV) GL_ENUM(0x8ED5,GL_COVERAGE_ALL_FRAGMENTS_NV) GL_ENUM(0x8ED6,GL_COVERAGE_EDGE_FRAGMENTS_NV) GL_ENUM(0x8ED7,GL_COVERAGE_AUTOMATIC_NV) GL_ENUM(0x8E2C,GL_DEPTH_COMPONENT16_NONLINEAR_NV) GL_ENUM(0x933C,GL_FILL_RECTANGLE_NV) GL_ENUM(0x92DD,GL_FRAGMENT_COVERAGE_TO_COLOR_NV) GL_ENUM(0x92DE,GL_FRAGMENT_COVERAGE_COLOR_NV) GL_ENUM(0x9331,GL_COVERAGE_MODULATION_TABLE_NV) GL_ENUM(0x8E20,GL_COLOR_SAMPLES_NV) GL_ENUM(0x932D,GL_DEPTH_SAMPLES_NV) GL_ENUM(0x932E,GL_STENCIL_SAMPLES_NV) GL_ENUM(0x932F,GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV) GL_ENUM(0x9330,GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV) GL_ENUM(0x9332,GL_COVERAGE_MODULATION_NV) GL_ENUM(0x9333,GL_COVERAGE_MODULATION_TABLE_SIZE_NV) GL_ENUM(0x9371,GL_MULTISAMPLES_NV) GL_ENUM(0x9372,GL_SUPERSAMPLE_SCALE_X_NV) GL_ENUM(0x9373,GL_SUPERSAMPLE_SCALE_Y_NV) GL_ENUM(0x9374,GL_CONFORMANT_NV) GL_ENUM(0x9070,GL_PATH_FORMAT_SVG_NV) GL_ENUM(0x9071,GL_PATH_FORMAT_PS_NV) GL_ENUM(0x9072,GL_STANDARD_FONT_NAME_NV) GL_ENUM(0x9073,GL_SYSTEM_FONT_NAME_NV) GL_ENUM(0x9074,GL_FILE_NAME_NV) GL_ENUM(0x9075,GL_PATH_STROKE_WIDTH_NV) GL_ENUM(0x9076,GL_PATH_END_CAPS_NV) GL_ENUM(0x9077,GL_PATH_INITIAL_END_CAP_NV) GL_ENUM(0x9078,GL_PATH_TERMINAL_END_CAP_NV) GL_ENUM(0x9079,GL_PATH_JOIN_STYLE_NV) GL_ENUM(0x907A,GL_PATH_MITER_LIMIT_NV) GL_ENUM(0x907B,GL_PATH_DASH_CAPS_NV) GL_ENUM(0x907C,GL_PATH_INITIAL_DASH_CAP_NV) GL_ENUM(0x907D,GL_PATH_TERMINAL_DASH_CAP_NV) GL_ENUM(0x907E,GL_PATH_DASH_OFFSET_NV) GL_ENUM(0x907F,GL_PATH_CLIENT_LENGTH_NV) GL_ENUM(0x9080,GL_PATH_FILL_MODE_NV) GL_ENUM(0x9081,GL_PATH_FILL_MASK_NV) GL_ENUM(0x9082,GL_PATH_FILL_COVER_MODE_NV) GL_ENUM(0x9083,GL_PATH_STROKE_COVER_MODE_NV) GL_ENUM(0x9084,GL_PATH_STROKE_MASK_NV) GL_ENUM(0x9088,GL_COUNT_UP_NV) GL_ENUM(0x9089,GL_COUNT_DOWN_NV) GL_ENUM(0x908A,GL_PATH_OBJECT_BOUNDING_BOX_NV) GL_ENUM(0x908B,GL_CONVEX_HULL_NV) GL_ENUM(0x908D,GL_BOUNDING_BOX_NV) GL_ENUM(0x908E,GL_TRANSLATE_X_NV) GL_ENUM(0x908F,GL_TRANSLATE_Y_NV) GL_ENUM(0x9090,GL_TRANSLATE_2D_NV) GL_ENUM(0x9091,GL_TRANSLATE_3D_NV) GL_ENUM(0x9092,GL_AFFINE_2D_NV) GL_ENUM(0x9094,GL_AFFINE_3D_NV) GL_ENUM(0x9096,GL_TRANSPOSE_AFFINE_2D_NV) GL_ENUM(0x9098,GL_TRANSPOSE_AFFINE_3D_NV) GL_ENUM(0x909A,GL_UTF8_NV) GL_ENUM(0x909B,GL_UTF16_NV) GL_ENUM(0x909C,GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV) GL_ENUM(0x909D,GL_PATH_COMMAND_COUNT_NV) GL_ENUM(0x909E,GL_PATH_COORD_COUNT_NV) GL_ENUM(0x909F,GL_PATH_DASH_ARRAY_COUNT_NV) GL_ENUM(0x90A0,GL_PATH_COMPUTED_LENGTH_NV) GL_ENUM(0x90A1,GL_PATH_FILL_BOUNDING_BOX_NV) GL_ENUM(0x90A2,GL_PATH_STROKE_BOUNDING_BOX_NV) GL_ENUM(0x90A3,GL_SQUARE_NV) GL_ENUM(0x90A4,GL_ROUND_NV) GL_ENUM(0x90A5,GL_TRIANGULAR_NV) GL_ENUM(0x90A6,GL_BEVEL_NV) GL_ENUM(0x90A7,GL_MITER_REVERT_NV) GL_ENUM(0x90A8,GL_MITER_TRUNCATE_NV) GL_ENUM(0x90A9,GL_SKIP_MISSING_GLYPH_NV) GL_ENUM(0x90AA,GL_USE_MISSING_GLYPH_NV) GL_ENUM(0x90AB,GL_PATH_ERROR_POSITION_NV) GL_ENUM(0x90AD,GL_ACCUM_ADJACENT_PAIRS_NV) GL_ENUM(0x90AE,GL_ADJACENT_PAIRS_NV) GL_ENUM(0x90AF,GL_FIRST_TO_REST_NV) GL_ENUM(0x90B0,GL_PATH_GEN_MODE_NV) GL_ENUM(0x90B1,GL_PATH_GEN_COEFF_NV) GL_ENUM(0x90B3,GL_PATH_GEN_COMPONENTS_NV) GL_ENUM(0x90B7,GL_PATH_STENCIL_FUNC_NV) GL_ENUM(0x90B8,GL_PATH_STENCIL_REF_NV) GL_ENUM(0x90B9,GL_PATH_STENCIL_VALUE_MASK_NV) GL_ENUM(0x90BD,GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV) GL_ENUM(0x90BE,GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV) GL_ENUM(0x90BF,GL_PATH_COVER_DEPTH_FUNC_NV) GL_ENUM(0x90B4,GL_PATH_DASH_OFFSET_RESET_NV) GL_ENUM(0x90B5,GL_MOVE_TO_RESETS_NV) GL_ENUM(0x90B6,GL_MOVE_TO_CONTINUES_NV) GL_ENUM(0x00,GL_CLOSE_PATH_NV) GL_ENUM(0x02,GL_MOVE_TO_NV) GL_ENUM(0x03,GL_RELATIVE_MOVE_TO_NV) GL_ENUM(0x04,GL_LINE_TO_NV) GL_ENUM(0x05,GL_RELATIVE_LINE_TO_NV) GL_ENUM(0x06,GL_HORIZONTAL_LINE_TO_NV) GL_ENUM(0x07,GL_RELATIVE_HORIZONTAL_LINE_TO_NV) GL_ENUM(0x08,GL_VERTICAL_LINE_TO_NV) GL_ENUM(0x09,GL_RELATIVE_VERTICAL_LINE_TO_NV) GL_ENUM(0x0A,GL_QUADRATIC_CURVE_TO_NV) GL_ENUM(0x0B,GL_RELATIVE_QUADRATIC_CURVE_TO_NV) GL_ENUM(0x0C,GL_CUBIC_CURVE_TO_NV) GL_ENUM(0x0D,GL_RELATIVE_CUBIC_CURVE_TO_NV) GL_ENUM(0x0E,GL_SMOOTH_QUADRATIC_CURVE_TO_NV) GL_ENUM(0x0F,GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV) GL_ENUM(0x10,GL_SMOOTH_CUBIC_CURVE_TO_NV) GL_ENUM(0x11,GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV) GL_ENUM(0x12,GL_SMALL_CCW_ARC_TO_NV) GL_ENUM(0x13,GL_RELATIVE_SMALL_CCW_ARC_TO_NV) GL_ENUM(0x14,GL_SMALL_CW_ARC_TO_NV) GL_ENUM(0x15,GL_RELATIVE_SMALL_CW_ARC_TO_NV) GL_ENUM(0x16,GL_LARGE_CCW_ARC_TO_NV) GL_ENUM(0x17,GL_RELATIVE_LARGE_CCW_ARC_TO_NV) GL_ENUM(0x18,GL_LARGE_CW_ARC_TO_NV) GL_ENUM(0x19,GL_RELATIVE_LARGE_CW_ARC_TO_NV) GL_ENUM(0xF0,GL_RESTART_PATH_NV) GL_ENUM(0xF2,GL_DUP_FIRST_CUBIC_CURVE_TO_NV) GL_ENUM(0xF4,GL_DUP_LAST_CUBIC_CURVE_TO_NV) GL_ENUM(0xF6,GL_RECT_NV) GL_ENUM(0xF8,GL_CIRCULAR_CCW_ARC_TO_NV) GL_ENUM(0xFA,GL_CIRCULAR_CW_ARC_TO_NV) GL_ENUM(0xFC,GL_CIRCULAR_TANGENT_ARC_TO_NV) GL_ENUM(0xFE,GL_ARC_TO_NV) GL_ENUM(0xFF,GL_RELATIVE_ARC_TO_NV) GL_ENUM(0xE8,GL_ROUNDED_RECT_NV) GL_ENUM(0xE9,GL_RELATIVE_ROUNDED_RECT_NV) GL_ENUM(0xEA,GL_ROUNDED_RECT2_NV) GL_ENUM(0xEB,GL_RELATIVE_ROUNDED_RECT2_NV) GL_ENUM(0xEC,GL_ROUNDED_RECT4_NV) GL_ENUM(0xED,GL_RELATIVE_ROUNDED_RECT4_NV) GL_ENUM(0xEE,GL_ROUNDED_RECT8_NV) GL_ENUM(0xEF,GL_RELATIVE_ROUNDED_RECT8_NV) GL_ENUM(0xF7,GL_RELATIVE_RECT_NV) GL_ENUM(0x9368,GL_FONT_GLYPHS_AVAILABLE_NV) GL_ENUM(0x9369,GL_FONT_TARGET_UNAVAILABLE_NV) GL_ENUM(0x936A,GL_FONT_UNAVAILABLE_NV) GL_ENUM(0x936B,GL_FONT_UNINTELLIGIBLE_NV) GL_ENUM(0x1A,GL_CONIC_CURVE_TO_NV) GL_ENUM(0x1B,GL_RELATIVE_CONIC_CURVE_TO_NV) GL_ENUM(0x936C,GL_STANDARD_FONT_FORMAT_NV) GL_ENUM(0x84E3,GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV) GL_ENUM(0x84E4,GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV) GL_ENUM(0x936D,GL_FRAGMENT_INPUT_NV) GL_ENUM(0xC0,GL_SHARED_EDGE_NV) GL_ENUM(0x0B40,GL_POLYGON_MODE_NV) GL_ENUM(0x2A01,GL_POLYGON_OFFSET_POINT_NV) GL_ENUM(0x2A02,GL_POLYGON_OFFSET_LINE_NV) GL_ENUM(0x1B00,GL_POINT_NV) GL_ENUM(0x1B01,GL_LINE_NV) GL_ENUM(0x1B02,GL_FILL_NV) GL_ENUM(0x8C46,GL_SLUMINANCE_NV) GL_ENUM(0x8C44,GL_SLUMINANCE_ALPHA_NV) GL_ENUM(0x8C47,GL_SLUMINANCE8_NV) GL_ENUM(0x8C45,GL_SLUMINANCE8_ALPHA8_NV) GL_ENUM(0x8C4C,GL_COMPRESSED_SRGB_S3TC_DXT1_NV) GL_ENUM(0x8C4D,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV) GL_ENUM(0x8C4E,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV) GL_ENUM(0x8C4F,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV) GL_ENUM(0x88EE,GL_ETC1_SRGB8_NV) GL_ENUM(0x933D,GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV) GL_ENUM(0x933E,GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV) GL_ENUM(0x933F,GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV) GL_ENUM(0x9340,GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV) GL_ENUM(0x9341,GL_PROGRAMMABLE_SAMPLE_LOCATION_NV) GL_ENUM(0x9342,GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV) GL_ENUM(0x9343,GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV) GL_ENUM(0x825B,GL_MAX_VIEWPORTS_NV) GL_ENUM(0x825C,GL_VIEWPORT_SUBPIXEL_BITS_NV) GL_ENUM(0x825D,GL_VIEWPORT_BOUNDS_RANGE_NV) GL_ENUM(0x825F,GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV) GL_ENUM(0x9630,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR) GL_ENUM(0x9632,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR) GL_ENUM(0x9631,GL_MAX_VIEWS_OVR) GL_ENUM(0x8FB0,GL_BINNING_CONTROL_HINT_QCOM) GL_ENUM(0x8FB1,GL_CPU_OPTIMIZED_QCOM) GL_ENUM(0x8FB2,GL_GPU_OPTIMIZED_QCOM) GL_ENUM(0x8FB3,GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM) GL_ENUM(0x8FC4,GL_SHADER_BINARY_VIV) opengl/libs/hooks.h0100644 0000000 0000000 00000005467 13077405420 013334 0ustar000000000 0000000 /* ** Copyright 2007, 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_GLES_CM_HOOKS_H #define ANDROID_GLES_CM_HOOKS_H #include #include #include #include #include #include #include #include #include #include #include #include #include // set to 1 for debugging #define USE_SLOW_BINDING 0 #undef NELEM #define NELEM(x) (sizeof(x)/sizeof(*(x))) // maximum number of GL extensions that can be used simultaneously in // a given process. this limitation exists because we need to have // a static function for each extension and currently these static functions // are generated at compile time. #define MAX_NUMBER_OF_GL_EXTENSIONS 256 #include /* special private C library header */ // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- // GL / EGL hooks #undef GL_ENTRY #undef EGL_ENTRY #define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__); #define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__); struct egl_t { #include "EGL/egl_entries.in" }; struct gl_hooks_t { struct gl_t { #include "entries.in" } gl; struct gl_ext_t { __eglMustCastToProperFunctionPointerType extensions[MAX_NUMBER_OF_GL_EXTENSIONS]; } ext; }; #undef GL_ENTRY #undef EGL_ENTRY EGLAPI void setGlThreadSpecific(gl_hooks_t const *value); // We have a dedicated TLS slot in bionic inline gl_hooks_t const * volatile * get_tls_hooks() { volatile void *tls_base = __get_tls(); gl_hooks_t const * volatile * tls_hooks = reinterpret_cast(tls_base); return tls_hooks; } inline EGLAPI gl_hooks_t const* getGlThreadSpecific() { gl_hooks_t const * volatile * tls_hooks = get_tls_hooks(); gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API]; return hooks; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif /* ANDROID_GLES_CM_HOOKS_H */ opengl/libs/tools/0040755 0000000 0000000 00000000000 13077405420 013167 5ustar000000000 0000000 opengl/libs/tools/genfiles0100755 0000000 0000000 00000003615 13077405420 014713 0ustar000000000 0000000 #! /bin/sh # # Copyright (C) 2008 Google Inc. # # 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. # Force a specific locale for sorting to avoid irrelevant differences # in the generated files that could hide real differences. export LC_ALL=POSIX ./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in ./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in ./glapigen ../../include/GLES3/gl3.h > ../GLES2/gl2_api.in ./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in ./glentrygen ../../include/GLES/gl.h > /tmp/gl_entries.in ./glentrygen ../../include/GLES/glext.h > /tmp/glext_entries.in ./glentrygen ../../include/GLES3/gl3.h > /tmp/gl2_entries.in ./glentrygen ../../include/GLES2/gl2ext.h > /tmp/gl2ext_entries.in # The awk command removes lines with the same function name as an earlier # line, even if the rest of the line differs. Although signatures of # functions with the same name should be the same, the different versions # have some irrelevant whitespace and parameter name differences. cat /tmp/gl_entries.in \ /tmp/glext_entries.in \ /tmp/gl2_entries.in \ /tmp/gl2ext_entries.in \ | sort -t, -k2 \ | awk -F, '!_[$2]++' \ > ../entries.in cat ../../include/GLES/gl.h \ ../../include/GLES/glext.h \ ../../include/GLES2/gl2ext.h \ ../../include/GLES3/gl3.h \ | ./glenumsgen \ | sort \ > ../enums.in opengl/libs/tools/glapigen0100755 0000000 0000000 00000003260 13077405420 014701 0ustar000000000 0000000 #! /usr/bin/perl # # Copyright (C) 2008 Google Inc. # # 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. use strict; sub rtrim($) { my $string = shift; $string =~ s/\s+$//; return $string; } while (my $line = <>) { next if $line =~ /^\//; next if $line =~ /^#/; next if $line =~ /^\s*$/; if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) { next; } my $type = rtrim($2); my $name = $3; my $args = $4; #printf("%s", $line); my $prefix = ""; if ($name eq "glGetString") { $prefix = "__"; } printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args); printf(" {\n"); if ($type eq "void") { printf(" CALL_GL_API(%s", $name); } else { printf(" CALL_GL_API_RETURN(%s", $name); } my @args = split ',', $args; my $len = scalar(@args); for (my $num = 0; $num < $len; $num++) { if ($args[$num] ne "void") { print ", "; # # extract the name from the parameter # type name # const type *name # type *name # type name[4] # if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) { printf("%s", $2); } } } printf(");\n"); printf("}\n"); } opengl/libs/tools/glentrygen0100755 0000000 0000000 00000001771 13077405420 015276 0ustar000000000 0000000 #! /usr/bin/perl # # Copyright (C) 2008 Google Inc. # # 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. use strict; sub rtrim($) { my $string = shift; $string =~ s/\s+$//; return $string; } while (my $line = <>) { next if $line =~ /^\//; next if $line =~ /^#/; next if $line =~ /^\s*$/; if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) { next; } my $type = rtrim($2); my $name = $3; my $args = $4; printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args); } opengl/libs/tools/glenumsgen0100755 0000000 0000000 00000001754 13077405420 015265 0ustar000000000 0000000 #! /usr/bin/perl # # Copyright (C) 2010 Google Inc. # # 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. use strict; my %enumHash = (); while (my $line = ) { next if $line =~ /^\//; # Skip bitfield definitions. next if $line =~ /_BIT(\d+_|\s+)/; if ($line !~ /^#define\s+(\S+)\s+(0x\S+)/) { next; } my $enumName = $1; my $enumValue = $2; next if exists($enumHash { $enumValue }); $enumHash { $enumValue } = $enumName; printf("GL_ENUM(%s,%s)\n", $enumValue, $enumName); } opengl/specs/0040755 0000000 0000000 00000000000 13077405420 012213 5ustar000000000 0000000 opengl/specs/EGL_ANDROID_blob_cache.txt0100644 0000000 0000000 00000020233 13077405420 016641 0ustar000000000 0000000 Name ANDROID_blob_cache Name Strings EGL_ANDROID_blob_cache Contributors Jamie Gennis Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Complete Version Version 3, December 13, 2012 Number EGL Extension #48 Dependencies Requires EGL 1.0 This extension is written against the wording of the EGL 1.4 Specification Overview Shader compilation and optimization has been a troublesome aspect of OpenGL programming for a long time. It can consume seconds of CPU cycles during application start-up. Additionally, state-based re-compiles done internally by the drivers add an unpredictable element to application performance tuning, often leading to occasional pauses in otherwise smooth animations. This extension provides a mechanism through which client API implementations may cache shader binaries after they are compiled. It may then retrieve those cached shaders during subsequent executions of the same program. The management of the cache is handled by the application (or middleware), allowing it to be tuned to a particular platform or environment. While the focus of this extension is on providing a persistent cache for shader binaries, it may also be useful for caching other data. This is perfectly acceptable, but the guarantees provided (or lack thereof) were designed around the shader use case. Note that although this extension is written as if the application implements the caching functionality, on the Android OS it is implemented as part of the Android EGL module. This extension is not exposed to applications on Android, but will be used automatically in every application that uses EGL if it is supported by the underlying device-specific EGL implementation. New Types /* * EGLsizeiANDROID is a signed integer type for representing the size of a * memory buffer. */ #include typedef khronos_ssize_t EGLsizeiANDROID; /* * EGLSetBlobFunc is a pointer to an application-provided function that a * client API implementation may use to insert a key/value pair into the * cache. */ typedef void (*EGLSetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) /* * EGLGetBlobFunc is a pointer to an application-provided function that a * client API implementation may use to retrieve a cached value from the * cache. */ typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) New Procedures and Functions void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); New Tokens None. Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) Add a new subsection after Section 3.8, page 50 (Synchronization Primitives) "3.9 Persistent Caching In order to facilitate persistent caching of internal client API state that is slow to compute or collect, the application may specify callback function pointers through which the client APIs can request data be cached and retrieved. The command void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); sets the callback function pointers that client APIs associated with display can use to interact with caching functionality provided by the application. points to a function that inserts a new value into the cache and associates it with the given key. points to a function that retrieves from the cache the value associated with a given key. The semantics of these callback functions are described in Section 3.9.1 (Cache Operations). Cache functions may only be specified once during the lifetime of an EGLDisplay. The and functions may be called at any time and from any thread from the time at which eglSetBlobCacheFuncsANDROID is called until the time that the last resource associated with is deleted and itself is terminated. Concurrent calls to these functions from different threads is also allowed. If eglSetBlobCacheFuncsANDROID generates an error then all client APIs must behave as though eglSetBlobCacheFuncsANDROID was not called for the display . If or is NULL then an EGL_BAD_PARAMETER error is generated. If a successful eglSetBlobCacheFuncsANDROID call was already made for and the display has not since been terminated then an EGL_BAD_PARAMETER error is generated. 3.9.1 Cache Operations To insert a new binary value into the cache and associate it with a given key, a client API implementation can call the application-provided callback function void (*set) (const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) and are pointers to the beginning of the key and value, respectively, that are to be inserted. and specify the size in bytes of the data pointed to by and , respectively. No guarantees are made as to whether a given key/value pair is present in the cache after the set call. If a different value has been associated with the given key in the past then it is undefined which value, if any, is associated with the key after the set call. Note that while there are no guarantees, the cache implementation should attempt to cache the most recently set value for a given key. To retrieve the binary value associated with a given key from the cache, a client API implementation can call the application-provided callback function EGLsizeiANDROID (*get) (const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) is a pointer to the beginning of the key. specifies the size in bytes of the binary key pointed to by . If the cache contains a value associated with the given key then the size of that binary value in bytes is returned. Otherwise 0 is returned. If the cache contains a value for the given key and its size in bytes is less than or equal to then the value is written to the memory pointed to by . Otherwise nothing is written to the memory pointed to by . Issues 1. How should errors be handled in the callback functions? RESOLVED: No guarantees are made about the presence of values in the cache, so there should not be a need to return error information to the client API implementation. The cache implementation can simply drop a value if it encounters an error during the 'set' callback. Similarly, it can simply return 0 if it encouters an error in a 'get' callback. 2. When a client API driver gets updated, that may need to invalidate previously cached entries. How can the driver handle this situation? RESPONSE: There are a number of ways the driver can handle this situation. The recommended way is to include the driver version in all cache keys. That way each driver version will use a set of cache keys that are unique to that version, and conflicts should never occur. Updating the driver could then leave a number of values in the cache that will never be requested again. If needed, the cache implementation can handle those values in some way, but the driver does not need to take any special action. 3. How much data can be stored in the cache? RESPONSE: This is entirely dependent upon the cache implementation. Presumably it will be tuned to store enough data to be useful, but not enough to become problematic. :) Revision History #3 (Jon Leech, December 13, 2012) - Fix typo in New Functions section & assign extension #. #2 (Jamie Gennis, April 25, 2011) - Swapped the order of the size and pointer arguments to the get and set functions. #1 (Jamie Gennis, April 22, 2011) - Initial draft. opengl/specs/EGL_ANDROID_create_native_client_buffer.txt0100644 0000000 0000000 00000020326 13077405420 022303 0ustar000000000 0000000 Name ANDROID_create_native_client_buffer Name Strings EGL_ANDROID_create_native_client_buffer Contributors Craig Donner Contact Craig Donner, Google Inc. (cdonner 'at' google.com) Status Draft Version Version 1, January 19, 2016 Number EGL Extension #XXX Dependencies Requires EGL 1.2. EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required. This extension is written against the wording of the EGL 1.2 Specification as modified by EGL_KHR_image_base and EGL_ANDROID_image_native_buffer. Overview This extension allows creating an EGLClientBuffer backed by an Android window buffer (struct ANativeWindowBuffer) which can be later used to create an EGLImage. New Types None. New Procedures and Functions EGLClientBuffer eglCreateNativeClientBufferANDROID( const EGLint *attrib_list) New Tokens EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) Add the following to section 2.5.1 "EGLImage Specification" (as modified by the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications), below the description of eglCreateImageKHR: "The command EGLClientBuffer eglCreateNativeClientBufferANDROID( const EGLint *attrib_list) may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer struct. EGL implementations must guarantee that the lifetime of the returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound to, following the lifetime semantics described below in section 2.5.2; the EGLClientBuffer must be destroyed no earlier than when all of its associated EGLImages are destroyed by eglDestroyImageKHR. is a list of attribute-value pairs which is used to specify the dimensions, format, and usage of the underlying buffer structure. If is non-NULL, the last attribute specified in the list must be EGL_NONE. Attribute names accepted in are shown in Table aaa, together with the for which each attribute name is valid, and the default value used for each attribute if it is not included in . +---------------------------------+----------------------+---------------+ | Attribute | Description | Default Value | | | | | +---------------------------------+----------------------+---------------+ | EGL_NONE | Marks the end of the | N/A | | | attribute-value list | | | EGL_WIDTH | The width of the | 0 | | | buffer data | | | EGL_HEIGHT | The height of the | 0 | | | buffer data | | | EGL_RED_SIZE | The bits of Red in | 0 | | | the color buffer | | | EGL_GREEN_SIZE | The bits of Green in | 0 | | | the color buffer | | | EGL_BLUE_SIZE | The bits of Blue in | 0 | | | the color buffer | | | EGL_ALPHA_SIZE | The bits of Alpha in | 0 | | | the color buffer | | | | buffer data | | | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of | 0 | | | the buffer data | | +---------------------------------+----------------------+---------------+ Table aaa. Legal attributes for eglCreateNativeClientBufferANDROID parameter. The maximum width and height may depend on the amount of available memory, which may also depend on the format and usage flags. The values of EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE is non-zero then the combination of all four sizes must correspond to a valid pixel format for the implementation. The EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of the following bits: EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the created buffer must have a hardware-protected path to external display sink. If a hardware-protected path is not available, then either don't composite only this buffer (preferred) to the external sink, or (less desirable) do not route the entire composition to the external sink. EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be used to create a renderbuffer. This flag must not be set if EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID is set. EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to create a texture. This flag must not be set if EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID is set. Errors If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no memory will be allocated, and one of the following errors will be generated: * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error EGL_BAD_PARAMETER is generated. * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the EGL implementation, the error EGL_BAD_PARAMETER is generated. * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination of gralloc usage flags for the EGL implementation, or is incompatible with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is Generated. * If both the EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID and EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID are set in the value of EGL_NATIVE_BUFFER_USAGE_ANDROID, the error EGL_BAD_PARAMETER is Generated." Issues 1. Should this extension define what combinations of formats and usage flags EGL implementations are required to support? RESOLVED: Partially. The set of valid color combinations is implementation-specific and may depend on additional EGL extensions, but generally RGB565 and RGBA888 should be supported. The particular valid combinations for a given Android version and implementation should be documented by that version. 2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the client buffers created by this extension? RESOLVED: No. A destroy function would add several complications: a) ANativeWindowBuffer is a reference counted object, may be used outside of EGL. b) The same buffer may back multiple EGLImages, though this usage may result in undefined behavior. c) The interactions between the lifetimes of EGLImages and their EGLClientBuffers would become needlessly complex. Because ANativeWindowBuffer is a reference counted object, implementations of this extension should ensure the buffer has a lifetime at least as long as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest method is to increment the reference count of the buffer in eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should ensure proper lifetime semantics. Revision History #2 (Craig Donner, April 15, 2016) - Set color formats and usage bits explicitly using additional attributes, and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID. #1 (Craig Donner, January 19, 2016) - Initial draft. opengl/specs/EGL_ANDROID_framebuffer_target.txt0100644 0000000 0000000 00000006121 13077405420 020432 0ustar000000000 0000000 Name ANDROID_framebuffer_target Name Strings EGL_ANDROID_framebuffer_target Contributors Jamie Gennis Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Complete Version Version 1, September 20, 2012 Number EGL Extension #47 Dependencies Requires EGL 1.0 This extension is written against the wording of the EGL 1.4 Specification Overview Android supports a number of different ANativeWindow implementations that can be used to create an EGLSurface. One implementation, which is used to send the result of performing window composition to a display, may have some device-specific restrictions. Because of this, some EGLConfigs may be incompatible with these ANativeWindows. This extension introduces a new boolean EGLConfig attribute that indicates whether the EGLConfig supports rendering to an ANativeWindow for which the buffers are passed to the HWComposer HAL as a framebuffer target layer. New Types None. New Procedures and Functions None. New Tokens Accepted by the parameter of eglGetConfigAttrib and the parameter of eglChooseConfig: EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) Section 3.4, Configuration Management, add a row to Table 3.1. Attribute Type Notes ------------------------------ ------- --------------------------- EGL_FRAMEBUFFER_TARGET_ANDROID boolean whether use as a HWComposer framebuffer target layer is supported Section 3.4, Configuration Management, add a row to Table 3.4. Attribute Default Selection Sort Sort Criteria Order Priority ------------------------------ ------------- --------- ----- -------- EGL_FRAMEBUFFER_TARGET_ANDROID EGL_DONT_CARE Exact None Section 3.4, Configuration Management, add a paragraph at the end of the subsection titled Other EGLConfig Attribute Descriptions. EGL_FRAMEBUFFER_TARGET_ANDROID is a boolean indicating whether the config may be used to create an EGLSurface from an ANativeWindow for which the buffers are to be passed to HWComposer as a framebuffer target layer. Section 3.4.1, Querying Configurations, change the last paragraph as follow EGLConfigs are not sorted with respect to the parameters EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_CONFORMANT, EGL_LEVEL, EGL_NATIVE_RENDERABLE, EGL_MAX_SWAP_INTERVAL, EGL_MIN_SWAP_INTERVAL, EGL_RENDERABLE_TYPE, EGL_SURFACE_TYPE, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_BLUE_VALUE, and EGL_RECORDABLE_ANDROID. Issues Revision History #1 (Jamie Gennis, September 20, 2012) - Initial draft. opengl/specs/EGL_ANDROID_front_buffer_auto_refresh.txt0100644 0000000 0000000 00000002600 13077405420 022025 0ustar000000000 0000000 Name ANDROID_front_buffer_auto_refresh Name Strings EGL_ANDROID_front_buffer_auto_refresh Contributors Pablo Ceballos Contact Pablo Ceballos, Google Inc. (pceballos 'at' google.com) Status Draft Version Version 1, February 3, 2016 Number EGL Extension #XXX Dependencies Requires EGL 1.2 This extension is written against the wording of the EGL 1.5 Specification Overview This extension is intended for latency-sensitive applications that are doing front-buffer rendering. It allows them to indicate to the Android compositor that it should perform composition every time the display refreshes. This removes the overhead of having to notify the compositor that the window surface has been updated, but it comes at the cost of doing potentially unneeded composition work if the window surface has not been updated. New Types None New Procedures and Functions None New Tokens EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6 "Surface Attributes", page 43: If attribute is EGL_ANDROID_front_buffer_auto_refresh, then value specifies whether to enable or disable auto-refresh in the Android compositor when doing front-buffer rendering. Issues None Revision History #1 (Pablo Ceballos, February 3, 2016) - Initial draft. opengl/specs/EGL_ANDROID_image_native_buffer.txt0100644 0000000 0000000 00000005514 13077405420 020566 0ustar000000000 0000000 Name ANDROID_image_native_buffer Name Strings EGL_ANDROID_image_native_buffer Contributors Mathias Agopian Jamie Gennis Jesse Hall Contact Jesse Hall, Google Inc. (jessehall 'at' google.com) Status Complete Version Version 1, November 28, 2012 Number EGL Extension #49 Dependencies EGL 1.2 is required. EGL_KHR_image_base is required. This extension is written against the wording of the EGL 1.2 Specification. Overview This extension enables using an Android window buffer (struct ANativeWindowBuffer) as an EGLImage source. New Types None. New Procedures and Functions None. New Tokens Accepted by the parameter of eglCreateImageKHR: EGL_NATIVE_BUFFER_ANDROID 0x3140 Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) Add to section 2.5.1 "EGLImage Specification" (as defined by the EGL_KHR_image_base specification), in the description of eglCreateImageKHR: "Values accepted for are listed in Table aaa, below. +----------------------------+-----------------------------------------+ | | Notes | +----------------------------+-----------------------------------------+ | EGL_NATIVE_BUFFER_ANDROID | Used for ANativeWindowBuffer objects | +----------------------------+-----------------------------------------+ Table aaa. Legal values for eglCreateImageKHR parameter ... If is EGL_NATIVE_BUFFER_ANDROID, must be a valid display, must be EGL_NO_CONTEXT, must be a pointer to a valid ANativeWindowBuffer object (cast into the type EGLClientBuffer), and attributes other than EGL_IMAGE_PRESERVED_KHR are ignored." Add to the list of error conditions for eglCreateImageKHR: "* If is EGL_NATIVE_BUFFER_ANDROID and is not a pointer to a valid ANativeWindowBuffer, the error EGL_BAD_PARAMETER is generated. * If is EGL_NATIVE_BUFFER_ANDROID and is not EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated. * If is EGL_NATIVE_BUFFER_ANDROID and was created with properties (format, usage, dimensions, etc.) not supported by the EGL implementation, the error EGL_BAD_PARAMETER is generated." Issues 1. Should this extension define what combinations of ANativeWindowBuffer properties implementations are required to support? RESOLVED: No. The requirements have evolved over time and will continue to change with future Android releases. The minimum requirements for a given Android version should be documented by that version. Revision History #1 (Jesse Hall, November 28, 2012) - Initial draft. opengl/specs/EGL_ANDROID_native_fence_sync.txt0100644 0000000 0000000 00000027401 13077405420 020266 0ustar000000000 0000000 Name ANDROID_native_fence_sync Name Strings EGL_ANDROID_native_fence_sync Contributors Jamie Gennis Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Complete Version Version 3, September 4, 2012 Number EGL Extension #50 Dependencies Requires EGL 1.1 This extension is written against the wording of the EGL 1.2 Specification EGL_KHR_fence_sync is required. Overview This extension enables the creation of EGL fence sync objects that are associated with a native synchronization fence object that is referenced using a file descriptor. These EGL fence sync objects have nearly identical semantics to those defined by the KHR_fence_sync extension, except that they have an additional attribute storing the file descriptor referring to the native fence object. This extension assumes the existence of a native fence synchronization object that behaves similarly to an EGL fence sync object. These native objects must have a signal status like that of an EGLSyncKHR object that indicates whether the fence has ever been signaled. Once signaled the native object's signal status may not change again. New Types None. New Procedures and Functions EGLint eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR); New Tokens Accepted by the parameter of eglCreateSyncKHR, and returned in when eglGetSyncAttribKHR is called with EGL_SYNC_TYPE_KHR: EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 Accepted by the parameter of eglCreateSyncKHR: EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 Accepted by the parameter of eglCreateSyncKHR, and returned by eglDupNativeFenceFDANDROID in the event of an error: EGL_NO_NATIVE_FENCE_FD_ANDROID -1 Returned in when eglGetSyncAttribKHR is called with EGL_SYNC_CONDITION_KHR: EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) Add the following after the sixth paragraph of Section 3.8.1 (Sync Objects), added by KHR_fence_sync "If is EGL_SYNC_NATIVE_FENCE_ANDROID, an EGL native fence sync object is created. In this case the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute may optionally be specified. If this attribute is specified, it must be set to either a file descriptor that refers to a native fence object or to the value EGL_NO_NATIVE_FENCE_FD_ANDROID. The default values for the EGL native fence sync object attributes are as follows: Attribute Name Initial Attribute Value(s) --------------- -------------------------- EGL_SYNC_TYPE_KHR EGL_SYNC_NATIVE_FENCE_ANDROID EGL_SYNC_STATUS_KHR EGL_UNSIGNALED_KHR EGL_SYNC_CONDITION_KHR EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR EGL_SYNC_NATIVE_FENCE_FD_ANDROID EGL_NO_NATIVE_FENCE_FD_ANDROID If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute is not EGL_NO_NATIVE_FENCE_FD_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is set to EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR attribute is set to reflect the signal status of the native fence object. Additionally, the EGL implementation assumes ownership of the file descriptor, so the caller must not use it after calling eglCreateSyncKHR." Modify Section 3.8.1 (Sync Objects), added by KHR_fence_sync, starting at the seventh paragraph "When a fence sync object is created or when an EGL native fence sync object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set to EGL_NO_NATIVE_FENCE_FD_ANDROID, eglCreateSyncKHR also inserts a fence command into the command stream of the bound client API's current context (i.e., the context returned by eglGetCurrentContext), and associates it with the newly created sync object. After associating the fence command with an EGL native fence sync object, the next Flush() operation performed by the current client API causes a new native fence object to be created, and the EGL_SYNC_NATIVE_FENCE_ANDROID attribute of the EGL native fence object is set to a file descriptor that refers to the new native fence object. This new native fence object is signaled when the EGL native fence sync object is signaled. When the condition of the sync object is satisfied by the fence command, the sync is signaled by the associated client API context, causing any eglClientWaitSyncKHR commands (see below) blocking on to unblock. If the sync object is an EGL native fence sync object then the native fence object is also signaled when the condition is satisfied. The EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR condition is satisfied by completion of the fence command corresponding to the sync object and all preceding commands in the associated client API context's command stream. The sync object will not be signaled until all effects from these commands on the client API's internal and framebuffer state are fully realized. No other state is affected by execution of the fence command. The EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID condition is satisfied by the signaling of the native fence object referred to by the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute. When this happens any eglClientWaitSyncKHR commands blocking on unblock." Modify the list of eglCreateSyncKHR errors in Section 3.8.1 (Sync Objects), added by KHR_fence_sync "Errors ------ * If is not the name of a valid, initialized EGLDisplay, EGL_NO_SYNC_KHR is returned and an EGL_BAD_DISPLAY error is generated. * If is EGL_SYNC_FENCE_KHR and is neither NULL nor empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is generated. * If is EGL_SYNC_NATIVE_FENCE_ANDROID and contains an attribute other than EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is generated. * If is not a supported type of sync object, EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is generated. * If is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and no context is current for the bound API (i.e., eglGetCurrentContext returns EGL_NO_CONTEXT), EGL_NO_SYNC_KHR is returned and an EGL_BAD_MATCH error is generated. * If is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and does not match the EGLDisplay of the currently bound context for the currently bound client API (the EGLDisplay returned by eglGetCurrentDisplay()) then EGL_NO_SYNC_KHR is returned and an EGL_BAD_MATCH error is generated. * If is EGL_SYNC_FENCE_KHR or EGL_SYNC_NATIVE_FENCE_ANDROID and the currently bound client API does not support the client API extension indicating it can place fence commands, then EGL_NO_SYNC_KHR is returned and an EGL_BAD_MATCH error is generated." Modify table 3.cc in Section 3.8.1 (Sync Objects), added by KHR_fence_sync " Attribute Description Supported Sync Objects ----------------- ----------------------- ---------------------- EGL_SYNC_TYPE_KHR Type of the sync object All EGL_SYNC_STATUS_KHR Status of the sync object All EGL_SYNC_CONDITION_KHR Signaling condition EGL_SYNC_FENCE_KHR and EGL_SYNC_NATIVE_FENCE_ANDROID only " Modify the second paragraph description of eglDestroySyncKHR in Section 3.8.1 (Sync Objects), added by KHR_fence_sync "If no errors are generated, EGL_TRUE is returned, and will no longer be the handle of a valid sync object. Additionally, if is an EGL native fence sync object and the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute is not EGL_NO_NATIVE_FENCE_FD_ANDROID then that file descriptor is closed." Add the following after the last paragraph of Section 3.8.1 (Sync Objects), added by KHR_fence_sync The command EGLint eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR sync); duplicates the file descriptor stored in the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of an EGL native fence sync object and returns the new file descriptor. Errors ------ * If is not a valid sync object for , EGL_NO_NATIVE_FENCE_FD_ANDROID is returned and an EGL_BAD_PARAMETER error is generated. * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of is EGL_NO_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID is returned and an EGL_BAD_PARAMETER error is generated. * If does not match the display passed to eglCreateSyncKHR when was created, the behaviour is undefined." Issues 1. Should EGLSyncKHR objects that wrap native fence objects use the EGL_SYNC_FENCE_KHR type? RESOLVED: A new sync object type will be added. We don't want to require all EGL fence sync objects to wrap native fence objects, so we need some way to tell the EGL implementation at sync object creation whether the sync object should support querying the native fence FD attribute. We could do this with either a new sync object type or with a boolean attribute. It might be nice to pick up future signaling conditions that might be added for fence sync objects, but there may be things that get added that don't make sense in the context of native fence objects. 2. Who is responsible for dup'ing the native fence file descriptors? RESOLVED: Whenever a file descriptor is passed into or returned from an EGL call in this extension, ownership of that file descriptor is transfered. The recipient of the file descriptor must close it when it is no longer needed, and the provider of the file descriptor must dup it before providing it if they require continued use of the native fence. 3. Can the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute be queried? RESOLVED: No. Returning the file descriptor owned by the EGL implementation would violate the file descriptor ownership rule described in issue #2. Having eglGetSyncAttribKHR return a different (dup'd) file descriptor each time it's called seems wrong, so a new function was added to explicitly dup the file descriptor. That said, the attribute is useful both as a way to pass an existing file descriptor to eglCreateSyncKHR and as a way to describe the subsequent behavior of EGL native fence sync objects, so it is left as an attribute for which the value cannot be queried. Revision History #3 (Jamie Gennis, September 4, 2012) - Reworded the extension to refer to "native fence" objects rather than "Android fence" objects. - Added a paragraph to the overview that describes assumptions about the native fence sync objects. #2 (Jamie Gennis, July 23, 2012) - Changed the file descriptor ownership transferring behavior. - Added the eglDupAndroidFenceFDANDROID function. - Removed EGL_SYNC_NATIVE_FENCE_FD_ANDROID from the table of gettable attributes. - Added language specifying that a native Android fence is created at the flush following the creation of an EGL Android fence sync object that is not passed an existing native fence. #1 (Jamie Gennis, May 29, 2012) - Initial draft. opengl/specs/EGL_ANDROID_presentation_time.txt0100644 0000000 0000000 00000010536 13077405420 020336 0ustar000000000 0000000 Name ANDROID_presentation_time Name Strings EGL_ANDROID_presentation_time Contributors Jamie Gennis Andy McFadden Jesse Hall Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Draft Version Version 3, June 26, 2013 Number EGL Extension #XXX Dependencies Requires EGL 1.1 This extension is written against the wording of the EGL 1.4 Specification Overview Often when rendering a sequence of images, there is some time at which each image is intended to be presented to the viewer. This extension allows this desired presentation time to be specified for each frame rendered to an EGLSurface, allowing the native window system to use it. New Types /* * EGLnsecsANDROID is a signed integer type for representing a time in * nanoseconds. */ #include typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; New Procedures and Functions EGLboolean eglPresentationTimeANDROID( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time); New Tokens None. Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) Add a new subsection before Section 3.9.4, page 53 (Posting Errors) "3.9.4 Presentation Time The function EGLboolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time); specifies the time at which the current color buffer of surface should be presented to the viewer. The time parameter should be a time in nanoseconds, but the exact meaning of the time depends on the native window system's use of the presentation time. In situations where an absolute time is needed such as displaying the color buffer on a display device, the time should correspond to the system monotonic up-time clock. For situations in which an absolute time is not needed such as using the color buffer for video encoding, the presentation time of the first frame may be arbitrarily chosen and those of subsequent frames chosen relative to that of the first frame. The presentation time may be set multiple times, with each call to eglPresentationTimeANDROID overriding prior calls. Setting the presentation time alone does not cause the color buffer to be made visible, but if the color buffer is subsequently posted to a native window or copied to a native pixmap then the presentation time of the surface at that time may be passed along for the native window system to use. If the surface presentation time is successfully set, EGL_TRUE is returned. Otherwise EGL_FALSE is returned and an appropriate error is set. If is not the name of a valid, initialized EGLDisplay, an EGL_BAD_DISPLAY error is generated. If is not a valid EGLSurface then an EGL_BAD_SURFACE error is generated. Issues 1. How is the presentation time used? RESOLVED: The uses of the presentation time are intentionally not specified in this extension. Some possible uses include Audio/Video synchronization, video frame timestamps for video encoding, display latency metrics, and display latency control. 2. How can the current value of the clock that should be used for the presentation time when an absolute time is needed be queried on Android? RESOLVED: The current clock value can be queried from the Java System.nanoTime() method, or from the native clock_gettime function by passing CLOCK_MONOTONIC as the clock identifier. 3. Should the presentation time be state which is used by eglSwapBuffers, or should it be a new parameter to an extended variant of eglSwapBuffers? RESOLVED: The presentation time should be new state which is used by the existing eglSwapBuffers call. Adding new state composes better with other (hypothetical) extensions that also modify the behavior of eglSwapBuffers. Revision History #3 (Jesse Hall, June 26, 2013) - Enumerated errors generated by eglPresentationTimeANDROID. - Added Issue #3 with resolution. #2 (Jamie Gennis, April 1, 2013) - Clarified how uses that either do or do not need an absolute time should be handled. - Specified the eglPresentationTimeANDROID return value. #1 (Jamie Gennis, January 8, 2013) - Initial draft. opengl/specs/EGL_ANDROID_recordable.txt0100644 0000000 0000000 00000011772 13077405420 016712 0ustar000000000 0000000 Name ANDROID_recordable Name Strings EGL_ANDROID_recordable Contributors Jamie Gennis Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Complete Version Version 2, July 15, 2011 Number EGL Extension #51 Dependencies Requires EGL 1.0 This extension is written against the wording of the EGL 1.4 Specification Overview Android supports a number of different ANativeWindow implementations that can be used to create an EGLSurface. One implementation, which records the rendered image as a video each time eglSwapBuffers gets called, may have some device-specific restrictions. Because of this, some EGLConfigs may be incompatible with these ANativeWindows. This extension introduces a new boolean EGLConfig attribute that indicates whether the EGLConfig supports rendering to an ANativeWindow that records images to a video. New Types None. New Procedures and Functions None. New Tokens Accepted by the parameter of eglGetConfigAttrib and the parameter of eglChooseConfig: EGL_RECORDABLE_ANDROID 0x3142 Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) Section 3.4, Configuration Management, add a row to Table 3.1. Attribute Type Notes ---------------------- ------- -------------------------- EGL_RECORDABLE_ANDROID boolean whether video recording is supported Section 3.4, Configuration Management, add a row to Table 3.4. Attribute Default Selection Sort Sort Criteria Order Priority ---------------------- ------------- --------- ----- -------- EGL_RECORDABLE_ANDROID EGL_DONT_CARE Exact None Section 3.4, Configuration Management, add a paragraph at the end of the subsection titled Other EGLConfig Attribute Descriptions. EGL_RECORDABLE_ANDROID is a boolean indicating whether the config may be used to create an EGLSurface from an ANativeWindow that is a video recorder as indicated by the NATIVE_WINDOW_IS_VIDEO_RECORDER query on the ANativeWindow. Section 3.4.1, Querying Configurations, change the last paragraph as follow EGLConfigs are not sorted with respect to the parameters EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_CONFORMANT, EGL_LEVEL, EGL_NATIVE_RENDERABLE, EGL_MAX_SWAP_INTERVAL, EGL_MIN_SWAP_INTERVAL, EGL_RENDERABLE_TYPE, EGL_SURFACE_TYPE, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_BLUE_VALUE, and EGL_RECORDABLE_ANDROID. Issues 1. Should this functionality be exposed as a new attribute or as a bit in the EGL_SURFACE_TYPE bitfield? RESOLVED: It should be a new attribute. It does not make sense to use up a bit in the limit-size bitfield for a platform-specific extension. 2. How should the new attribute affect the sorting of EGLConfigs? RESOLVED: It should not affect sorting. Some implementations may not have any drawback associated with using a recordable EGLConfig. Such implementations should not have to double-up some of their configs to one sort earlier than . Implementations that do have drawbacks can use the existing caveat mechanism to report this drawback to the client. 3. How is this extension expected to be implemented? RESPONSE: There are two basic approaches to implementing this extension that were considered during its design. In both cases it is assumed that a color space conversion must be performed at some point because most video encoding formats use a YUV color space. The two approaches are distinguished by the point at which this color space conversion is performed. One approach involves performing the color space conversion as part of the eglSwapBuffers call before queuing the rendered image to the ANativeWindow. In this case, the VisualID of the EGLConfig would correspond to a YUV Android HAL pixel format from which the video encoder can read. The EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that config to render normal window contents would result in an RGB -> YUV color space conversion when rendering the frame as well as a YUV -> RGB conversion when compositing the window. The other approach involves performing the color space conversion in the video encoder. In this case, the VisualID of the EGLConfig would correspond to an RGB HAL pixel format from which the video encoder can read. The EGLConfig would likely not need to have any caveat set, as using this config for normal window rendering would not have any added cost. Revision History #2 (Jamie Gennis, July 15, 2011) - Added issue 3. #1 (Jamie Gennis, July 8, 2011) - Initial draft. opengl/specs/README0100644 0000000 0000000 00000002606 13077405420 013074 0ustar000000000 0000000 This directory contains OpenGL ES and EGL extension specifications that have been or are being defined for Android. The table below tracks usage of EGL enumerant values that have been reserved for use by Android extensions. Value Extension ---------------- ---------------------------------- 0x3140 EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer) 0x3141 EGL_PLATFORM_ANDROID_KHR (KHR_platform_android) 0x3142 EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable) 0x3143 EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer) 0x3144 EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync) 0x3145 EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync) 0x3146 EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync) 0x3147 EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target) 0x3148 EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop) 0x3149 EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop) 0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop) 0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop) 0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh) 0x314D - 0x314F (unused) opengl/tests/0040755 0000000 0000000 00000000000 13077405420 012240 5ustar000000000 0000000 opengl/tests/Android.mk0100644 0000000 0000000 00000001160 13077405420 014144 0ustar000000000 0000000 dirs := \ angeles \ configdump \ EGLTest \ fillrate \ filter \ finish \ gl2_basic \ gl2_copyTexImage \ gl2_yuvtex \ gl_basic \ gl_perf \ gl_yuvtex \ gralloc \ hwc \ include \ lib \ linetex \ swapinterval \ textures \ tritex \ ifneq (,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL)) dirs += \ gl2_cameraeye \ gl2_java \ gl2_jni \ gldual \ gl_jni \ gl_perfapp \ lighting1709 \ testLatency \ testPauseResume \ testViewport \ endif # JAVA_SUPPORT ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL)) dirs += \ testFramerate endif # JAVA_SUPPORT platform include $(call all-named-subdir-makefiles, $(dirs)) opengl/tests/EGLTest/0040755 0000000 0000000 00000000000 13077405420 013507 5ustar000000000 0000000 opengl/tests/EGLTest/Android.mk0100644 0000000 0000000 00000001637 13077405420 015424 0ustar000000000 0000000 # Build the unit tests. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := EGL_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ egl_cache_test.cpp \ EGL_test.cpp \ LOCAL_SHARED_LIBRARIES := \ libEGL \ libcutils \ libbinder \ libutils \ libgui \ LOCAL_C_INCLUDES := \ bionic/libc/private \ frameworks/native/opengl/libs \ frameworks/native/opengl/libs/EGL \ # gold in binutils 2.22 will warn about the usage of mktemp LOCAL_LDFLAGS += -Wl,--no-fatal-warnings include $(BUILD_NATIVE_TEST) # Include subdirectory makefiles # ============================================================ # If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework # team really wants is to build the stuff defined by this makefile. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif opengl/tests/EGLTest/EGL_test.cpp0100644 0000000 0000000 00000012444 13077405420 015663 0ustar000000000 0000000 /* * 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 #include #include #include namespace android { class EGLTest : public ::testing::Test { protected: EGLDisplay mEglDisplay; protected: EGLTest() : mEglDisplay(EGL_NO_DISPLAY) { } virtual void SetUp() { mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EGLint majorVersion; EGLint minorVersion; EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); RecordProperty("EglVersionMajor", majorVersion); RecordProperty("EglVersionMajor", minorVersion); } virtual void TearDown() { EGLBoolean success = eglTerminate(mEglDisplay); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); } }; TEST_F(EGLTest, DISABLED_EGLConfigEightBitFirst) { EGLint numConfigs; EGLConfig config; EGLBoolean success; EGLint attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_GE(numConfigs, 1); EGLint components[3]; success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_GE(components[0], 8); EXPECT_GE(components[1], 8); EXPECT_GE(components[2], 8); } TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) { EGLint numConfigs; EGLConfig config; EGLint attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; // Create a EGLSurface sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); consumer->consumerConnect(new DummyConsumer, false); sp mSTC = new Surface(producer); sp mANW = mSTC; EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_NE(EGL_NO_SURFACE, eglSurface) ; // do not destroy eglSurface // eglTerminate is called in the tear down and should destroy it for us } TEST_F(EGLTest, EGLConfigRGBA8888First) { EGLint numConfigs; EGLConfig config; EGLBoolean success; EGLint attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_GE(numConfigs, 1); EGLint components[4]; success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); ASSERT_EQ(EGL_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_GE(components[0], 8); EXPECT_GE(components[1], 8); EXPECT_GE(components[2], 8); EXPECT_GE(components[3], 8); } } opengl/tests/EGLTest/egl_cache_test.cpp0100644 0000000 0000000 00000005757 13077405420 017157 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "EGL_test" //#define LOG_NDEBUG 0 #include #include #include "egl_cache.h" #include "egl_display.h" namespace android { class EGLCacheTest : public ::testing::Test { protected: virtual void SetUp() { mCache = egl_cache_t::get(); } virtual void TearDown() { mCache->setCacheFilename(""); mCache->terminate(); } egl_cache_t* mCache; }; TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) { uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->setBlob("abcd", 4, "efgh", 4); ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4)); ASSERT_EQ(0xee, buf[0]); ASSERT_EQ(0xee, buf[1]); ASSERT_EQ(0xee, buf[2]); ASSERT_EQ(0xee, buf[3]); } TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) { uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4)); ASSERT_EQ('e', buf[0]); ASSERT_EQ('f', buf[1]); ASSERT_EQ('g', buf[2]); ASSERT_EQ('h', buf[3]); } TEST_F(EGLCacheTest, TerminatedCacheAlwaysMisses) { uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); mCache->terminate(); ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4)); ASSERT_EQ(0xee, buf[0]); ASSERT_EQ(0xee, buf[1]); ASSERT_EQ(0xee, buf[2]); ASSERT_EQ(0xee, buf[3]); } class EGLCacheSerializationTest : public EGLCacheTest { protected: virtual void SetUp() { EGLCacheTest::SetUp(); char* tn = tempnam("/sdcard", "EGL_test-cache-"); mFilename = tn; free(tn); } virtual void TearDown() { unlink(mFilename.string()); EGLCacheTest::TearDown(); } String8 mFilename; }; TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) { uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->setCacheFilename(mFilename); mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); mCache->terminate(); mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4)); ASSERT_EQ('e', buf[0]); ASSERT_EQ('f', buf[1]); ASSERT_EQ('g', buf[2]); ASSERT_EQ('h', buf[3]); } } opengl/tests/angeles/0040755 0000000 0000000 00000000000 13077405420 013656 5ustar000000000 0000000 opengl/tests/angeles/Android.mk0100644 0000000 0000000 00000000614 13077405420 015565 0ustar000000000 0000000 # Copyright 2006 The Android Open Source Project LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui libgui libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= angeles LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL0100644 0000000 0000000 00000000000 13077405420 017621 0ustar000000000 0000000 opengl/tests/angeles/README.txt0100644 0000000 0000000 00000007036 13077405420 015357 0ustar000000000 0000000 ------------------------------------------------------------------------ San Angeles Observation OpenGL ES version example Copyright 2004-2005 Jetro Lauha Web: http://iki.fi/jetro/ See file license.txt for licensing information. ------------------------------------------------------------------------ This is an OpenGL ES port of the small self-running demonstration called "San Angeles Observation", which was first presented in the Assembly'2004 event. It won the first place in the 4 KB intro competition category. The demonstration features a sightseeing of a futuristic city having many different kind of buildings and items. Everything is flat shaded with three different lights. The original version was made for desktop with OpenGL. It was naturally heavily size optimized in order to fit it in the size limit. For this OpenGL ES version example much of the code is cleaned up and the sound is removed. Also detail level is lowered, although it still contains over 60000 faces. The Win32 (2000/XP) binary package of original version is available from this address: http://jet.ro/files/angeles.zip First version of this OpenGL ES port was submitted to the Khronos OpenGL ES Coding Challenge held in 2004-2005. As a code example, this source shows the following: * How to create a minimal and portable ad hoc framework for small testing/demonstration programs. This framework compiles for both desktop and PocketPC Win32 environment, and a separate source is included for Linux with X11. * How to dynamically find and use the OpenGL ES DLL or shared object, so that the library is not needed at the compile/link stage. * How to use the basic features of OpenGL ES 1.0/1.1 Common Lite, such as vertex arrays, color arrays and lighting. * How to create a self contained small demonstration application with objects generated using procedural algorithms. As the original version was optimized for size instead of performance, that holds true for this OpenGL ES version as well. Thus the performance could be significantly increased, for example by changing the code to use glDrawElements instead of glDrawArrays. The code uses only OpenGL ES 1.0 Common Lite -level function calls without any extensions. The reference OpenGL ES implementations used for this application: * Hybrid's OpenGL ES API Implementation (Gerbera) version 2.0.4 Prebuilt Win32 PC executable: SanOGLES-Gerbera.exe * PowerVR MBX SDK, OpenGL ES Windows PC Emulation version 1.04.14.0170 Prebuilt Win32 PC executable: SanOGLES-PVRSDK.exe Note that DISABLE_IMPORTGL preprocessor macro can be used to specify not to use dynamic runtime binding of the library. You also need to define preprocessor macro PVRSDK to compile the source with PowerVR OpenGL ES SDK. The demo application is briefly tested with a few other OpenGL ES implementations as well (e.g. Vincent, GLESonGL on Linux, Dell Axim X50v). Most of these other implementations rendered the demo erroneously in some aspect. This may indicate that the demo source could still have some work to do with compatibility and correct API usage, although the non-conforming implementations are most probably unfinished as well. Thanks and Acknowledgements: * Toni Lnnberg (!Cube) created the music for original version, which is not featured in this OpenGL ES port. * Sara Kapli (st Rana) for additional camera work. * Paul Bourke for information about the supershapes. ------------------------------------------------------------------------ opengl/tests/angeles/app-linux.cpp0100644 0000000 0000000 00000016313 13077405420 016300 0ustar000000000 0000000 /* San Angeles Observation OpenGL ES version example * Copyright 2004-2005 Jetro Lauha * All rights reserved. * Web: http://iki.fi/jetro/ * * This source is free software; you can redistribute it and/or * modify it under the terms of EITHER: * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this source in the * file LICENSE-LGPL.txt. * (2) The BSD-style license that is included with this source in * the file LICENSE-BSD.txt. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. * * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $ * $Revision: 1.4 $ * * Parts of this source file is based on test/example code from * GLESonGL implementation by David Blythe. Here is copy of the * license notice from that source: * * Copyright (C) 2003 David Blythe All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include using namespace android; #include "app.h" int gAppAlive = 1; static const char sAppName[] = "San Angeles Observation OpenGL ES version example (Linux)"; static int sWindowWidth = WINDOW_DEFAULT_WIDTH; static int sWindowHeight = WINDOW_DEFAULT_HEIGHT; static EGLDisplay sEglDisplay = EGL_NO_DISPLAY; static EGLContext sEglContext = EGL_NO_CONTEXT; static EGLSurface sEglSurface = EGL_NO_SURFACE; const char *egl_strerror(unsigned err) { switch(err){ case EGL_SUCCESS: return "SUCCESS"; case EGL_NOT_INITIALIZED: return "NOT INITIALIZED"; case EGL_BAD_ACCESS: return "BAD ACCESS"; case EGL_BAD_ALLOC: return "BAD ALLOC"; case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE"; case EGL_BAD_CONFIG: return "BAD CONFIG"; case EGL_BAD_CONTEXT: return "BAD CONTEXT"; case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE"; case EGL_BAD_DISPLAY: return "BAD DISPLAY"; case EGL_BAD_MATCH: return "BAD MATCH"; case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW"; case EGL_BAD_PARAMETER: return "BAD PARAMETER"; case EGL_BAD_SURFACE: return "BAD_SURFACE"; // case EGL_CONTEXT_LOST: return "CONTEXT LOST"; default: return "UNKNOWN"; } } void egl_error(const char *name) { unsigned err = eglGetError(); if(err != EGL_SUCCESS) { fprintf(stderr,"%s(): egl error 0x%x (%s)\n", name, err, egl_strerror(err)); } } static void checkGLErrors() { GLenum error = glGetError(); if (error != GL_NO_ERROR) fprintf(stderr, "GL Error: 0x%04x\n", (int)error); } static void checkEGLErrors() { EGLint error = eglGetError(); // GLESonGL seems to be returning 0 when there is no errors? if (error && error != EGL_SUCCESS) fprintf(stderr, "EGL Error: 0x%04x\n", (int)error); } static int initGraphics(EGLint samples, const WindowSurface& windowSurface) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 16, EGL_SAMPLE_BUFFERS, samples ? 1 : 0, EGL_SAMPLES, samples, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLSurface surface; EGLint w, h; EGLDisplay dpy; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); return 0; } surface = eglCreateWindowSurface(dpy, config, window, NULL); egl_error("eglCreateWindowSurface"); fprintf(stderr,"surface = %p\n", surface); context = eglCreateContext(dpy, config, NULL, NULL); egl_error("eglCreateContext"); fprintf(stderr,"context = %p\n", context); eglMakeCurrent(dpy, surface, surface, context); egl_error("eglMakeCurrent"); eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth); eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight); sEglDisplay = dpy; sEglSurface = surface; sEglContext = context; if (samples == 0) { // GL_MULTISAMPLE is enabled by default glDisable(GL_MULTISAMPLE); } return EGL_TRUE; } static void deinitGraphics() { eglMakeCurrent(sEglDisplay, NULL, NULL, NULL); eglDestroyContext(sEglDisplay, sEglContext); eglDestroySurface(sEglDisplay, sEglSurface); eglTerminate(sEglDisplay); } int main(int argc, char *argv[]) { unsigned samples = 0; printf("usage: %s [samples]\n", argv[0]); if (argc == 2) { samples = atoi( argv[1] ); printf("Multisample enabled: GL_SAMPLES = %u\n", samples); } WindowSurface windowSurface; if (!initGraphics(samples, windowSurface)) { fprintf(stderr, "Graphics initialization failed.\n"); return EXIT_FAILURE; } appInit(); struct timeval timeTemp; int frameCount = 0; gettimeofday(&timeTemp, NULL); double totalTime = timeTemp.tv_usec/1000000.0 + timeTemp.tv_sec; while (gAppAlive) { struct timeval timeNow; gettimeofday(&timeNow, NULL); appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000, sWindowWidth, sWindowHeight); checkGLErrors(); eglSwapBuffers(sEglDisplay, sEglSurface); checkEGLErrors(); frameCount++; } gettimeofday(&timeTemp, NULL); appDeinit(); deinitGraphics(); totalTime = (timeTemp.tv_usec/1000000.0 + timeTemp.tv_sec) - totalTime; printf("totalTime=%f s, frameCount=%d, %.2f fps\n", totalTime, frameCount, frameCount/totalTime); return EXIT_SUCCESS; } opengl/tests/angeles/app.h0100644 0000000 0000000 00000003070 13077405420 014604 0ustar000000000 0000000 /* San Angeles Observation OpenGL ES version example * Copyright 2004-2005 Jetro Lauha * All rights reserved. * Web: http://iki.fi/jetro/ * * This source is free software; you can redistribute it and/or * modify it under the terms of EITHER: * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this source in the * file LICENSE-LGPL.txt. * (2) The BSD-style license that is included with this source in * the file LICENSE-BSD.txt. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. * * $Id: app.h,v 1.14 2005/02/06 21:13:54 tonic Exp $ * $Revision: 1.14 $ */ #ifndef APP_H_INCLUDED #define APP_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define WINDOW_DEFAULT_WIDTH 640 #define WINDOW_DEFAULT_HEIGHT 480 #define WINDOW_BPP 16 // The simple framework expects the application code to define these functions. extern void appInit(); extern void appDeinit(); extern void appRender(long tick, int width, int height); /* Value is non-zero when application is alive, and 0 when it is closing. * Defined by the application framework. */ extern int gAppAlive; #ifdef __cplusplus } #endif #endif // !APP_H_INCLUDED opengl/tests/angeles/cams.h0100644 0000000 0000000 00000005016 13077405420 014751 0ustar000000000 0000000 /* San Angeles Observation OpenGL ES version example * Copyright 2004-2005 Jetro Lauha * All rights reserved. * Web: http://iki.fi/jetro/ * * This source is free software; you can redistribute it and/or * modify it under the terms of EITHER: * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this source in the * file LICENSE-LGPL.txt. * (2) The BSD-style license that is included with this source in * the file LICENSE-BSD.txt. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. * * $Id: cams.h,v 1.7 2005/01/31 22:15:15 tonic Exp $ * $Revision: 1.7 $ */ #ifndef CAMS_H_INCLUDED #define CAMS_H_INCLUDED /* Length in milliseconds of one camera track base unit. * The value originates from the music synchronization. */ #define CAMTRACK_LEN 5442 // Camera track definition for one camera trucking shot. typedef struct { /* Five parameters of src[5] and dest[5]: * eyeX, eyeY, eyeZ, viewAngle, viewHeightOffs */ short src[5], dest[5]; unsigned char dist; // if >0, cam rotates around eye xy on dist * 0.1 unsigned char len; // length multiplier } CAMTRACK; static CAMTRACK sCamTracks[] = { { { 4500, 2700, 100, 70, -30 }, { 50, 50, -90, -100, 0 }, 20, 1 }, { { -1448, 4294, 25, 363, 0 }, { -136, 202, 125, -98, 100 }, 0, 1 }, { { 1437, 4930, 200, -275, -20 }, { 1684, 0, 0, 9, 0 }, 0, 1 }, { { 1800, 3609, 200, 0, 675 }, { 0, 0, 0, 300, 0 }, 0, 1 }, { { 923, 996, 50, 2336, -80 }, { 0, -20, -50, 0, 170 }, 0, 1 }, { { -1663, -43, 600, 2170, 0 }, { 20, 0, -600, 0, 100 }, 0, 1 }, { { 1049, -1420, 175, 2111, -17 }, { 0, 0, 0, -334, 0 }, 0, 2 }, { { 0, 0, 50, 300, 25 }, { 0, 0, 0, 300, 0 }, 70, 2 }, { { -473, -953, 3500, -353, -350 }, { 0, 0, -2800, 0, 0 }, 0, 2 }, { { 191, 1938, 35, 1139, -17 }, { 1205, -2909, 0, 0, 0 }, 0, 2 }, { { -1449, -2700, 150, 0, 0 }, { 0, 2000, 0, 0, 0 }, 0, 2 }, { { 5273, 4992, 650, 373, -50 }, { -4598, -3072, 0, 0, 0 }, 0, 2 }, { { 3223, -3282, 1075, -393, -25 }, { 1649, -1649, 0, 0, 0 }, 0, 2 } }; #define CAMTRACK_COUNT (sizeof(camTracks) / sizeof(camTracks[0])) #endif // !CAMS_H_INCLUDED opengl/tests/angeles/demo.c0100644 0000000 0000000 00000055773 13077405420 014764 0ustar000000000 0000000 /* San Angeles Observation OpenGL ES version example * Copyright 2004-2005 Jetro Lauha * All rights reserved. * Web: http://iki.fi/jetro/ * * This source is free software; you can redistribute it and/or * modify it under the terms of EITHER: * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this source in the * file LICENSE-LGPL.txt. * (2) The BSD-style license that is included with this source in * the file LICENSE-BSD.txt. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. * * $Id: demo.c,v 1.10 2005/02/08 20:54:39 tonic Exp $ * $Revision: 1.10 $ */ #include #include #include #include #include #include "app.h" #include "shapes.h" #include "cams.h" // Total run length is 20 * camera track base unit length (see cams.h). #define RUN_LENGTH (20 * CAMTRACK_LEN) #undef PI #define PI 3.1415926535897932f #define RANDOM_UINT_MAX 65535 static unsigned long sRandomSeed = 0; static void seedRandom(unsigned long seed) { sRandomSeed = seed; } static unsigned long randomUInt() { sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3; return sRandomSeed >> 16; } // Capped conversion from float to fixed. static long floatToFixed(float value) { if (value < -32768) value = -32768; if (value > 32767) value = 32767; return (long)(value * 65536); } #define FIXED(value) floatToFixed(value) // Definition of one GL object in this demo. typedef struct { /* Vertex array and color array are enabled for all objects, so their * pointers must always be valid and non-NULL. Normal array is not * used by the ground plane, so when its pointer is NULL then normal * array usage is disabled. * * Vertex array is supposed to use GL_FIXED datatype and stride 0 * (i.e. tightly packed array). Color array is supposed to have 4 * components per color with GL_UNSIGNED_BYTE datatype and stride 0. * Normal array is supposed to use GL_FIXED datatype and stride 0. */ GLfixed *vertexArray; GLubyte *colorArray; GLfixed *normalArray; GLint vertexComponents; GLsizei count; } GLOBJECT; static long sStartTick = 0; static long sTick = 0; static int sCurrentCamTrack = 0; static long sCurrentCamTrackStartTick = 0; static long sNextCamTrackStartTick = 0x7fffffff; static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL }; static GLOBJECT *sGroundPlane = NULL; typedef struct { float x, y, z; } VECTOR3; static void freeGLObject(GLOBJECT *object) { if (object == NULL) return; free(object->normalArray); free(object->colorArray); free(object->vertexArray); free(object); } static GLOBJECT * newGLObject(long vertices, int vertexComponents, int useNormalArray) { GLOBJECT *result; result = (GLOBJECT *)malloc(sizeof(GLOBJECT)); if (result == NULL) return NULL; result->count = vertices; result->vertexComponents = vertexComponents; result->vertexArray = (GLfixed *)malloc(vertices * vertexComponents * sizeof(GLfixed)); result->colorArray = (GLubyte *)malloc(vertices * 4 * sizeof(GLubyte)); if (useNormalArray) { result->normalArray = (GLfixed *)malloc(vertices * 3 * sizeof(GLfixed)); } else result->normalArray = NULL; if (result->vertexArray == NULL || result->colorArray == NULL || (useNormalArray && result->normalArray == NULL)) { freeGLObject(result); return NULL; } return result; } static void drawGLObject(GLOBJECT *object) { assert(object != NULL); glVertexPointer(object->vertexComponents, GL_FIXED, 0, object->vertexArray); glColorPointer(4, GL_UNSIGNED_BYTE, 0, object->colorArray); // Already done in initialization: //glEnableClientState(GL_VERTEX_ARRAY); //glEnableClientState(GL_COLOR_ARRAY); if (object->normalArray) { glNormalPointer(GL_FIXED, 0, object->normalArray); glEnableClientState(GL_NORMAL_ARRAY); } else glDisableClientState(GL_NORMAL_ARRAY); glDrawArrays(GL_TRIANGLES, 0, object->count); } static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2) { dest->x = v1->x - v2->x; dest->y = v1->y - v2->y; dest->z = v1->z - v2->z; } static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p) { // sphere-mapping of supershape parameters point->x = (float)(cos(t) * cos(p) / r1 / r2); point->y = (float)(sin(t) * cos(p) / r1 / r2); point->z = (float)(sin(p) / r2); } static float ssFunc(const float t, const float *p) { return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) + pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3])); } // Creates and returns a supershape object. // Based on Paul Bourke's POV-Ray implementation. // http://astronomy.swin.edu.au/~pbourke/povray/supershape/ static GLOBJECT * createSuperShape(const float *params) { const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3]; const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2]; // latitude 0 to pi/2 for no mirrored bottom // (latitudeBegin==0 for -pi/2 to pi/2 originally) const int latitudeBegin = resol2 / 4; const int latitudeEnd = resol2 / 2; // non-inclusive const int longitudeCount = resol1; const int latitudeCount = latitudeEnd - latitudeBegin; const long triangleCount = longitudeCount * latitudeCount * 2; const long vertices = triangleCount * 3; GLOBJECT *result; float baseColor[3]; int a, longitude, latitude; long currentVertex, currentQuad; result = newGLObject(vertices, 3, 1); if (result == NULL) return NULL; for (a = 0; a < 3; ++a) baseColor[a] = ((randomUInt() % 155) + 100) / 255.f; currentQuad = 0; currentVertex = 0; // longitude -pi to pi for (longitude = 0; longitude < longitudeCount; ++longitude) { // latitude 0 to pi/2 for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude) { float t1 = -PI + longitude * 2 * PI / resol1; float t2 = -PI + (longitude + 1) * 2 * PI / resol1; float p1 = -PI / 2 + latitude * 2 * PI / resol2; float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2; float r0, r1, r2, r3; r0 = ssFunc(t1, params); r1 = ssFunc(p1, ¶ms[6]); r2 = ssFunc(t2, params); r3 = ssFunc(p2, ¶ms[6]); if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0) { VECTOR3 pa, pb, pc, pd; VECTOR3 v1, v2, n; float ca; int i; //float lenSq, invLenSq; superShapeMap(&pa, r0, r1, t1, p1); superShapeMap(&pb, r2, r1, t2, p1); superShapeMap(&pc, r2, r3, t2, p2); superShapeMap(&pd, r0, r3, t1, p2); // kludge to set lower edge of the object to fixed level if (latitude == latitudeBegin + 1) pa.z = pb.z = 0; vector3Sub(&v1, &pb, &pa); vector3Sub(&v2, &pd, &pa); // Calculate normal with cross product. /* i j k i j * v1.x v1.y v1.z | v1.x v1.y * v2.x v2.y v2.z | v2.x v2.y */ n.x = v1.y * v2.z - v1.z * v2.y; n.y = v1.z * v2.x - v1.x * v2.z; n.z = v1.x * v2.y - v1.y * v2.x; /* Pre-normalization of the normals is disabled here because * they will be normalized anyway later due to automatic * normalization (GL_NORMALIZE). It is enabled because the * objects are scaled with glScale. */ /* lenSq = n.x * n.x + n.y * n.y + n.z * n.z; invLenSq = (float)(1 / sqrt(lenSq)); n.x *= invLenSq; n.y *= invLenSq; n.z *= invLenSq; */ ca = pa.z + 0.5f; for (i = currentVertex * 3; i < (currentVertex + 6) * 3; i += 3) { result->normalArray[i] = FIXED(n.x); result->normalArray[i + 1] = FIXED(n.y); result->normalArray[i + 2] = FIXED(n.z); } for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4) { int a, color[3]; for (a = 0; a < 3; ++a) { color[a] = (int)(ca * baseColor[a] * 255); if (color[a] > 255) color[a] = 255; } result->colorArray[i] = (GLubyte)color[0]; result->colorArray[i + 1] = (GLubyte)color[1]; result->colorArray[i + 2] = (GLubyte)color[2]; result->colorArray[i + 3] = 0; } result->vertexArray[currentVertex * 3] = FIXED(pa.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pa.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pa.z); ++currentVertex; result->vertexArray[currentVertex * 3] = FIXED(pb.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); ++currentVertex; result->vertexArray[currentVertex * 3] = FIXED(pd.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); ++currentVertex; result->vertexArray[currentVertex * 3] = FIXED(pb.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); ++currentVertex; result->vertexArray[currentVertex * 3] = FIXED(pc.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pc.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pc.z); ++currentVertex; result->vertexArray[currentVertex * 3] = FIXED(pd.x); result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); ++currentVertex; } // r0 && r1 && r2 && r3 ++currentQuad; } // latitude } // longitude // Set number of vertices in object to the actual amount created. result->count = currentVertex; return result; } static GLOBJECT * createGroundPlane() { const int scale = 4; const int yBegin = -15, yEnd = 15; // ends are non-inclusive const int xBegin = -15, xEnd = 15; const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2; const long vertices = triangleCount * 3; GLOBJECT *result; int x, y; long currentVertex, currentQuad; result = newGLObject(vertices, 2, 0); if (result == NULL) return NULL; currentQuad = 0; currentVertex = 0; for (y = yBegin; y < yEnd; ++y) { for (x = xBegin; x < xEnd; ++x) { GLubyte color; int i, a; color = (GLubyte)((randomUInt() & 0x5f) + 81); // 101 1111 for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4) { result->colorArray[i] = color; result->colorArray[i + 1] = color; result->colorArray[i + 2] = color; result->colorArray[i + 3] = 0; } // Axis bits for quad triangles: // x: 011100 (0x1c), y: 110001 (0x31) (clockwise) // x: 001110 (0x0e), y: 100011 (0x23) (counter-clockwise) for (a = 0; a < 6; ++a) { const int xm = x + ((0x1c >> a) & 1); const int ym = y + ((0x31 >> a) & 1); const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f); result->vertexArray[currentVertex * 2] = FIXED(xm * scale + m); result->vertexArray[currentVertex * 2 + 1] = FIXED(ym * scale + m); ++currentVertex; } ++currentQuad; } } return result; } static void drawGroundPlane() { glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_COLOR); glDisable(GL_LIGHTING); drawGLObject(sGroundPlane); glEnable(GL_LIGHTING); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } static void drawFadeQuad() { static const GLfixed quadVertices[] = { -0x10000, -0x10000, 0x10000, -0x10000, -0x10000, 0x10000, 0x10000, -0x10000, 0x10000, 0x10000, -0x10000, 0x10000 }; const int beginFade = sTick - sCurrentCamTrackStartTick; const int endFade = sNextCamTrackStartTick - sTick; const int minFade = beginFade < endFade ? beginFade : endFade; if (minFade < 1024) { const GLfixed fadeColor = minFade << 6; glColor4x(fadeColor, fadeColor, fadeColor, 0); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_COLOR); glDisable(GL_LIGHTING); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glVertexPointer(2, GL_FIXED, 0, quadVertices); glDrawArrays(GL_TRIANGLES, 0, 6); glEnableClientState(GL_COLOR_ARRAY); glMatrixMode(GL_MODELVIEW); glEnable(GL_LIGHTING); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } } // Called from the app framework. void appInit() { int a; glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glShadeModel(GL_FLAT); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHT2); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); seedRandom(15); for (a = 0; a < SUPERSHAPE_COUNT; ++a) { sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]); assert(sSuperShapeObjects[a] != NULL); } sGroundPlane = createGroundPlane(); assert(sGroundPlane != NULL); } // Called from the app framework. void appDeinit() { int a; for (a = 0; a < SUPERSHAPE_COUNT; ++a) freeGLObject(sSuperShapeObjects[a]); freeGLObject(sGroundPlane); } static void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) { GLfloat xmin, xmax, ymin, ymax; ymax = zNear * (GLfloat)tan(fovy * PI / 360); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536), (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536), (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536)); } static void prepareFrame(int width, int height) { glViewport(0, 0, width, height); glClearColorx((GLfixed)(0.1f * 65536), (GLfixed)(0.2f * 65536), (GLfixed)(0.3f * 65536), 0x10000); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, (float)width / height, 0.5f, 150); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void configureLightAndMaterial() { static GLfixed light0Position[] = { -0x40000, 0x10000, 0x10000, 0 }; static GLfixed light0Diffuse[] = { 0x10000, 0x6666, 0, 0x10000 }; static GLfixed light1Position[] = { 0x10000, -0x20000, -0x10000, 0 }; static GLfixed light1Diffuse[] = { 0x11eb, 0x23d7, 0x5999, 0x10000 }; static GLfixed light2Position[] = { -0x10000, 0, -0x40000, 0 }; static GLfixed light2Diffuse[] = { 0x11eb, 0x2b85, 0x23d7, 0x10000 }; static GLfixed materialSpecular[] = { 0x10000, 0x10000, 0x10000, 0x10000 }; glLightxv(GL_LIGHT0, GL_POSITION, light0Position); glLightxv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); glLightxv(GL_LIGHT1, GL_POSITION, light1Position); glLightxv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse); glLightxv(GL_LIGHT2, GL_POSITION, light2Position); glLightxv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse); glMaterialxv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular); glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, 60 << 16); glEnable(GL_COLOR_MATERIAL); } static void drawModels(float zScale) { const int translationScale = 9; int x, y; seedRandom(9); glScalex(1 << 16, 1 << 16, (GLfixed)(zScale * 65536)); for (y = -5; y <= 5; ++y) { for (x = -5; x <= 5; ++x) { float buildingScale; GLfixed fixedScale; int curShape = randomUInt() % SUPERSHAPE_COUNT; buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1]; fixedScale = (GLfixed)(buildingScale * 65536); glPushMatrix(); glTranslatex((x * translationScale) * 65536, (y * translationScale) * 65536, 0); glRotatex((GLfixed)((randomUInt() % 360) << 16), 0, 0, 1 << 16); glScalex(fixedScale, fixedScale, fixedScale); drawGLObject(sSuperShapeObjects[curShape]); glPopMatrix(); } } for (x = -2; x <= 2; ++x) { const int shipScale100 = translationScale * 500; const int offs100 = x * shipScale100 + (sTick % shipScale100); float offs = offs100 * 0.01f; GLfixed fixedOffs = (GLfixed)(offs * 65536); glPushMatrix(); glTranslatex(fixedOffs, -4 * 65536, 2 << 16); drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); glPopMatrix(); glPushMatrix(); glTranslatex(-4 * 65536, fixedOffs, 4 << 16); glRotatex(90 << 16, 0, 0, 1 << 16); drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); glPopMatrix(); } } /* Following gluLookAt implementation is adapted from the * Mesa 3D Graphics library. http://www.mesa3d.org */ static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) { GLfloat m[16]; GLfloat x[3], y[3], z[3]; GLfloat mag; /* Make rotation matrix */ /* Z vector */ z[0] = eyex - centerx; z[1] = eyey - centery; z[2] = eyez - centerz; mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); if (mag) { /* mpichler, 19950515 */ z[0] /= mag; z[1] /= mag; z[2] /= mag; } /* Y vector */ y[0] = upx; y[1] = upy; y[2] = upz; /* X vector = Y cross Z */ x[0] = y[1] * z[2] - y[2] * z[1]; x[1] = -y[0] * z[2] + y[2] * z[0]; x[2] = y[0] * z[1] - y[1] * z[0]; /* Recompute Y = Z cross X */ y[0] = z[1] * x[2] - z[2] * x[1]; y[1] = -z[0] * x[2] + z[2] * x[0]; y[2] = z[0] * x[1] - z[1] * x[0]; /* mpichler, 19950515 */ /* cross product gives area of parallelogram, which is < 1.0 for * non-perpendicular unit-length vectors; so normalize x, y here */ mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); if (mag) { x[0] /= mag; x[1] /= mag; x[2] /= mag; } mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); if (mag) { y[0] /= mag; y[1] /= mag; y[2] /= mag; } #define M(row,col) m[col*4+row] M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0; M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0; M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0; M(3, 0) = 0.0; M(3, 1) = 0.0; M(3, 2) = 0.0; M(3, 3) = 1.0; #undef M { int a; GLfixed fixedM[16]; for (a = 0; a < 16; ++a) fixedM[a] = (GLfixed)(m[a] * 65536); glMultMatrixx(fixedM); } /* Translate Eye to Origin */ glTranslatex((GLfixed)(-eyex * 65536), (GLfixed)(-eyey * 65536), (GLfixed)(-eyez * 65536)); } static void camTrack() { float lerp[5]; float eX, eY, eZ, cX, cY, cZ; float trackPos; CAMTRACK *cam; long currentCamTick; int a; if (sNextCamTrackStartTick <= sTick) { ++sCurrentCamTrack; sCurrentCamTrackStartTick = sNextCamTrackStartTick; } sNextCamTrackStartTick = sCurrentCamTrackStartTick + sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN; cam = &sCamTracks[sCurrentCamTrack]; currentCamTick = sTick - sCurrentCamTrackStartTick; trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len); for (a = 0; a < 5; ++a) lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f; if (cam->dist) { float dist = cam->dist * 0.1f; cX = lerp[0]; cY = lerp[1]; cZ = lerp[2]; eX = cX - (float)cos(lerp[3]) * dist; eY = cY - (float)sin(lerp[3]) * dist; eZ = cZ - lerp[4]; } else { eX = lerp[0]; eY = lerp[1]; eZ = lerp[2]; cX = eX + (float)cos(lerp[3]); cY = eY + (float)sin(lerp[3]); cZ = eZ + lerp[4]; } gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1); } // Called from the app framework. /* The tick is current time in milliseconds, width and height * are the image dimensions to be rendered. */ void appRender(long tick, int width, int height) { if (sStartTick == 0) sStartTick = tick; if (!gAppAlive) return; // Actual tick value is "blurred" a little bit. sTick = (sTick + tick - sStartTick) >> 1; // Terminate application after running through the demonstration once. if (sTick >= RUN_LENGTH) { gAppAlive = 0; return; } // Prepare OpenGL ES for rendering of the frame. prepareFrame(width, height); // Update the camera position and set the lookat. camTrack(); // Configure environment. configureLightAndMaterial(); // Draw the reflection by drawing models with negated Z-axis. glPushMatrix(); drawModels(-1); glPopMatrix(); // Blend the ground plane to the window. drawGroundPlane(); // Draw all the models normally. drawModels(1); // Draw fade quad over whole window (when changing cameras). drawFadeQuad(); } opengl/tests/angeles/include/0040755 0000000 0000000 00000000000 13077405420 015301 5ustar000000000 0000000 opengl/tests/angeles/include/GLES/0040755 0000000 0000000 00000000000 13077405420 016033 5ustar000000000 0000000 opengl/tests/angeles/include/GLES/egl.h0100644 0000000 0000000 00000017475 13077405420 016766 0ustar000000000 0000000 #ifndef __egl_h_ #define __egl_h_ /* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.0 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: The application programming interfaces ** established by SGI in conjunction with the Original Code are The ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X ** Window System(R) (Version 1.3), released October 19, 1998. This software ** was created using the OpenGL(R) version 1.2.1 Sample Implementation ** published by SGI, but has not been independently verified as being ** compliant with the OpenGL(R) version 1.2.1 Specification. */ #include #include /* ** egltypes.h is platform dependent. It defines: ** ** - EGL types and resources ** - Native types ** - EGL and native handle values ** ** EGL types and resources are to be typedef'ed with appropriate platform ** dependent resource handle types. EGLint must be an integer of at least ** 32-bit. ** ** NativeDisplayType, NativeWindowType and NativePixmapType are to be ** replaced with corresponding types of the native window system in egl.h. ** ** EGL and native handle values must match their types. ** ** Example egltypes.h: */ #if 0 #include #include /* ** Types and resources */ typedef int EGLBoolean; typedef int32_t EGLint; typedef void *EGLDisplay; typedef void *EGLConfig; typedef void *EGLSurface; typedef void *EGLContext; /* ** EGL and native handle values */ #define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) #define EGL_NO_CONTEXT ((EGLContext)0) #define EGL_NO_DISPLAY ((EGLDisplay)0) #define EGL_NO_SURFACE ((EGLSurface)0) #endif /* ** Versioning and extensions */ #define EGL_VERSION_1_0 1 /* ** Boolean */ #define EGL_FALSE 0 #define EGL_TRUE 1 /* ** Errors */ #define EGL_SUCCESS 0x3000 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300A #define EGL_BAD_NATIVE_WINDOW 0x300B #define EGL_BAD_PARAMETER 0x300C #define EGL_BAD_SURFACE 0x300D /* 0x300E - 0x301F reserved for additional errors. */ /* ** Config attributes */ #define EGL_BUFFER_SIZE 0x3020 #define EGL_ALPHA_SIZE 0x3021 #define EGL_BLUE_SIZE 0x3022 #define EGL_GREEN_SIZE 0x3023 #define EGL_RED_SIZE 0x3024 #define EGL_DEPTH_SIZE 0x3025 #define EGL_STENCIL_SIZE 0x3026 #define EGL_CONFIG_CAVEAT 0x3027 #define EGL_CONFIG_ID 0x3028 #define EGL_LEVEL 0x3029 #define EGL_MAX_PBUFFER_HEIGHT 0x302A #define EGL_MAX_PBUFFER_PIXELS 0x302B #define EGL_MAX_PBUFFER_WIDTH 0x302C #define EGL_NATIVE_RENDERABLE 0x302D #define EGL_NATIVE_VISUAL_ID 0x302E #define EGL_NATIVE_VISUAL_TYPE 0x302F /*#define EGL_PRESERVED_RESOURCES 0x3030*/ #define EGL_SAMPLES 0x3031 #define EGL_SAMPLE_BUFFERS 0x3032 #define EGL_SURFACE_TYPE 0x3033 #define EGL_TRANSPARENT_TYPE 0x3034 #define EGL_TRANSPARENT_BLUE_VALUE 0x3035 #define EGL_TRANSPARENT_GREEN_VALUE 0x3036 #define EGL_TRANSPARENT_RED_VALUE 0x3037 /* ** Config attribute and value */ #define EGL_NONE 0x3038 /* 0x3039 - 0x304F reserved for additional config attributes. */ /* ** Config values */ #define EGL_DONT_CARE ((EGLint) -1) #define EGL_PBUFFER_BIT 0x01 #define EGL_PIXMAP_BIT 0x02 #define EGL_WINDOW_BIT 0x04 #define EGL_SLOW_CONFIG 0x3050 #define EGL_NON_CONFORMANT_CONFIG 0x3051 #define EGL_TRANSPARENT_RGB 0x3052 /* ** String names */ #define EGL_VENDOR 0x3053 #define EGL_VERSION 0x3054 #define EGL_EXTENSIONS 0x3055 /* ** Surface attributes */ #define EGL_HEIGHT 0x3056 #define EGL_WIDTH 0x3057 #define EGL_LARGEST_PBUFFER 0x3058 /* ** Current surfaces */ #define EGL_DRAW 0x3059 #define EGL_READ 0x305A /* ** Engines */ #define EGL_CORE_NATIVE_ENGINE 0x305B /* 0x305C-0x3FFFF reserved for future use */ /* ** Functions */ #ifdef __cplusplus extern "C" { #endif GLAPI EGLint APIENTRY eglGetError (void); GLAPI EGLDisplay APIENTRY eglGetDisplay (NativeDisplayType display); GLAPI EGLBoolean APIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor); GLAPI EGLBoolean APIENTRY eglTerminate (EGLDisplay dpy); GLAPI const char * APIENTRY eglQueryString (EGLDisplay dpy, EGLint name); GLAPI void (* APIENTRY eglGetProcAddress (const char *procname))(); GLAPI EGLBoolean APIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); GLAPI EGLBoolean APIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); GLAPI EGLBoolean APIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); GLAPI EGLSurface APIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list); GLAPI EGLSurface APIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list); GLAPI EGLSurface APIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); GLAPI EGLBoolean APIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface); GLAPI EGLBoolean APIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); GLAPI EGLContext APIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list); GLAPI EGLBoolean APIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx); GLAPI EGLBoolean APIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); GLAPI EGLContext APIENTRY eglGetCurrentContext (void); GLAPI EGLSurface APIENTRY eglGetCurrentSurface (EGLint readdraw); GLAPI EGLDisplay APIENTRY eglGetCurrentDisplay (void); GLAPI EGLBoolean APIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); GLAPI EGLBoolean APIENTRY eglWaitGL (void); GLAPI EGLBoolean APIENTRY eglWaitNative (EGLint engine); GLAPI EGLBoolean APIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface draw); GLAPI EGLBoolean APIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, NativePixmapType target); #ifdef __cplusplus } #endif #endif /* ___egl_h_ */ opengl/tests/angeles/include/GLES/egltypes.h0100644 0000000 0000000 00000000741 13077405420 020037 0ustar000000000 0000000 /* ** Types and resources */ typedef int EGLBoolean; typedef long EGLint; typedef void *EGLDisplay; typedef void *EGLConfig; typedef void *EGLSurface; typedef void *EGLContext; typedef void *NativeDisplayType; typedef void *NativeWindowType; typedef void *NativePixmapType; /* ** EGL and native handle values */ #define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) #define EGL_NO_CONTEXT ((EGLContext)0) #define EGL_NO_DISPLAY ((EGLDisplay)0) #define EGL_NO_SURFACE ((EGLSurface)0) opengl/tests/angeles/include/GLES/gl.h0100644 0000000 0000000 00000060373 13077405420 016614 0ustar000000000 0000000 #ifndef __gl_h_ #define __gl_h_ #ifdef __cplusplus extern "C" { #endif /* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.0 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: The application programming interfaces ** established by SGI in conjunction with the Original Code are The ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X ** Window System(R) (Version 1.3), released October 19, 1998. This software ** was created using the OpenGL(R) version 1.2.1 Sample Implementation ** published by SGI, but has not been independently verified as being ** compliant with the OpenGL(R) version 1.2.1 Specification. */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef GLAPI #define GLAPI extern #endif typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef signed char GLbyte; typedef short GLshort; typedef int GLint; typedef int GLsizei; typedef unsigned char GLubyte; typedef unsigned short GLushort; typedef unsigned int GLuint; typedef float GLfloat; typedef float GLclampf; typedef void GLvoid; typedef int GLintptrARB; typedef int GLsizeiptrARB; typedef int GLfixed; typedef int GLclampx; /* Internal convenience typedefs */ typedef void (*_GLfuncptr)(); /*************************************************************/ /* Extensions */ #define GL_OES_VERSION_1_0 1 #define GL_OES_read_format 1 #define GL_OES_compressed_paletted_texture 1 /* ClearBufferMask */ #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 /* Boolean */ #define GL_FALSE 0 #define GL_TRUE 1 /* BeginMode */ #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 /* AlphaFunction */ #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 /* BlendingFactorDest */ #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 /* BlendingFactorSrc */ /* GL_ZERO */ /* GL_ONE */ #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 /* GL_SRC_ALPHA */ /* GL_ONE_MINUS_SRC_ALPHA */ /* GL_DST_ALPHA */ /* GL_ONE_MINUS_DST_ALPHA */ /* ColorMaterialFace */ /* GL_FRONT_AND_BACK */ /* ColorMaterialParameter */ /* GL_AMBIENT_AND_DIFFUSE */ /* ColorPointerType */ /* GL_UNSIGNED_BYTE */ /* GL_FLOAT */ /* GL_FIXED */ /* CullFaceMode */ #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 /* DepthFunction */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* EnableCap */ #define GL_FOG 0x0B60 #define GL_LIGHTING 0x0B50 #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_ALPHA_TEST 0x0BC0 #define GL_BLEND 0x0BE2 #define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 /* GL_LIGHT0 */ /* GL_LIGHT1 */ /* GL_LIGHT2 */ /* GL_LIGHT3 */ /* GL_LIGHT4 */ /* GL_LIGHT5 */ /* GL_LIGHT6 */ /* GL_LIGHT7 */ #define GL_POINT_SMOOTH 0x0B10 #define GL_LINE_SMOOTH 0x0B20 #define GL_SCISSOR_TEST 0x0C11 #define GL_COLOR_MATERIAL 0x0B57 #define GL_NORMALIZE 0x0BA1 #define GL_RESCALE_NORMAL 0x803A #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 #define GL_COLOR_ARRAY 0x8076 #define GL_TEXTURE_COORD_ARRAY 0x8078 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 /* ErrorCode */ #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_OUT_OF_MEMORY 0x0505 /* FogMode */ /* GL_LINEAR */ #define GL_EXP 0x0800 #define GL_EXP2 0x0801 /* FogParameter */ #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_START 0x0B63 #define GL_FOG_END 0x0B64 #define GL_FOG_MODE 0x0B65 #define GL_FOG_COLOR 0x0B66 /* FrontFaceDirection */ #define GL_CW 0x0900 #define GL_CCW 0x0901 /* GetPName */ #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #define GL_MAX_LIGHTS 0x0D31 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 #define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 /* HintMode */ #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 /* HintTarget */ #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #define GL_POINT_SMOOTH_HINT 0x0C51 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_POLYGON_SMOOTH_HINT 0x0C53 #define GL_FOG_HINT 0x0C54 /* LightModelParameter */ #define GL_LIGHT_MODEL_AMBIENT 0x0B53 #define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 /* LightParameter */ #define GL_AMBIENT 0x1200 #define GL_DIFFUSE 0x1201 #define GL_SPECULAR 0x1202 #define GL_POSITION 0x1203 #define GL_SPOT_DIRECTION 0x1204 #define GL_SPOT_EXPONENT 0x1205 #define GL_SPOT_CUTOFF 0x1206 #define GL_CONSTANT_ATTENUATION 0x1207 #define GL_LINEAR_ATTENUATION 0x1208 #define GL_QUADRATIC_ATTENUATION 0x1209 /* DataType */ #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C /* LogicOp */ #define GL_CLEAR 0x1500 #define GL_AND 0x1501 #define GL_AND_REVERSE 0x1502 #define GL_COPY 0x1503 #define GL_AND_INVERTED 0x1504 #define GL_NOOP 0x1505 #define GL_XOR 0x1506 #define GL_OR 0x1507 #define GL_NOR 0x1508 #define GL_EQUIV 0x1509 #define GL_INVERT 0x150A #define GL_OR_REVERSE 0x150B #define GL_COPY_INVERTED 0x150C #define GL_OR_INVERTED 0x150D #define GL_NAND 0x150E #define GL_SET 0x150F /* MaterialFace */ /* GL_FRONT_AND_BACK */ /* MaterialParameter */ #define GL_EMISSION 0x1600 #define GL_SHININESS 0x1601 #define GL_AMBIENT_AND_DIFFUSE 0x1602 /* GL_AMBIENT */ /* GL_DIFFUSE */ /* GL_SPECULAR */ /* MatrixMode */ #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 #define GL_TEXTURE 0x1702 /* NormalPointerType */ /* GL_BYTE */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* PixelFormat */ #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A /* PixelStoreParameter */ #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 /* PixelType */ /* GL_UNSIGNED_BYTE */ #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 /* ShadingModel */ #define GL_FLAT 0x1D00 #define GL_SMOOTH 0x1D01 /* StencilFunction */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* StencilOp */ /* GL_ZERO */ #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 /* GL_INVERT */ /* StringName */ #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 /* TexCoordPointerType */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* GL_BYTE */ /* TextureEnvMode */ #define GL_MODULATE 0x2100 #define GL_DECAL 0x2101 /* GL_BLEND */ #define GL_ADD 0x0104 /* GL_REPLACE */ /* TextureEnvParameter */ #define GL_TEXTURE_ENV_MODE 0x2200 #define GL_TEXTURE_ENV_COLOR 0x2201 /* TextureEnvTarget */ #define GL_TEXTURE_ENV 0x2300 /* TextureMagFilter */ #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 /* TextureMinFilter */ /* GL_NEAREST */ /* GL_LINEAR */ #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 /* TextureParameterName */ #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 /* TextureTarget */ /* GL_TEXTURE_2D */ /* TextureUnit */ #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF /* TextureWrapMode */ #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F /* PixelInternalFormat */ #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 /* VertexPointerType */ /* GL_SHORT */ /* GL_FLOAT */ /* GL_FIXED */ /* GL_BYTE */ /* LightName */ #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 #define GL_LIGHT2 0x4002 #define GL_LIGHT3 0x4003 #define GL_LIGHT4 0x4004 #define GL_LIGHT5 0x4005 #define GL_LIGHT6 0x4006 #define GL_LIGHT7 0x4007 /*************************************************************/ GLAPI void APIENTRY glActiveTexture (GLenum texture); GLAPI void APIENTRY glAlphaFunc (GLenum func, GLclampf ref); GLAPI void APIENTRY glAlphaFuncx (GLenum func, GLclampx ref); GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GLAPI void APIENTRY glClear (GLbitfield mask); GLAPI void APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); GLAPI void APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); GLAPI void APIENTRY glClearDepthf (GLclampf depth); GLAPI void APIENTRY glClearDepthx (GLclampx depth); GLAPI void APIENTRY glClearStencil (GLint s); GLAPI void APIENTRY glClientActiveTexture (GLenum texture); GLAPI void APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI void APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GLAPI void APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glCullFace (GLenum mode); GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GLAPI void APIENTRY glDepthFunc (GLenum func); GLAPI void APIENTRY glDepthMask (GLboolean flag); GLAPI void APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); GLAPI void APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar); GLAPI void APIENTRY glDisable (GLenum cap); GLAPI void APIENTRY glDisableClientState (GLenum array); GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); GLAPI void APIENTRY glEnable (GLenum cap); GLAPI void APIENTRY glEnableClientState (GLenum array); GLAPI void APIENTRY glFinish (void); GLAPI void APIENTRY glFlush (void); GLAPI void APIENTRY glFogf (GLenum pname, GLfloat param); GLAPI void APIENTRY glFogfv (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFogx (GLenum pname, GLfixed param); GLAPI void APIENTRY glFogxv (GLenum pname, const GLfixed *params); GLAPI void APIENTRY glFrontFace (GLenum mode); GLAPI void APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GLAPI void APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); GLAPI GLenum APIENTRY glGetError (void); GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *params); GLAPI const GLubyte * APIENTRY glGetString (GLenum name); GLAPI void APIENTRY glHint (GLenum target, GLenum mode); GLAPI void APIENTRY glLightModelf (GLenum pname, GLfloat param); GLAPI void APIENTRY glLightModelfv (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glLightModelx (GLenum pname, GLfixed param); GLAPI void APIENTRY glLightModelxv (GLenum pname, const GLfixed *params); GLAPI void APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param); GLAPI void APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param); GLAPI void APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glLineWidth (GLfloat width); GLAPI void APIENTRY glLineWidthx (GLfixed width); GLAPI void APIENTRY glLoadIdentity (void); GLAPI void APIENTRY glLoadMatrixf (const GLfloat *m); GLAPI void APIENTRY glLoadMatrixx (const GLfixed *m); GLAPI void APIENTRY glLogicOp (GLenum opcode); GLAPI void APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param); GLAPI void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param); GLAPI void APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glMatrixMode (GLenum mode); GLAPI void APIENTRY glMultMatrixf (const GLfloat *m); GLAPI void APIENTRY glMultMatrixx (const GLfixed *m); GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI void APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); GLAPI void APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz); GLAPI void APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz); GLAPI void APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); GLAPI void APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); GLAPI void APIENTRY glPointSize (GLfloat size); GLAPI void APIENTRY glPointSizex (GLfixed size); GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GLAPI void APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units); GLAPI void APIENTRY glPopMatrix (void); GLAPI void APIENTRY glPushMatrix (void); GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); GLAPI void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); GLAPI void APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert); GLAPI void APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glShadeModel (GLenum mode); GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GLAPI void APIENTRY glStencilMask (GLuint mask); GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GLAPI void APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param); GLAPI void APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param); GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #ifdef __cplusplus } #endif #endif /* __gl_h_ */ opengl/tests/angeles/license-BSD.txt0100644 0000000 0000000 00000003414 13077405420 016446 0ustar000000000 0000000 This is the BSD-style license for the "San Angeles Observation" OpenGL ES version example source code --------------------------------------------------------------- San Angeles Observation OpenGL ES version example Copyright (c) 2004-2005, Jetro Lauha All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the software product's copyright owner nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. opengl/tests/angeles/license-LGPL.txt0100644 0000000 0000000 00000063476 13077405420 016612 0ustar000000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! opengl/tests/angeles/license.txt0100644 0000000 0000000 00000001572 13077405420 016043 0ustar000000000 0000000 San Angeles Observation OpenGL ES version example Copyright 2004-2005 Jetro Lauha All rights reserved. Web: http://iki.fi/jetro/ This source is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this source in the file LICENSE-LGPL.txt. (2) The BSD-style license that is included with this source in the file LICENSE-BSD.txt. This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. opengl/tests/angeles/shapes.h0100644 0000000 0000000 00000007064 13077405420 015316 0ustar000000000 0000000 /* San Angeles Observation OpenGL ES version example * Copyright 2004-2005 Jetro Lauha * All rights reserved. * Web: http://iki.fi/jetro/ * * This source is free software; you can redistribute it and/or * modify it under the terms of EITHER: * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this source in the * file LICENSE-LGPL.txt. * (2) The BSD-style license that is included with this source in * the file LICENSE-BSD.txt. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. * * $Id: shapes.h,v 1.6 2005/01/31 22:15:30 tonic Exp $ * $Revision: 1.6 $ */ #ifndef SHAPES_H_INCLUDED #define SHAPES_H_INCLUDED #define SUPERSHAPE_PARAMS 15 static const float sSuperShapeParams[][SUPERSHAPE_PARAMS] = { // m a b n1 n2 n3 m a b n1 n2 n3 res1 res2 scale (org.res1,res2) { 10, 1, 2, 90, 1, -45, 8, 1, 1, -1, 1, -0.4f, 20, 30, 2 }, // 40, 60 { 10, 1, 2, 90, 1, -45, 4, 1, 1, 10, 1, -0.4f, 20, 20, 4 }, // 40, 40 { 10, 1, 2, 60, 1, -10, 4, 1, 1, -1, -2, -0.4f, 41, 41, 1 }, // 82, 82 { 6, 1, 1, 60, 1, -70, 8, 1, 1, 0.4f, 3, 0.25f, 20, 20, 1 }, // 40, 40 { 4, 1, 1, 30, 1, 20, 12, 1, 1, 0.4f, 3, 0.25f, 10, 30, 1 }, // 20, 60 { 8, 1, 1, 30, 1, -4, 8, 2, 1, -1, 5, 0.5f, 25, 26, 1 }, // 60, 60 { 13, 1, 1, 30, 1, -4, 13, 1, 1, 1, 5, 1, 30, 30, 6 }, // 60, 60 { 10, 1, 1.1f, -0.5f, 0.1f, 70, 60, 1, 1, -90, 0, -0.25f, 20, 60, 8 }, // 60, 180 { 7, 1, 1, 20, -0.3f, -3.5f, 6, 1, 1, -1, 4.5f, 0.5f, 10, 20, 4 }, // 60, 80 { 4, 1, 1, 10, 10, 10, 4, 1, 1, 10, 10, 10, 10, 20, 1 }, // 20, 40 { 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 10, 10, 2 }, // 10, 10 { 1, 1, 1, 38, -0.25f, 19, 4, 1, 1, 10, 10, 10, 10, 15, 2 }, // 20, 40 { 2, 1, 1, 0.7f, 0.3f, 0.2f, 3, 1, 1, 100, 100, 100, 10, 25, 2 }, // 20, 50 { 6, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 30, 30, 2 }, // 60, 60 { 3, 1, 1, 1, 1, 1, 6, 1, 1, 2, 1, 1, 10, 20, 2 }, // 20, 40 { 6, 1, 1, 6, 5.5f, 100, 6, 1, 1, 25, 10, 10, 30, 20, 2 }, // 60, 40 { 3, 1, 1, 0.5f, 1.7f, 1.7f, 2, 1, 1, 10, 10, 10, 20, 20, 2 }, // 40, 40 { 5, 1, 1, 0.1f, 1.7f, 1.7f, 1, 1, 1, 0.3f, 0.5f, 0.5f, 20, 20, 4 }, // 40, 40 { 2, 1, 1, 6, 5.5f, 100, 6, 1, 1, 4, 10, 10, 10, 22, 1 }, // 40, 40 { 6, 1, 1, -1, 70, 0.1f, 9, 1, 0.5f, -98, 0.05f, -45, 20, 30, 4 }, // 60, 91 { 6, 1, 1, -1, 90, -0.1f, 7, 1, 1, 90, 1.3f, 34, 13, 16, 1 }, // 32, 60 }; #define SUPERSHAPE_COUNT (sizeof(sSuperShapeParams) / sizeof(sSuperShapeParams[0])) #endif // !SHAPES_H_INCLUDED opengl/tests/configdump/0040755 0000000 0000000 00000000000 13077405420 014373 5ustar000000000 0000000 opengl/tests/configdump/Android.mk0100644 0000000 0000000 00000000402 13077405420 016275 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ configdump.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv1_CM LOCAL_MODULE:= test-opengl-configdump LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/configdump/configdump.cpp0100644 0000000 0000000 00000005513 13077405420 017233 0ustar000000000 0000000 /* ** Copyright 2010, 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 #include #include #define ATTRIBUTE(_attr) { _attr, #_attr } struct Attribute { EGLint attribute; char const* name; }; Attribute attributes[] = { ATTRIBUTE( EGL_BUFFER_SIZE ), ATTRIBUTE( EGL_ALPHA_SIZE ), ATTRIBUTE( EGL_BLUE_SIZE ), ATTRIBUTE( EGL_GREEN_SIZE ), ATTRIBUTE( EGL_RED_SIZE ), ATTRIBUTE( EGL_DEPTH_SIZE ), ATTRIBUTE( EGL_STENCIL_SIZE ), ATTRIBUTE( EGL_CONFIG_CAVEAT ), ATTRIBUTE( EGL_CONFIG_ID ), ATTRIBUTE( EGL_LEVEL ), ATTRIBUTE( EGL_MAX_PBUFFER_HEIGHT ), ATTRIBUTE( EGL_MAX_PBUFFER_WIDTH ), ATTRIBUTE( EGL_MAX_PBUFFER_PIXELS ), ATTRIBUTE( EGL_NATIVE_RENDERABLE ), ATTRIBUTE( EGL_NATIVE_VISUAL_ID ), ATTRIBUTE( EGL_NATIVE_VISUAL_TYPE ), ATTRIBUTE( EGL_SAMPLES ), ATTRIBUTE( EGL_SAMPLE_BUFFERS ), ATTRIBUTE( EGL_SURFACE_TYPE ), ATTRIBUTE( EGL_TRANSPARENT_TYPE ), ATTRIBUTE( EGL_TRANSPARENT_BLUE_VALUE ), ATTRIBUTE( EGL_TRANSPARENT_GREEN_VALUE ), ATTRIBUTE( EGL_TRANSPARENT_RED_VALUE ), ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGB ), ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGBA ), ATTRIBUTE( EGL_MIN_SWAP_INTERVAL ), ATTRIBUTE( EGL_MAX_SWAP_INTERVAL ), ATTRIBUTE( EGL_LUMINANCE_SIZE ), ATTRIBUTE( EGL_ALPHA_MASK_SIZE ), ATTRIBUTE( EGL_COLOR_BUFFER_TYPE ), ATTRIBUTE( EGL_RENDERABLE_TYPE ), ATTRIBUTE( EGL_MATCH_NATIVE_PIXMAP ), ATTRIBUTE( EGL_CONFORMANT ), }; int main(int argc, char** argv) { EGLConfig* configs; EGLint n; EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, 0, 0); eglGetConfigs(dpy, NULL, 0, &n); configs = new EGLConfig[n]; eglGetConfigs(dpy, configs, n, &n); for (EGLint i=0 ; i #include #include #include #include #include #include #include using namespace android; int main(int argc, char** argv) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLSurface surface; EGLint w, h; EGLDisplay dpy; WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); return 0; } surface = eglCreateWindowSurface(dpy, config, window, NULL); context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); printf("w=%d, h=%d\n", w, h); glBindTexture(GL_TEXTURE_2D, 0); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DITHER); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glColor4f(1,1,1,1); uint32_t* t32 = (uint32_t*)malloc(512*512*4); for (int y=0 ; y<512 ; y++) { for (int x=0 ; x<512 ; x++) { int u = x-256; int v = y-256; if (u*u+v*v < 256*256) { t32[x+y*512] = 0x10FFFFFF; } else { t32[x+y*512] = 0x20FF0000; } } } const GLfloat fh = h; const GLfloat fw = w; const GLfloat vertices[4][2] = { { 0, 0 }, { 0, fh }, { fw, fh }, { fw, 0 } }; const GLfloat texCoords[4][2] = { { 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 0 } }; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, w, 0, h, 0, 1); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); eglSwapInterval(dpy, 1); glClearColor(1,0,0,0); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); eglSwapBuffers(dpy, surface); nsecs_t times[32]; for (int c=1 ; c<32 ; c++) { glClear(GL_COLOR_BUFFER_BIT); for (int i=0 ; i=1 ; c--) { int j=0; for (int c=1 ; c<32 ; c++) { glClear(GL_COLOR_BUFFER_BIT); nsecs_t now = systemTime(); for (int i=0 ; i #include #include #include #include #include #include using namespace android; #define USE_DRAW_TEXTURE 1 int main(int argc, char** argv) { if (argc!=2 && argc!=3) { printf("usage: %s <0-6> [pbuffer]\n", argv[0]); return 0; } const int test = atoi(argv[1]); int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer"); EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT, EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_NONE }; EGLint numConfigs = -1; EGLint majorVersion; EGLint minorVersion; EGLConfig config; EGLContext context; EGLSurface surface; EGLint w, h; EGLDisplay dpy; EGLNativeWindowType window = 0; WindowSurface* windowSurface = NULL; if (!usePbuffer) { windowSurface = new WindowSurface(); window = windowSurface->getSurface(); } dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); if (!usePbuffer) { EGLUtils::selectConfigForNativeWindow( dpy, s_configAttribs, window, &config); surface = eglCreateWindowSurface(dpy, config, window, NULL); } else { printf("using pbuffer\n"); eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE }; surface = eglCreatePbufferSurface(dpy, config, attribs); if (surface == EGL_NO_SURFACE) { printf("eglCreatePbufferSurface error %x\n", eglGetError()); } } context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); GLint dim = w #include #include #include #include #include #include #include #include #include #include using namespace android; int main(int argc, char** argv) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLSurface surface; EGLint w, h; EGLDisplay dpy; WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); return 0; } surface = eglCreateWindowSurface(dpy, config, window, NULL); context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); GLint dim = w #include #include #include #include #include #include #include #include #include #include using namespace android; static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); const char *v = (const char *) glGetString(s); // int error = glGetError(); // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, // (unsigned int) v); // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) // fprintf(stderr, "GL %s = %s\n", name, v); // else // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); fprintf(stderr, "GL %s = %s\n", name, v); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { fprintf(stderr, "after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 vPosition;\n" "void main() {\n" " gl_Position = vPosition;\n" "}\n"; static const char gFragmentShader[] = "precision mediump float;\n" "void main() {\n" " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); fprintf(stderr, "Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); fprintf(stderr, "Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } GLuint gProgram; GLuint gvPositionHandle; bool setupGraphics(int w, int h) { gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { return false; } gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); checkGlError("glGetAttribLocation"); fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; void renderFrame() { glClearColor(0.0f, 0.0f, 1.0f, 1.0f); checkGlError("glClearColor"); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvPositionHandle); checkGlError("glEnableVertexAttribArray"); glDrawArrays(GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); } void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { printf(" %s: ", names[j].name); printf("%d (0x%x)", value, value); } } printf("\n"); } int printEGLConfigurations(EGLDisplay dpy) { EGLint numConfig = 0; EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { return false; } printf("Number of EGL configuration: %d\n", numConfig); EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig); if (! configs) { printf("Could not allocate configs.\n"); return false; } returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { free(configs); return false; } for(int i = 0; i < numConfig; i++) { printf("Configuration %d\n", i); printEGLConfiguration(dpy, configs[i]); } free(configs); return true; } int main(int argc, char** argv) { EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLSurface surface; EGLint w, h; EGLDisplay dpy; checkEglError(""); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (dpy == EGL_NO_DISPLAY) { printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); return 0; } returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); if (returnValue != EGL_TRUE) { printf("eglInitialize failed\n"); return 0; } if (!printEGLConfigurations(dpy)) { printf("printEGLConfigurations failed\n"); return 0; } checkEglError("printEGLConfigurations"); WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); if (returnValue) { printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); return 0; } checkEglError("EGLUtils::selectConfigForNativeWindow"); printf("Chose this configuration:\n"); printEGLConfiguration(dpy, myConfig); surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (surface == EGL_NO_SURFACE) { printf("gelCreateWindowSurface failed.\n"); return 0; } context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { printf("eglCreateContext failed\n"); return 0; } returnValue = eglMakeCurrent(dpy, surface, surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { return 0; } eglQuerySurface(dpy, surface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; fprintf(stderr, "Window dimensions: %d x %d\n", w, h); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); if(!setupGraphics(w, h)) { fprintf(stderr, "Could not set up graphics.\n"); return 0; } for (;;) { renderFrame(); eglSwapBuffers(dpy, surface); checkEglError("eglSwapBuffers"); } return 0; } opengl/tests/gl2_cameraeye/0040755 0000000 0000000 00000000000 13077405420 014737 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/Android.mk0100644 0000000 0000000 00000000566 13077405420 016654 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := GL2CameraEye LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) # Use the following include to make our test apk. include $(call all-makefiles-under,$(LOCAL_PATH)) opengl/tests/gl2_cameraeye/AndroidManifest.xml0100644 0000000 0000000 00000003321 13077405420 020524 0ustar000000000 0000000 opengl/tests/gl2_cameraeye/res/0040755 0000000 0000000 00000000000 13077405420 015530 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/res/values/0040755 0000000 0000000 00000000000 13077405420 017027 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/res/values/strings.xml0100644 0000000 0000000 00000001371 13077405420 021241 0ustar000000000 0000000 GL2CameraEye opengl/tests/gl2_cameraeye/src/0040755 0000000 0000000 00000000000 13077405420 015526 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/src/com/0040755 0000000 0000000 00000000000 13077405420 016304 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/src/com/android/0040755 0000000 0000000 00000000000 13077405420 017724 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/0040755 0000000 0000000 00000000000 13077405420 022264 5ustar000000000 0000000 opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/GL2CameraEye.java0100644 0000000 0000000 00000043412 13077405420 025270 0ustar000000000 0000000 /* * 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 com.android.gl2cameraeye; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.view.MotionEvent; import android.content.Context; import android.util.Log; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import android.opengl.Matrix; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.SensorManager; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.Sensor; public class GL2CameraEye extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new CamGLSurfaceView(this); setContentView(mGLView); setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } @Override protected void onPause() { super.onPause(); mGLView.onPause(); } @Override protected void onResume() { super.onResume(); mGLView.onResume(); } private GLSurfaceView mGLView; } class CamGLSurfaceView extends GLSurfaceView implements SensorEventListener { public CamGLSurfaceView(Context context) { super(context); setEGLContextClientVersion(2); mRenderer = new CamRenderer(context); setRenderer(mRenderer); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); } public boolean onTouchEvent(final MotionEvent event) { queueEvent(new Runnable(){ public void run() { mRenderer.setPosition(event.getX() / getWidth(), event.getY() / getHeight()); }}); return true; } @Override public void onPause() { super.onPause(); mCamera.stopPreview(); mCamera.release(); mSensorManager.unregisterListener(this); } @Override public void onResume() { mCamera = Camera.open(); Camera.Parameters p = mCamera.getParameters(); // No changes to default camera parameters mCamera.setParameters(p); queueEvent(new Runnable(){ public void run() { mRenderer.setCamera(mCamera); }}); mSensorManager.registerListener(this, mAcceleration, SensorManager.SENSOR_DELAY_GAME); super.onResume(); } public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) { final float[] accelerationVector = event.values; queueEvent(new Runnable(){ public void run() { mRenderer.setAcceleration(accelerationVector); }}); } } public void onAccuracyChanged(Sensor sensor, int accuracy) { // Ignoring sensor accuracy changes. } CamRenderer mRenderer; Camera mCamera; SensorManager mSensorManager; Sensor mAcceleration; } class CamRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { public CamRenderer(Context context) { mContext = context; mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangleVertices.put(mTriangleVerticesData).position(0); Matrix.setIdentityM(mSTMatrix, 0); Matrix.setIdentityM(mMMatrix, 0); float[] defaultAcceleration = {0.f,0.f,0.f}; setAcceleration(defaultAcceleration); mPos[0] = 0.f; mPos[1] = 0.f; mPos[2] = 0.f; mVel[0] = 0.f; mVel[1] = 0.f; mVel[2] = 0.f; } /* The following set methods are not synchronized, so should only * be called within the rendering thread context. Use GLSurfaceView.queueEvent for safe access. */ public void setPosition(float x, float y) { /* Map from screen (0,0)-(1,1) to scene coordinates */ mPos[0] = (x*2-1)*mRatio; mPos[1] = (-y)*2+1; mPos[2] = 0.f; mVel[0] = 0; mVel[1] = 0; mVel[2] = 0; } public void setCamera(Camera camera) { mCamera = camera; Camera.Size previewSize = camera.getParameters().getPreviewSize(); mCameraRatio = (float)previewSize.width/previewSize.height; } public void setAcceleration(float[] accelerationVector) { mGForce[0] = accelerationVector[0]; mGForce[1] = accelerationVector[1]; mGForce[2] = accelerationVector[2]; } public void onDrawFrame(GL10 glUnused) { synchronized(this) { if (updateSurface) { mSurface.updateTexImage(); mSurface.getTransformMatrix(mSTMatrix); long timestamp = mSurface.getTimestamp(); doPhysics(timestamp); updateSurface = false; } } // Ignore the passed-in GL10 interface, and use the GLES20 // class's static methods instead. GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUseProgram(mProgram); checkGlError("glUseProgram"); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); checkGlError("glVertexAttribPointer maPosition"); GLES20.glEnableVertexAttribArray(maPositionHandle); checkGlError("glEnableVertexAttribArray maPositionHandle"); mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); checkGlError("glVertexAttribPointer maTextureHandle"); GLES20.glEnableVertexAttribArray(maTextureHandle); checkGlError("glEnableVertexAttribArray maTextureHandle"); Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0); Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0); GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); GLES20.glUniform1f(muCRatioHandle, mCameraRatio); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); checkGlError("glDrawArrays"); } public void onSurfaceChanged(GL10 glUnused, int width, int height) { // Ignore the passed-in GL10 interface, and use the GLES20 // class's static methods instead. GLES20.glViewport(0, 0, width, height); mRatio = (float) width / height; Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7); } public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { // Ignore the passed-in GL10 interface, and use the GLES20 // class's static methods instead. /* Set up alpha blending and an Android background color */ GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f); /* Set up shaders and handles to their variables */ mProgram = createProgram(mVertexShader, mFragmentShader); if (mProgram == 0) { return; } maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); checkGlError("glGetAttribLocation aPosition"); if (maPositionHandle == -1) { throw new RuntimeException("Could not get attrib location for aPosition"); } maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord"); checkGlError("glGetAttribLocation aTextureCoord"); if (maTextureHandle == -1) { throw new RuntimeException("Could not get attrib location for aTextureCoord"); } muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); checkGlError("glGetUniformLocation uMVPMatrix"); if (muMVPMatrixHandle == -1) { throw new RuntimeException("Could not get attrib location for uMVPMatrix"); } muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix"); checkGlError("glGetUniformLocation uSTMatrix"); if (muMVPMatrixHandle == -1) { throw new RuntimeException("Could not get attrib location for uSTMatrix"); } muCRatioHandle = GLES20.glGetUniformLocation(mProgram, "uCRatio"); checkGlError("glGetUniformLocation uCRatio"); if (muMVPMatrixHandle == -1) { throw new RuntimeException("Could not get attrib location for uCRatio"); } /* * Create our texture. This has to be done each time the * surface is created. */ int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); mTextureID = textures[0]; GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); checkGlError("glBindTexture mTextureID"); // Can't do mipmapping with camera source GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); // Clamp to edge is the only option GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); checkGlError("glTexParameteri mTextureID"); /* * Create the SurfaceTexture that will feed this textureID, and pass it to the camera */ mSurface = new SurfaceTexture(mTextureID); mSurface.setOnFrameAvailableListener(this); try { mCamera.setPreviewTexture(mSurface); } catch (IOException t) { Log.e(TAG, "Cannot set preview texture target!"); } /* Start the camera */ mCamera.startPreview(); Matrix.setLookAtM(mVMatrix, 0, 0, 0, 5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); mLastTime = 0; synchronized(this) { updateSurface = false; } } synchronized public void onFrameAvailable(SurfaceTexture surface) { /* For simplicity, SurfaceTexture calls here when it has new * data available. Call may come in from some random thread, * so let's be safe and use synchronize. No OpenGL calls can be done here. */ updateSurface = true; } private void doPhysics(long timestamp) { /* * Move the camera surface around based on some simple spring physics with drag */ if (mLastTime == 0) mLastTime = timestamp; float deltaT = (timestamp - mLastTime)/1000000000.f; // To seconds float springStrength = 20.f; float frictionCoeff = 10.f; float mass = 10.f; float gMultiplier = 4.f; /* Only update physics every 30 ms */ if (deltaT > 0.030f) { mLastTime = timestamp; float[] totalForce = new float[3]; totalForce[0] = -mPos[0] * springStrength - mVel[0]*frictionCoeff + gMultiplier*mGForce[0]*mass; totalForce[1] = -mPos[1] * springStrength - mVel[1]*frictionCoeff + gMultiplier*mGForce[1]*mass; totalForce[2] = -mPos[2] * springStrength - mVel[2]*frictionCoeff + gMultiplier*mGForce[2]*mass; float[] accel = new float[3]; accel[0] = totalForce[0]/mass; accel[1] = totalForce[1]/mass; accel[2] = totalForce[2]/mass; /* Not a very accurate integrator */ mVel[0] = mVel[0] + accel[0]*deltaT; mVel[1] = mVel[1] + accel[1]*deltaT; mVel[2] = mVel[2] + accel[2]*deltaT; mPos[0] = mPos[0] + mVel[0]*deltaT; mPos[1] = mPos[1] + mVel[1]*deltaT; mPos[2] = mPos[2] + mVel[2]*deltaT; Matrix.setIdentityM(mMMatrix, 0); Matrix.translateM(mMMatrix, 0, mPos[0], mPos[1], mPos[2]); } } private int loadShader(int shaderType, String source) { int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compiled = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e(TAG, "Could not compile shader " + shaderType + ":"); Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } private int createProgram(String vertexSource, String fragmentSource) { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } int program = GLES20.glCreateProgram(); if (program != 0) { GLES20.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); GLES20.glLinkProgram(program); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES20.GL_TRUE) { Log.e(TAG, "Could not link program: "); Log.e(TAG, GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; } private void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e(TAG, op + ": glError " + error); throw new RuntimeException(op + ": glError " + error); } } private static final int FLOAT_SIZE_BYTES = 4; private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; private final float[] mTriangleVerticesData = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, -1.0f, 1.0f, 0, 0.f, 1.f, 1.0f, 1.0f, 0, 1.f, 1.f, }; private FloatBuffer mTriangleVertices; private final String mVertexShader = "uniform mat4 uMVPMatrix;\n" + "uniform mat4 uSTMatrix;\n" + "uniform float uCRatio;\n" + "attribute vec4 aPosition;\n" + "attribute vec4 aTextureCoord;\n" + "varying vec2 vTextureCoord;\n" + "varying vec2 vTextureNormCoord;\n" + "void main() {\n" + " vec4 scaledPos = aPosition;\n" + " scaledPos.x = scaledPos.x * uCRatio;\n" + " gl_Position = uMVPMatrix * scaledPos;\n" + " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + " vTextureNormCoord = aTextureCoord.xy;\n" + "}\n"; private final String mFragmentShader = "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "varying vec2 vTextureCoord;\n" + "varying vec2 vTextureNormCoord;\n" + "uniform samplerExternalOES sTexture;\n" + "void main() {\n" + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + " gl_FragColor.a = 1.0-min(length(vTextureNormCoord-0.5)*2.0,1.0);\n" + "}\n"; private float[] mMVPMatrix = new float[16]; private float[] mProjMatrix = new float[16]; private float[] mMMatrix = new float[16]; private float[] mVMatrix = new float[16]; private float[] mSTMatrix = new float[16]; private int mProgram; private int mTextureID; private int muMVPMatrixHandle; private int muSTMatrixHandle; private int muCRatioHandle; private int maPositionHandle; private int maTextureHandle; private float mRatio = 1.0f; private float mCameraRatio = 1.0f; private float[] mVel = new float[3]; private float[] mPos = new float[3]; private float[] mGForce = new float[3]; private long mLastTime; private SurfaceTexture mSurface; private Camera mCamera; private boolean updateSurface = false; private Context mContext; private static String TAG = "CamRenderer"; // Magic key private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65; } opengl/tests/gl2_copyTexImage/0040755 0000000 0000000 00000000000 13077405420 015402 5ustar000000000 0000000 opengl/tests/gl2_copyTexImage/Android.mk0100644 0000000 0000000 00000000704 13077405420 017311 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gl2_copyTexImage.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-gl2_copyTexImage LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES include $(BUILD_EXECUTABLE) opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp0100644 0000000 0000000 00000035241 13077405420 021252 0ustar000000000 0000000 /* * Copyright (C) 2007 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 #include #include #include #include #include #include #include #include #include #include using namespace android; static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); const char *v = (const char *) glGetString(s); // int error = glGetError(); // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, // (unsigned int) v); // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) // fprintf(stderr, "GL %s = %s\n", name, v); // else // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); fprintf(stderr, "GL %s = %s\n", name, v); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { fprintf(stderr, "after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 vPosition;\n" "void main() {\n" " gl_Position = vPosition;\n" "}\n"; static const char gFragmentShader[] = "precision mediump float;\n" "void main() {\n" " gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);\n" "}\n"; GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); fprintf(stderr, "Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); fprintf(stderr, "Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } GLuint gProgram; GLuint gTextureProgram; GLuint gvPositionHandle; GLuint gvTexturePositionHandle; GLuint gvTextureTexCoordsHandle; GLuint gvTextureSamplerHandle; GLuint gFbo; GLuint gTexture; GLuint gBufferTexture; static const char gSimpleVS[] = "attribute vec4 position;\n" "attribute vec2 texCoords;\n" "varying vec2 outTexCoords;\n" "\nvoid main(void) {\n" " outTexCoords = texCoords;\n" " gl_Position = position;\n" "}\n\n"; static const char gSimpleFS[] = "precision mediump float;\n\n" "varying vec2 outTexCoords;\n" "uniform sampler2D texture;\n" "\nvoid main(void) {\n" " gl_FragColor = texture2D(texture, outTexCoords);\n" "}\n\n"; bool setupGraphics(int w, int h) { gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { return false; } gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); checkGlError("glGetAttribLocation"); fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); gTextureProgram = createProgram(gSimpleVS, gSimpleFS); if (!gTextureProgram) { return false; } gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position"); checkGlError("glGetAttribLocation"); gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords"); checkGlError("glGetAttribLocation"); gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture"); checkGlError("glGetAttribLocation"); glActiveTexture(GL_TEXTURE0); glGenTextures(1, &gTexture); glBindTexture(GL_TEXTURE_2D, gTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenTextures(1, &gBufferTexture); glBindTexture(GL_TEXTURE_2D, gBufferTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenFramebuffers(1, &gFbo); glBindFramebuffer(GL_FRAMEBUFFER, gFbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gTexture, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; const GLint FLOAT_SIZE_BYTES = 4; const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; const GLfloat gTriangleVerticesData[] = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, -1.0f, 1.0f, 0, 0.f, 1.f, 1.0f, 1.0f, 0, 1.f, 1.f, }; void renderFrame(GLint w, GLint h) { glClearColor(1.0f, 0.0f, 0.0f, 1.0f); checkGlError("glClearColor"); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); // Bind FBO and draw into it glBindFramebuffer(GL_FRAMEBUFFER, gFbo); checkGlError("glBindFramebuffer"); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); checkGlError("glClearColor"); glClear(GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvPositionHandle); checkGlError("glEnableVertexAttribArray"); glDrawArrays(GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); // Copy content of FBO into a texture glBindTexture(GL_TEXTURE_2D, gBufferTexture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w / 2, h / 2); checkGlError("glCopyTexSubImage2D"); // Back to the display glBindFramebuffer(GL_FRAMEBUFFER, 0); checkGlError("glBindFramebuffer"); // Draw copied content on the screen glUseProgram(gTextureProgram); checkGlError("glUseProgram"); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData); checkGlError("glVertexAttribPointer"); glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvTexturePositionHandle); glEnableVertexAttribArray(gvTextureTexCoordsHandle); checkGlError("glEnableVertexAttribArray"); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGlError("glDrawArrays"); } void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { printf(" %s: ", names[j].name); printf("%d (0x%x)", value, value); } } printf("\n"); } int printEGLConfigurations(EGLDisplay dpy) { EGLint numConfig = 0; EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { return false; } printf("Number of EGL configuration: %d\n", numConfig); EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig); if (! configs) { printf("Could not allocate configs.\n"); return false; } returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { free(configs); return false; } for(int i = 0; i < numConfig; i++) { printf("Configuration %d\n", i); printEGLConfiguration(dpy, configs[i]); } free(configs); return true; } int main(int argc, char** argv) { EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLSurface surface; EGLint w, h; EGLDisplay dpy; checkEglError(""); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (dpy == EGL_NO_DISPLAY) { printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); return 0; } returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); if (returnValue != EGL_TRUE) { printf("eglInitialize failed\n"); return 0; } if (!printEGLConfigurations(dpy)) { printf("printEGLConfigurations failed\n"); return 0; } checkEglError("printEGLConfigurations"); WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); EGLint numConfigs = -1, n = 0; eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs); if (numConfigs) { EGLConfig* const configs = new EGLConfig[numConfigs]; eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n); myConfig = configs[0]; delete[] configs; } checkEglError("EGLUtils::selectConfigForNativeWindow"); printf("Chose this configuration:\n"); printEGLConfiguration(dpy, myConfig); surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (surface == EGL_NO_SURFACE) { printf("gelCreateWindowSurface failed.\n"); return 0; } context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { printf("eglCreateContext failed\n"); return 0; } returnValue = eglMakeCurrent(dpy, surface, surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { return 0; } eglQuerySurface(dpy, surface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; fprintf(stderr, "Window dimensions: %d x %d\n", w, h); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); if(!setupGraphics(w, h)) { fprintf(stderr, "Could not set up graphics.\n"); return 0; } for (;;) { renderFrame(w, h); eglSwapBuffers(dpy, surface); checkEglError("eglSwapBuffers"); } return 0; } opengl/tests/gl2_java/0040755 0000000 0000000 00000000000 13077405420 013725 5ustar000000000 0000000 opengl/tests/gl2_java/Android.mk0100644 0000000 0000000 00000000640 13077405420 015633 0ustar000000000 0000000 ######################################################################### # OpenGL ES 2.0 Java sample ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GL2Java include $(BUILD_PACKAGE) opengl/tests/gl2_java/AndroidManifest.xml0100644 0000000 0000000 00000002554 13077405420 017521 0ustar000000000 0000000 opengl/tests/gl2_java/res/0040755 0000000 0000000 00000000000 13077405420 014516 5ustar000000000 0000000 opengl/tests/gl2_java/res/values/0040755 0000000 0000000 00000000000 13077405420 016015 5ustar000000000 0000000 opengl/tests/gl2_java/res/values/strings.xml0100644 0000000 0000000 00000001627 13077405420 020233 0ustar000000000 0000000 GL2Java opengl/tests/gl2_java/src/0040755 0000000 0000000 00000000000 13077405420 014514 5ustar000000000 0000000 opengl/tests/gl2_java/src/com/0040755 0000000 0000000 00000000000 13077405420 015272 5ustar000000000 0000000 opengl/tests/gl2_java/src/com/android/0040755 0000000 0000000 00000000000 13077405420 016712 5ustar000000000 0000000 opengl/tests/gl2_java/src/com/android/gl2java/0040755 0000000 0000000 00000000000 13077405420 020240 5ustar000000000 0000000 opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaActivity.java0100644 0000000 0000000 00000002320 13077405420 024000 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gl2java; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; import java.io.File; public class GL2JavaActivity extends Activity { GL2JavaView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new GL2JavaView(getApplication()); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/gl2_java/src/com/android/gl2java/GL2JavaView.java0100644 0000000 0000000 00000014211 13077405420 023120 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.gl2java; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLES20; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class GL2JavaView extends GLSurfaceView { private static String TAG = "GL2JavaView"; public GL2JavaView(Context context) { super(context); setEGLContextClientVersion(2); setRenderer(new Renderer()); } private static class Renderer implements GLSurfaceView.Renderer { public Renderer() { mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTriangleVertices.put(mTriangleVerticesData).position(0); } public void onDrawFrame(GL10 gl) { GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUseProgram(mProgram); checkGlError("glUseProgram"); GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTriangleVertices); checkGlError("glVertexAttribPointer"); GLES20.glEnableVertexAttribArray(mvPositionHandle); checkGlError("glEnableVertexAttribArray"); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); } public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { mProgram = createProgram(mVertexShader, mFragmentShader); if (mProgram == 0) { return; } mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); checkGlError("glGetAttribLocation"); if (mvPositionHandle == -1) { throw new RuntimeException("Could not get attrib location for vPosition"); } } private int loadShader(int shaderType, String source) { int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compiled = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e(TAG, "Could not compile shader " + shaderType + ":"); Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } private int createProgram(String vertexSource, String fragmentSource) { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } int program = GLES20.glCreateProgram(); if (program != 0) { GLES20.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); GLES20.glLinkProgram(program); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES20.GL_TRUE) { Log.e(TAG, "Could not link program: "); Log.e(TAG, GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; } private void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e(TAG, op + ": glError " + error); throw new RuntimeException(op + ": glError " + error); } } private final float[] mTriangleVerticesData = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; private FloatBuffer mTriangleVertices; private final String mVertexShader = "attribute vec4 vPosition;\n" + "void main() {\n" + " gl_Position = vPosition;\n" + "}\n"; private final String mFragmentShader = "precision mediump float;\n" + "void main() {\n" + " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + "}\n"; private int mProgram; private int mvPositionHandle; } } opengl/tests/gl2_jni/0040755 0000000 0000000 00000000000 13077405420 013564 5ustar000000000 0000000 opengl/tests/gl2_jni/Android.mk0100644 0000000 0000000 00000002042 13077405420 015470 0ustar000000000 0000000 ######################################################################### # OpenGL ES JNI sample # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GL2JNI LOCAL_JNI_SHARED_LIBRARIES := libgl2jni include $(BUILD_PACKAGE) ######################################################################### # Build JNI Shared Library ######################################################################### LOCAL_PATH:= $(LOCAL_PATH)/jni include $(CLEAR_VARS) # Optional tag would mean it doesn't get installed by default LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter LOCAL_SRC_FILES:= \ gl_code.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libEGL \ libGLESv2 LOCAL_MODULE := libgl2jni include $(BUILD_SHARED_LIBRARY) opengl/tests/gl2_jni/AndroidManifest.xml0100644 0000000 0000000 00000002463 13077405420 017357 0ustar000000000 0000000 opengl/tests/gl2_jni/jni/0040755 0000000 0000000 00000000000 13077405420 014344 5ustar000000000 0000000 opengl/tests/gl2_jni/jni/gl_code.cpp0100644 0000000 0000000 00000011503 13077405420 016441 0ustar000000000 0000000 // OpenGL ES 2.0 code #include #define LOG_TAG "GL2JNI gl_code.cpp" #include #include #include #include #include #include #include static void printGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); ALOGI("GL %s = %s\n", name, v); } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { ALOGI("after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 vPosition;\n" "void main() {\n" " gl_Position = vPosition;\n" "}\n"; static const char gFragmentShader[] = "precision mediump float;\n" "void main() {\n" " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); ALOGE("Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); ALOGE("Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } GLuint gProgram; GLuint gvPositionHandle; bool setupGraphics(int w, int h) { printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); ALOGI("setupGraphics(%d, %d)", w, h); gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { ALOGE("Could not create program."); return false; } gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); checkGlError("glGetAttribLocation"); ALOGI("glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; void renderFrame() { static float grey; grey += 0.01f; if (grey > 1.0f) { grey = 0.0f; } glClearColor(grey, grey, grey, 1.0f); checkGlError("glClearColor"); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvPositionHandle); checkGlError("glEnableVertexAttribArray"); glDrawArrays(GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); } extern "C" { JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj); }; JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height) { setupGraphics(width, height); } JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj) { renderFrame(); } opengl/tests/gl2_jni/res/0040755 0000000 0000000 00000000000 13077405420 014355 5ustar000000000 0000000 opengl/tests/gl2_jni/res/values/0040755 0000000 0000000 00000000000 13077405420 015654 5ustar000000000 0000000 opengl/tests/gl2_jni/res/values/strings.xml0100644 0000000 0000000 00000001625 13077405420 020070 0ustar000000000 0000000 GL2JNI opengl/tests/gl2_jni/src/0040755 0000000 0000000 00000000000 13077405420 014353 5ustar000000000 0000000 opengl/tests/gl2_jni/src/com/0040755 0000000 0000000 00000000000 13077405420 015131 5ustar000000000 0000000 opengl/tests/gl2_jni/src/com/android/0040755 0000000 0000000 00000000000 13077405420 016551 5ustar000000000 0000000 opengl/tests/gl2_jni/src/com/android/gl2jni/0040755 0000000 0000000 00000000000 13077405420 017736 5ustar000000000 0000000 opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java0100644 0000000 0000000 00000002314 13077405420 023240 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gl2jni; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; import java.io.File; public class GL2JNIActivity extends Activity { GL2JNIView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new GL2JNIView(getApplication()); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java0100644 0000000 0000000 00000001715 13077405420 022156 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gl2jni; // Wrapper for native library public class GL2JNILib { static { System.loadLibrary("gl2jni"); } /** * @param width the current view width * @param height the current view height */ public static native void init(int width, int height); public static native void step(); } opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java0100644 0000000 0000000 00000026762 13077405420 022373 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.gl2jni; /* * Copyright (C) 2008 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. */ import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class GL2JNIView extends GLSurfaceView { private static String TAG = "GL2JNIView"; public GL2JNIView(Context context) { super(context); init(false, 0, 0); } public GL2JNIView(Context context, boolean translucent, int depth, int stencil) { super(context); init(translucent, depth, stencil); } private void init(boolean translucent, int depth, int stencil) { setEGLContextFactory(new ContextFactory()); setEGLConfigChooser( translucent ? new ConfigChooser(8,8,8,8, depth, stencil) : new ConfigChooser(5,6,5,0, depth, stencil)); setRenderer(new Renderer()); } private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES 2.0 context"); checkEglError("Before eglCreateContext", egl); int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); checkEglError("After eglCreateContext", egl); return context; } public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { egl.eglDestroyContext(display, context); } } private static void checkEglError(String prompt, EGL10 egl) { int error; while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); } } private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { mRedSize = r; mGreenSize = g; mBlueSize = b; mAlphaSize = a; mDepthSize = depth; mStencilSize = stencil; } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException("No configs match configSpec"); } EGLConfig[] configs = new EGLConfig[numConfigs]; egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); // printConfigs(egl, display, configs); return chooseConfig(egl, display, configs); } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { EGLConfig closestConfig = null; int closestDistance = 1000; 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); int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize); if (distance < closestDistance) { closestDistance = distance; closestConfig = config; } } } return closestConfig; } 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; } private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { int numConfigs = configs.length; Log.w(TAG, String.format("%d configurations", numConfigs)); for (int i = 0; i < numConfigs; i++) { Log.w(TAG, String.format("Configuration %d:\n", i)); printConfig(egl, display, configs[i]); } } private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config) { int[] attributes = { EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE, EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_CONFIG_ID, EGL10.EGL_LEVEL, EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH, EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE, 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE, 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE, EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE, 0x3042 // EGL10.EGL_CONFORMANT }; String[] names = { "EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT", "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT", "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH", "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES", "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE", "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE", "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL", "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT" }; int[] value = new int[1]; for (int i = 0; i < attributes.length; i++) { int attribute = attributes[i]; String name = names[i]; if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { Log.w(TAG, String.format(" %s: %d\n", name, value[0])); } else { // Log.w(TAG, String.format(" %s: failed\n", name)); while (egl.eglGetError() != EGL10.EGL_SUCCESS); } } } // Subclasses can adjust these values: protected int mRedSize; protected int mGreenSize; protected int mBlueSize; protected int mAlphaSize; protected int mDepthSize; protected int mStencilSize; private int[] mValue = new int[1]; } private static class Renderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl) { GL2JNILib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GL2JNILib.init(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } } } opengl/tests/gl2_yuvtex/0040755 0000000 0000000 00000000000 13077405420 014350 5ustar000000000 0000000 opengl/tests/gl2_yuvtex/Android.mk0100644 0000000 0000000 00000000742 13077405420 016261 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gl2_yuvtex.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libutils \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-gl2_yuvtex LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES include $(BUILD_EXECUTABLE) opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp0100644 0000000 0000000 00000033357 13077405420 017174 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); const char *v = (const char *) glGetString(s); // int error = glGetError(); // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, // (unsigned int) v); // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) // fprintf(stderr, "GL %s = %s\n", name, v); // else // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); fprintf(stderr, "GL %s = %s\n", name, v); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { fprintf(stderr, "after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 vPosition;\n" "varying vec2 yuvTexCoords;\n" "void main() {\n" " yuvTexCoords = vPosition.xy + vec2(0.5, 0.5);\n" " gl_Position = vPosition;\n" "}\n"; static const char gFragmentShader[] = "#extension GL_OES_EGL_image_external : require\n" "precision mediump float;\n" "uniform samplerExternalOES yuvTexSampler;\n" "varying vec2 yuvTexCoords;\n" "void main() {\n" " gl_FragColor = texture2D(yuvTexSampler, yuvTexCoords);\n" "}\n"; GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); fprintf(stderr, "Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } } else { fprintf(stderr, "Guessing at GL_INFO_LOG_LENGTH size\n"); char* buf = (char*) malloc(0x1000); if (buf) { glGetShaderInfoLog(shader, 0x1000, NULL, buf); fprintf(stderr, "Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } } glDeleteShader(shader); shader = 0; } } return shader; } GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); fprintf(stderr, "Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } GLuint gProgram; GLint gvPositionHandle; GLint gYuvTexSamplerHandle; bool setupGraphics(int w, int h) { gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { return false; } gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); checkGlError("glGetAttribLocation"); fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); gYuvTexSamplerHandle = glGetUniformLocation(gProgram, "yuvTexSampler"); checkGlError("glGetUniformLocation"); fprintf(stderr, "glGetUniformLocation(\"yuvTexSampler\") = %d\n", gYuvTexSamplerHandle); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } int align(int x, int a) { return (x + (a-1)) & (~(a-1)); } const int yuvTexWidth = 608; const int yuvTexHeight = 480; const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12; const int yuvTexOffsetY = 0; const bool yuvTexSameUV = false; static sp yuvTexBuffer; static GLuint yuvTex; bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) { int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1; int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1; yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, yuvTexUsage); int yuvTexStrideY = yuvTexBuffer->getStride(); int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight; int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2; int yuvTexStrideU = yuvTexStrideV; char* buf = NULL; status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); if (err != 0) { fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err); return false; } for (int x = 0; x < yuvTexWidth; x++) { for (int y = 0; y < yuvTexHeight; y++) { int parityX = (x / blockWidth) & 1; int parityY = (y / blockHeight) & 1; unsigned char intensity = (parityX ^ parityY) ? 63 : 191; buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) { buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; if (yuvTexSameUV) { buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity; } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) { buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity; } } } } err = yuvTexBuffer->unlock(); if (err != 0) { fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err); return false; } EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer(); EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, 0); checkEglError("eglCreateImageKHR"); if (img == EGL_NO_IMAGE_KHR) { return false; } glGenTextures(1, &yuvTex); checkGlError("glGenTextures"); glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); checkGlError("glBindTexture"); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img); checkGlError("glEGLImageTargetTexture2DOES"); return true; } const GLfloat gTriangleVertices[] = { -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, }; void renderFrame() { glClearColor(0.0f, 0.0f, 1.0f, 1.0f); checkGlError("glClearColor"); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvPositionHandle); checkGlError("glEnableVertexAttribArray"); glUniform1i(gYuvTexSamplerHandle, 0); checkGlError("glUniform1i"); glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); checkGlError("glBindTexture"); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); checkGlError("glDrawArrays"); } void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { printf(" %s: ", names[j].name); printf("%d (0x%x)", value, value); } } printf("\n"); } int main(int argc, char** argv) { EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLSurface surface; EGLint w, h; EGLDisplay dpy; checkEglError(""); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (dpy == EGL_NO_DISPLAY) { printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); return 0; } returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); if (returnValue != EGL_TRUE) { printf("eglInitialize failed\n"); return 0; } WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); if (returnValue) { printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); return 1; } checkEglError("EGLUtils::selectConfigForNativeWindow"); printf("Chose this configuration:\n"); printEGLConfiguration(dpy, myConfig); surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (surface == EGL_NO_SURFACE) { printf("gelCreateWindowSurface failed.\n"); return 1; } context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { printf("eglCreateContext failed\n"); return 1; } returnValue = eglMakeCurrent(dpy, surface, surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { return 1; } eglQuerySurface(dpy, surface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; fprintf(stderr, "Window dimensions: %d x %d\n", w, h); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); if(!setupYuvTexSurface(dpy, context)) { fprintf(stderr, "Could not set up texture surface.\n"); return 1; } if(!setupGraphics(w, h)) { fprintf(stderr, "Could not set up graphics.\n"); return 1; } for (;;) { renderFrame(); eglSwapBuffers(dpy, surface); checkEglError("eglSwapBuffers"); } return 0; } opengl/tests/gl_basic/0040755 0000000 0000000 00000000000 13077405420 014003 5ustar000000000 0000000 opengl/tests/gl_basic/Android.mk0100644 0000000 0000000 00000000620 13077405420 015707 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gl_basic.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv1_CM \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-gl_basic LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/gl_basic/gl_basic.cpp0100644 0000000 0000000 00000022433 13077405420 016253 0ustar000000000 0000000 // Simple OpenGL ES 1.x application showing how to initialize and draw something. #include #include #include #include #include #include #include #include using namespace android; EGLDisplay eglDisplay; EGLSurface eglSurface; EGLContext eglContext; GLuint texture; #define FIXED_ONE 0x10000 #define ITERATIONS 50 int init_gl_surface(const WindowSurface& windowSurface); void free_gl_surface(void); void init_scene(void); void render(); void create_texture(void); int readTimer(void); static void printGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); fprintf(stderr, "GL %s = %s\n", name, v); } static void gluLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { // See the OpenGL GLUT documentation for gluLookAt for a description // of the algorithm. We implement it in a straightforward way: float fx = centerX - eyeX; float fy = centerY - eyeY; float fz = centerZ - eyeZ; // Normalize f float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz); fx *= rlf; fy *= rlf; fz *= rlf; // Normalize up float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ); upX *= rlup; upY *= rlup; upZ *= rlup; // compute s = f x up (x means "cross product") float sx = fy * upZ - fz * upY; float sy = fz * upX - fx * upZ; float sz = fx * upY - fy * upX; // compute u = s x f float ux = sy * fz - sz * fy; float uy = sz * fx - sx * fz; float uz = sx * fy - sy * fx; float m[16] ; m[0] = sx; m[1] = ux; m[2] = -fx; m[3] = 0.0f; m[4] = sy; m[5] = uy; m[6] = -fy; m[7] = 0.0f; m[8] = sz; m[9] = uz; m[10] = -fz; m[11] = 0.0f; m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f; glMultMatrixf(m); glTranslatef(-eyeX, -eyeY, -eyeZ); } void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { printf(" %s: ", names[j].name); printf("%d (0x%x)", value, value); } } printf("\n"); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } int printEGLConfigurations(EGLDisplay dpy) { EGLint numConfig = 0; EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { return false; } printf("Number of EGL configurations: %d\n", numConfig); EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig); if (! configs) { printf("Could not allocate configs.\n"); return false; } returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig); checkEglError("eglGetConfigs", returnVal); if (!returnVal) { free(configs); return false; } for(int i = 0; i < numConfig; i++) { printf("Configuration %d\n", i); printEGLConfiguration(dpy, configs[i]); } free(configs); return true; } int main(int argc, char **argv) { int q; int start, end; printf("Initializing EGL...\n"); WindowSurface windowSurface; if(!init_gl_surface(windowSurface)) { printf("GL initialisation failed - exiting\n"); return 0; } init_scene(); create_texture(); printf("Running...\n"); while(true) { render(); } free_gl_surface(); return 0; } int init_gl_surface(const WindowSurface& windowSurface) { EGLint numConfigs = 1; EGLConfig myConfig = {0}; EGLint attrib[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY ) { printf("eglGetDisplay failed\n"); return 0; } if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE ) { printf("eglInitialize failed\n"); return 0; } if (! printEGLConfigurations(eglDisplay)) { printf("printEGLConfigurations failed.\n"); return 0; } EGLNativeWindowType window = windowSurface.getSurface(); EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig); if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig, window, 0)) == EGL_NO_SURFACE ) { printf("eglCreateWindowSurface failed\n"); return 0; } if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT ) { printf("eglCreateContext failed\n"); return 0; } if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE ) { printf("eglMakeCurrent failed\n"); return 0; } int w, h; eglQuerySurface(eglDisplay, eglSurface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(eglDisplay, eglSurface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; fprintf(stderr, "Window dimensions: %d x %d\n", w, h); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); return 1; } void free_gl_surface(void) { if (eglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); eglDestroyContext( eglDisplay, eglContext ); eglDestroySurface( eglDisplay, eglSurface ); eglTerminate( eglDisplay ); eglDisplay = EGL_NO_DISPLAY; } } void init_scene(void) { glDisable(GL_DITHER); glEnable(GL_CULL_FACE); float ratio = 320.0f / 480.0f; glViewport(0, 0, 320, 480); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustumf(-ratio, ratio, -1, 1, 1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( 0, 0, 3, // eye 0, 0, 0, // center 0, 1, 0); // up glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } void create_texture(void) { const unsigned int on = 0xff0000ff; const unsigned int off = 0xffffffff; const unsigned int pixels[] = { on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, }; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } void render() { int i, j; int quads = 1; const GLfloat vertices[] = { -1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0 }; const GLfixed texCoords[] = { 0, 0, FIXED_ONE, 0, FIXED_ONE, FIXED_ONE, 0, FIXED_ONE }; const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; glVertexPointer(3, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FIXED, 0, texCoords); glClearColor(1.0, 1.0, 1.0, 1.0); int nelem = sizeof(indices)/sizeof(indices[0]); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices); eglSwapBuffers(eglDisplay, eglSurface); } opengl/tests/gl_jni/0040755 0000000 0000000 00000000000 13077405420 013502 5ustar000000000 0000000 opengl/tests/gl_jni/Android.mk0100644 0000000 0000000 00000002071 13077405420 015410 0ustar000000000 0000000 ######################################################################### # OpenGL ES JNI sample # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GLJNI LOCAL_JNI_SHARED_LIBRARIES := libgljni include $(BUILD_PACKAGE) ######################################################################### # Build JNI Shared Library ######################################################################### LOCAL_PATH:= $(LOCAL_PATH)/jni include $(CLEAR_VARS) # Optional tag would mean it doesn't get installed by default LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter LOCAL_SRC_FILES:= \ gl_code.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libEGL \ libGLESv1_CM LOCAL_MODULE := libgljni LOCAL_ARM_MODE := arm include $(BUILD_SHARED_LIBRARY) opengl/tests/gl_jni/AndroidManifest.xml0100644 0000000 0000000 00000002767 13077405420 017304 0ustar000000000 0000000 opengl/tests/gl_jni/jni/0040755 0000000 0000000 00000000000 13077405420 014262 5ustar000000000 0000000 opengl/tests/gl_jni/jni/gl_code.cpp0100644 0000000 0000000 00000011362 13077405420 016362 0ustar000000000 0000000 // OpenGL ES 1.0 code #include #define LOG_TAG "GLJNI gl_code.cpp" #include #include #include #include #include GLuint texture; GLfloat background; #define FIXED_ONE 0x10000 static void printGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); ALOGI("GL %s = %s\n", name, v); } static void gluLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { // See the OpenGL GLUT documentation for gluLookAt for a description // of the algorithm. We implement it in a straightforward way: float fx = centerX - eyeX; float fy = centerY - eyeY; float fz = centerZ - eyeZ; // Normalize f float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz); fx *= rlf; fy *= rlf; fz *= rlf; // Normalize up float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ); upX *= rlup; upY *= rlup; upZ *= rlup; // compute s = f x up (x means "cross product") float sx = fy * upZ - fz * upY; float sy = fz * upX - fx * upZ; float sz = fx * upY - fy * upX; // compute u = s x f float ux = sy * fz - sz * fy; float uy = sz * fx - sx * fz; float uz = sx * fy - sy * fx; float m[16] ; m[0] = sx; m[1] = ux; m[2] = -fx; m[3] = 0.0f; m[4] = sy; m[5] = uy; m[6] = -fy; m[7] = 0.0f; m[8] = sz; m[9] = uz; m[10] = -fz; m[11] = 0.0f; m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f; glMultMatrixf(m); glTranslatef(-eyeX, -eyeY, -eyeZ); } void init_scene(int width, int height) { printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); glDisable(GL_DITHER); glEnable(GL_CULL_FACE); float ratio = width / height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustumf(-ratio, ratio, -1, 1, 1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( 0, 0, 3, // eye 0, 0, 0, // center 0, 1, 0); // up glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } void create_texture() { const unsigned int on = 0xff0000ff; const unsigned int off = 0xffffffff; const unsigned int pixels[] = { on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, }; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } extern "C" { JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj); }; JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height) { init_scene(width, height); create_texture(); } JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj) { const GLfloat vertices[] = { -1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0 }; const GLfixed texCoords[] = { 0, 0, FIXED_ONE, 0, FIXED_ONE, FIXED_ONE, 0, FIXED_ONE }; const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 }; glVertexPointer(3, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FIXED, 0, texCoords); int nelem = sizeof(quadIndices)/sizeof(quadIndices[0]); static float grey; grey += 0.01f; if (grey > 1.0f) { grey = 0.0f; } glClearColor(background, grey, grey, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices); } JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj) { background = 1.0f - background; } opengl/tests/gl_jni/res/0040755 0000000 0000000 00000000000 13077405420 014273 5ustar000000000 0000000 opengl/tests/gl_jni/res/values/0040755 0000000 0000000 00000000000 13077405420 015572 5ustar000000000 0000000 opengl/tests/gl_jni/res/values/strings.xml0100644 0000000 0000000 00000001623 13077405420 020004 0ustar000000000 0000000 GLJNI opengl/tests/gl_jni/src/0040755 0000000 0000000 00000000000 13077405420 014271 5ustar000000000 0000000 opengl/tests/gl_jni/src/com/0040755 0000000 0000000 00000000000 13077405420 015047 5ustar000000000 0000000 opengl/tests/gl_jni/src/com/android/0040755 0000000 0000000 00000000000 13077405420 016467 5ustar000000000 0000000 opengl/tests/gl_jni/src/com/android/gljni/0040755 0000000 0000000 00000000000 13077405420 017572 5ustar000000000 0000000 opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java0100644 0000000 0000000 00000002257 13077405420 023020 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gljni; import android.app.Activity; import android.os.Bundle; public class GLJNIActivity extends Activity { GLJNIView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new GLJNIView(getApplication()); mView.setFocusableInTouchMode(true); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java0100644 0000000 0000000 00000001775 13077405420 021736 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gljni; // Wrapper for native library public class GLJNILib { static { System.loadLibrary("gljni"); } /** * @param width the current view width * @param height the current view height */ public static native void init(int width, int height); public static native void step(); public static native void changeBackground(); } opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java0100644 0000000 0000000 00000005431 13077405420 022133 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.gljni; /* * Copyright (C) 2008 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. */ import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class GLJNIView extends GLSurfaceView { GLJNIView(Context context) { super(context); init(); } public GLJNIView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setRenderer(new Renderer()); } private class Renderer implements GLSurfaceView.Renderer { private static final String TAG = "Renderer"; public void onDrawFrame(GL10 gl) { GLJNILib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GLJNILib.init(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { GLJNILib.changeBackground(); return true; } } opengl/tests/gl_perf/0040755 0000000 0000000 00000000000 13077405420 013656 5ustar000000000 0000000 opengl/tests/gl_perf/Android.mk0100644 0000000 0000000 00000000724 13077405420 015567 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gl2_perf.cpp \ filltest.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ libEGL \ libGLESv2 \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-gl2_perf LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES include $(BUILD_EXECUTABLE) opengl/tests/gl_perf/fill_common.cpp0100644 0000000 0000000 00000021672 13077405420 016665 0ustar000000000 0000000 /* * Copyright (C) 2007 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 "fragment_shaders.cpp" FILE * fOut = NULL; void ptSwap(); static char gCurrentTestName[1024]; static uint32_t gWidth = 0; static uint32_t gHeight = 0; static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { ALOGE("after %s() glError (0x%x)\n", op, error); } } GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); ALOGE("Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } enum { A_POS, A_COLOR, A_TEX0, A_TEX1 }; GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader v"); glAttachShader(program, pixelShader); checkGlError("glAttachShader p"); glBindAttribLocation(program, A_POS, "a_pos"); glBindAttribLocation(program, A_COLOR, "a_color"); glBindAttribLocation(program, A_TEX0, "a_tex0"); glBindAttribLocation(program, A_TEX1, "a_tex1"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); ALOGE("Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } checkGlError("createProgram"); glUseProgram(program); return program; } uint64_t getTime() { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000); } uint64_t gTime; void startTimer() { gTime = getTime(); } static void endTimer(int count) { uint64_t t2 = getTime(); double delta = ((double)(t2 - gTime)) / 1000000000; double pixels = (gWidth * gHeight) * count; double mpps = pixels / delta / 1000000; double dc60 = ((double)count) / delta / 60; if (fOut) { fprintf(fOut, "%s, %f, %f\r\n", gCurrentTestName, mpps, dc60); fflush(fOut); } else { printf("%s, %f, %f\n", gCurrentTestName, mpps, dc60); } ALOGI("%s, %f, %f\r\n", gCurrentTestName, mpps, dc60); } static const char gVertexShader[] = "attribute vec4 a_pos;\n" "attribute vec4 a_color;\n" "attribute vec2 a_tex0;\n" "attribute vec2 a_tex1;\n" "varying vec4 v_color;\n" "varying vec2 v_tex0;\n" "varying vec2 v_tex1;\n" "uniform vec2 u_texOff;\n" "void main() {\n" " v_color = a_color;\n" " v_tex0 = a_tex0;\n" " v_tex1 = a_tex1;\n" " v_tex0.x += u_texOff.x;\n" " v_tex1.y += u_texOff.y;\n" " gl_Position = a_pos;\n" "}\n"; static void setupVA() { static const float vtx[] = { -1.0f,-1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; static const float color[] = { 1.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0f,1.0f, 1.0f,1.0f,0.0f,1.0f, 1.0f,1.0f,1.0f,1.0f }; static const float tex0[] = { 0.0f,0.0f, 1.0f,0.0f, 0.0f,1.0f, 1.0f,1.0f }; static const float tex1[] = { 1.0f,0.0f, 1.0f,1.0f, 0.0f,1.0f, 0.0f,0.0f }; glEnableVertexAttribArray(A_POS); glEnableVertexAttribArray(A_COLOR); glEnableVertexAttribArray(A_TEX0); glEnableVertexAttribArray(A_TEX1); glVertexAttribPointer(A_POS, 2, GL_FLOAT, false, 8, vtx); glVertexAttribPointer(A_COLOR, 4, GL_FLOAT, false, 16, color); glVertexAttribPointer(A_TEX0, 2, GL_FLOAT, false, 8, tex0); glVertexAttribPointer(A_TEX1, 2, GL_FLOAT, false, 8, tex1); } static void randUniform(int pgm, const char *var) { GLint loc = glGetUniformLocation(pgm, var); if (loc >= 0) { float x = ((float)rand()) / RAND_MAX; float y = ((float)rand()) / RAND_MAX; float z = ((float)rand()) / RAND_MAX; float w = ((float)rand()) / RAND_MAX; glUniform4f(loc, x, y, z, w); } } static void doLoop(bool warmup, int pgm, uint32_t passCount) { if (warmup) { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); ptSwap(); glFinish(); return; } startTimer(); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); for (uint32_t ct=0; ct < passCount; ct++) { GLint loc = glGetUniformLocation(pgm, "u_texOff"); glUniform2f(loc, ((float)ct) / passCount, ((float)ct) / 2.f / passCount); randUniform(pgm, "u_color"); randUniform(pgm, "u_0"); randUniform(pgm, "u_1"); randUniform(pgm, "u_2"); randUniform(pgm, "u_3"); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } ptSwap(); glFinish(); endTimer(passCount); } static uint32_t rgb(uint32_t r, uint32_t g, uint32_t b) { uint32_t ret = 0xff000000; ret |= r & 0xff; ret |= (g & 0xff) << 8; ret |= (b & 0xff) << 16; return ret; } void genTextures() { uint32_t *m = (uint32_t *)malloc(1024*1024*4); for (int y=0; y < 1024; y++){ for (int x=0; x < 1024; x++){ m[y*1024 + x] = rgb(x, (((x+y) & 0xff) == 0x7f) * 0xff, y); } } glBindTexture(GL_TEXTURE_2D, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, m); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); for (int y=0; y < 16; y++){ for (int x=0; x < 16; x++){ m[y*16 + x] = rgb(x << 4, (((x+y) & 0xf) == 0x7) * 0xff, y << 4); } } glBindTexture(GL_TEXTURE_2D, 2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, m); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); free(m); } static void doSingleTest(uint32_t pgmNum, int tex) { const char *pgmTxt = gFragmentTests[pgmNum]->txt; int pgm = createProgram(gVertexShader, pgmTxt); if (!pgm) { printf("error running test\n"); return; } GLint loc = glGetUniformLocation(pgm, "u_tex0"); if (loc >= 0) glUniform1i(loc, 0); loc = glGetUniformLocation(pgm, "u_tex1"); if (loc >= 0) glUniform1i(loc, 1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE0); glBlendFunc(GL_ONE, GL_ONE); glDisable(GL_BLEND); //sprintf(str2, "%i, %i, %i, %i, %i, 0", //useVarColor, texCount, modulateFirstTex, extraMath, tex0); //doLoop(true, pgm, w, h, str2); //doLoop(false, pgm, w, h, str2); glEnable(GL_BLEND); sprintf(gCurrentTestName, "%s, %i, %i, 1", gFragmentTests[pgmNum]->name, pgmNum, tex); doLoop(true, pgm, 100); doLoop(false, pgm, 100); } opengl/tests/gl_perf/filltest.cpp0100644 0000000 0000000 00000002467 13077405420 016216 0ustar000000000 0000000 /* * Copyright (C) 2007 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 #include #include #include #include #include #include #include #include #include #include using namespace android; #include "fill_common.cpp" bool doTest(uint32_t w, uint32_t h) { gWidth = w; gHeight = h; setupVA(); genTextures(); printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n"); for (uint32_t num = 0; num < gFragmentTestCount; num++) { doSingleTest(num, 2); if (gFragmentTests[num]->texCount) { doSingleTest(num, 1); } } exit(0); return true; } opengl/tests/gl_perf/fragment_shaders.cpp0100644 0000000 0000000 00000006177 13077405420 017706 0ustar000000000 0000000 typedef struct FragmentTestRec { const char * name; uint32_t texCount; const char * txt; } FragmentTest; static FragmentTest fpFill = { "Solid color", 0, "precision mediump float;\n" "uniform vec4 u_color;\n" "void main() {\n" " gl_FragColor = u_color;\n" "}\n" }; static FragmentTest fpGradient = { "Solid gradient", 0, "precision mediump float;\n" "varying lowp vec4 v_color;\n" "void main() {\n" " gl_FragColor = v_color;\n" "}\n" }; static FragmentTest fpCopyTex = { "Texture copy", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "uniform sampler2D u_tex0;\n" "void main() {\n" " gl_FragColor = texture2D(u_tex0, v_tex0);\n" "}\n" }; static FragmentTest fpCopyTexGamma = { "Texture copy with gamma", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "uniform sampler2D u_tex0;\n" "void main() {\n" " vec4 t = texture2D(u_tex0, v_tex0);\n" " t.rgb = pow(t.rgb, vec3(1.4, 1.4, 1.4));\n" " gl_FragColor = t;\n" "}\n" }; static FragmentTest fpTexSpec = { "Texture spec", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "uniform sampler2D u_tex0;\n" "void main() {\n" " vec4 t = texture2D(u_tex0, v_tex0);\n" " float simSpec = dot(gl_FragCoord.xyz, gl_FragCoord.xyz);\n" " simSpec = pow(clamp(simSpec, 0.1, 1.0), 40.0);\n" " gl_FragColor = t + vec4(simSpec, simSpec, simSpec, simSpec);\n" "}\n" }; static FragmentTest fpDepTex = { "Dependent Lookup", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "uniform sampler2D u_tex0;\n" "void main() {\n" " vec4 t = texture2D(u_tex0, v_tex0);\n" " t += texture2D(u_tex0, t.xy);\n" " gl_FragColor = t;\n" "}\n" }; static FragmentTest fpModulateConstantTex = { "Texture modulate constant", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "uniform sampler2D u_tex0;\n" "uniform vec4 u_color;\n" "void main() {\n" " lowp vec4 c = texture2D(u_tex0, v_tex0);\n" " c *= u_color;\n" " gl_FragColor = c;\n" "}\n" }; static FragmentTest fpModulateVaryingTex = { "Texture modulate gradient", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "varying lowp vec4 v_color;\n" "uniform sampler2D u_tex0;\n" "void main() {\n" " lowp vec4 c = texture2D(u_tex0, v_tex0);\n" " c *= v_color;\n" " gl_FragColor = c;\n" "}\n" }; static FragmentTest fpModulateVaryingConstantTex = { "Texture modulate gradient constant", 1, "precision mediump float;\n" "varying vec2 v_tex0;\n" "varying lowp vec4 v_color;\n" "uniform sampler2D u_tex0;\n" "uniform vec4 u_color;\n" "void main() {\n" " lowp vec4 c = texture2D(u_tex0, v_tex0);\n" " c *= v_color;\n" " c *= u_color;\n" " gl_FragColor = c;\n" "}\n" }; static FragmentTest *gFragmentTests[] = { &fpFill, &fpGradient, &fpCopyTex, &fpCopyTexGamma, &fpTexSpec, &fpDepTex, &fpModulateConstantTex, &fpModulateVaryingTex, &fpModulateVaryingConstantTex, }; static const size_t gFragmentTestCount = sizeof(gFragmentTests) / sizeof(gFragmentTests[0]); opengl/tests/gl_perf/gl2_perf.cpp0100644 0000000 0000000 00000007467 13077405420 016075 0ustar000000000 0000000 /* * Copyright (C) 2007 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 #include #include #include #include #include #include #include #include #include #include using namespace android; static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { fprintf(stderr, "after %s() glError (0x%x)\n", op, error); } } bool doTest(uint32_t w, uint32_t h); static EGLDisplay dpy; static EGLSurface surface; int main(int argc, char** argv) { EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLint w, h; checkEglError(""); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (dpy == EGL_NO_DISPLAY) { printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); return 0; } returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); if (returnValue != EGL_TRUE) { printf("eglInitialize failed\n"); return 0; } WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); if (returnValue) { printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); return 0; } checkEglError("EGLUtils::selectConfigForNativeWindow"); surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (surface == EGL_NO_SURFACE) { printf("gelCreateWindowSurface failed.\n"); return 0; } context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { printf("eglCreateContext failed\n"); return 0; } returnValue = eglMakeCurrent(dpy, surface, surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { return 0; } eglQuerySurface(dpy, surface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; glViewport(0, 0, w, h); for (;;) { doTest(w, h); eglSwapBuffers(dpy, surface); checkEglError("eglSwapBuffers"); } return 0; } void ptSwap() { eglSwapBuffers(dpy, surface); } opengl/tests/gl_perfapp/0040755 0000000 0000000 00000000000 13077405420 014357 5ustar000000000 0000000 opengl/tests/gl_perfapp/Android.mk0100644 0000000 0000000 00000002110 13077405420 016257 0ustar000000000 0000000 ######################################################################### # OpenGL ES Perf App # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GLPerf LOCAL_JNI_SHARED_LIBRARIES := libglperf # Run on Eclair LOCAL_SDK_VERSION := 7 include $(BUILD_PACKAGE) ######################################################################### # Build JNI Shared Library ######################################################################### LOCAL_PATH:= $(LOCAL_PATH)/jni include $(CLEAR_VARS) # Optional tag would mean it doesn't get installed by default LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter LOCAL_SRC_FILES:= \ gl_code.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libEGL \ libGLESv2 LOCAL_MODULE := libglperf include $(BUILD_SHARED_LIBRARY) opengl/tests/gl_perfapp/AndroidManifest.xml0100644 0000000 0000000 00000003011 13077405420 020140 0ustar000000000 0000000 opengl/tests/gl_perfapp/jni/0040755 0000000 0000000 00000000000 13077405420 015137 5ustar000000000 0000000 opengl/tests/gl_perfapp/jni/gl_code.cpp0100644 0000000 0000000 00000005106 13077405420 017236 0ustar000000000 0000000 // OpenGL ES 2.0 code #include #define LOG_TAG "GLPerf gl_code.cpp" #include #include #include #include #include #include #include #include #include "../../gl_perf/fill_common.cpp" ////////////////////////// // Width and height of the screen uint32_t w; uint32_t h; // The stateClock starts at zero and increments by 1 every time we draw a frame. It is used to control which phase of the test we are in. int stateClock; bool done; // Saves the parameters of the test (so we can print them out when we finish the timing.) int pgm; void ptSwap() { } void doTest() { uint32_t testNum = stateClock >> 2; int texSize = ((stateClock >> 1) & 0x1) + 1; if (testNum >= gFragmentTestCount) { ALOGI("done\n"); if (fOut) { fclose(fOut); fOut = NULL; } done = true; return; } // ALOGI("doTest %d %d %d\n", texCount, extraMath, testSubState); // for (uint32_t num = 0; num < gFragmentTestCount; num++) { doSingleTest(testNum, texSize); } extern "C" { JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj); }; JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj, jint width, jint height) { gWidth = width; gHeight = height; if (!done) { stateClock = 0; done = false; setupVA(); genTextures(); const char* fileName = "/sdcard/glperf.csv"; if (fOut != NULL) { ALOGI("Closing partially written output.n"); fclose(fOut); fOut = NULL; } ALOGI("Writing to: %s\n",fileName); fOut = fopen(fileName, "w"); if (fOut == NULL) { ALOGE("Could not open: %s\n", fileName); } ALOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n"); if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n"); } } JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_step(JNIEnv * env, jobject obj) { if (! done) { if (stateClock > 0 && ((stateClock & 1) == 0)) { //endTimer(100); } doTest(); stateClock++; } else { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); } } opengl/tests/gl_perfapp/res/0040755 0000000 0000000 00000000000 13077405420 015150 5ustar000000000 0000000 opengl/tests/gl_perfapp/res/values/0040755 0000000 0000000 00000000000 13077405420 016447 5ustar000000000 0000000 opengl/tests/gl_perfapp/res/values/strings.xml0100644 0000000 0000000 00000001625 13077405420 020663 0ustar000000000 0000000 GLPerf opengl/tests/gl_perfapp/src/0040755 0000000 0000000 00000000000 13077405420 015146 5ustar000000000 0000000 opengl/tests/gl_perfapp/src/com/0040755 0000000 0000000 00000000000 13077405420 015724 5ustar000000000 0000000 opengl/tests/gl_perfapp/src/com/android/0040755 0000000 0000000 00000000000 13077405420 017344 5ustar000000000 0000000 opengl/tests/gl_perfapp/src/com/android/glperf/0040755 0000000 0000000 00000000000 13077405420 020623 5ustar000000000 0000000 opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfActivity.java0100644 0000000 0000000 00000002503 13077405420 024317 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.glperf; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; import java.io.File; public class GLPerfActivity extends Activity { GLPerfView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mView = new GLPerfView(getApplication()); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfLib.java0100644 0000000 0000000 00000001715 13077405420 023235 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.glperf; // Wrapper for native library public class GLPerfLib { static { System.loadLibrary("glperf"); } /** * @param width the current view width * @param height the current view height */ public static native void init(int width, int height); public static native void step(); } opengl/tests/gl_perfapp/src/com/android/glperf/GLPerfView.java0100644 0000000 0000000 00000026762 13077405420 023452 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.glperf; /* * Copyright (C) 2008 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. */ import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class GLPerfView extends GLSurfaceView { private static String TAG = "GLPerfView"; public GLPerfView(Context context) { super(context); init(false, 0, 0); } public GLPerfView(Context context, boolean translucent, int depth, int stencil) { super(context); init(translucent, depth, stencil); } private void init(boolean translucent, int depth, int stencil) { setEGLContextFactory(new ContextFactory()); setEGLConfigChooser( translucent ? new ConfigChooser(8,8,8,8, depth, stencil) : new ConfigChooser(5,6,5,0, depth, stencil)); setRenderer(new Renderer()); } private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES 2.0 context"); checkEglError("Before eglCreateContext", egl); int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); checkEglError("After eglCreateContext", egl); return context; } public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { egl.eglDestroyContext(display, context); } } private static void checkEglError(String prompt, EGL10 egl) { int error; while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); } } private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { mRedSize = r; mGreenSize = g; mBlueSize = b; mAlphaSize = a; mDepthSize = depth; mStencilSize = stencil; } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException("No configs match configSpec"); } EGLConfig[] configs = new EGLConfig[numConfigs]; egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); // printConfigs(egl, display, configs); return chooseConfig(egl, display, configs); } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { EGLConfig closestConfig = null; int closestDistance = 1000; 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); int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize); if (distance < closestDistance) { closestDistance = distance; closestConfig = config; } } } return closestConfig; } 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; } private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { int numConfigs = configs.length; Log.w(TAG, String.format("%d configurations", numConfigs)); for (int i = 0; i < numConfigs; i++) { Log.w(TAG, String.format("Configuration %d:\n", i)); printConfig(egl, display, configs[i]); } } private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config) { int[] attributes = { EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE, EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_CONFIG_ID, EGL10.EGL_LEVEL, EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH, EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE, 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE, 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE, EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE, 0x3042 // EGL10.EGL_CONFORMANT }; String[] names = { "EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT", "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT", "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH", "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES", "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE", "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE", "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL", "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT" }; int[] value = new int[1]; for (int i = 0; i < attributes.length; i++) { int attribute = attributes[i]; String name = names[i]; if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { Log.w(TAG, String.format(" %s: %d\n", name, value[0])); } else { // Log.w(TAG, String.format(" %s: failed\n", name)); while (egl.eglGetError() != EGL10.EGL_SUCCESS); } } } // Subclasses can adjust these values: protected int mRedSize; protected int mGreenSize; protected int mBlueSize; protected int mAlphaSize; protected int mDepthSize; protected int mStencilSize; private int[] mValue = new int[1]; } private static class Renderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl) { GLPerfLib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GLPerfLib.init(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } } } opengl/tests/gl_yuvtex/0040755 0000000 0000000 00000000000 13077405420 014266 5ustar000000000 0000000 opengl/tests/gl_yuvtex/Android.mk0100644 0000000 0000000 00000000724 13077405420 016177 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gl_yuvtex.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv1_CM \ libutils \ libui \ libgui LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-gl_yuvtex LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES include $(BUILD_EXECUTABLE) opengl/tests/gl_yuvtex/gl_yuvtex.cpp0100644 0000000 0000000 00000024753 13077405420 017030 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); const char *v = (const char *) glGetString(s); // int error = glGetError(); // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, // (unsigned int) v); // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) // fprintf(stderr, "GL %s = %s\n", name, v); // else // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); fprintf(stderr, "GL %s = %s\n", name, v); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error); } } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { fprintf(stderr, "after %s() glError (0x%x)\n", op, error); } } bool setupGraphics(int w, int h) { glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } int align(int x, int a) { return (x + (a-1)) & (~(a-1)); } const int yuvTexWidth = 600; const int yuvTexHeight = 480; const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12; const int yuvTexOffsetY = 0; const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf; const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight; const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2; const int yuvTexStrideU = yuvTexStrideV; const bool yuvTexSameUV = false; static sp yuvTexBuffer; static GLuint yuvTex; bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) { int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1; int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1; yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, yuvTexUsage); char* buf = NULL; status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); if (err != 0) { fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err); return false; } for (int x = 0; x < yuvTexWidth; x++) { for (int y = 0; y < yuvTexHeight; y++) { int parityX = (x / blockWidth) & 1; int parityY = (y / blockHeight) & 1; unsigned char intensity = (parityX ^ parityY) ? 63 : 191; buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) { buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; if (yuvTexSameUV) { buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity; } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) { buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity; } } } } err = yuvTexBuffer->unlock(); if (err != 0) { fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err); return false; } EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer(); EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, 0); checkEglError("eglCreateImageKHR"); if (img == EGL_NO_IMAGE_KHR) { return false; } glGenTextures(1, &yuvTex); checkGlError("glGenTextures"); glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); checkGlError("glBindTexture"); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img); checkGlError("glEGLImageTargetTexture2DOES"); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGlError("glTexParameteri"); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGlError("glTexParameteri"); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); checkGlError("glTexEnvx"); GLint crop[4] = { 0, 0, yuvTexWidth, yuvTexHeight }; glTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_CROP_RECT_OES, crop); checkGlError("glTexParameteriv"); return true; } void renderFrame(int w, int h) { glClearColor(0.0f, 0.0f, 1.0f, 1.0f); checkGlError("glClearColor"); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); checkGlError("glBindTexture"); glEnable(GL_TEXTURE_EXTERNAL_OES); checkGlError("glEnable"); glDrawTexiOES(0, 0, 0, w, h); checkGlError("glDrawTexiOES"); } void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { printf(" %s: ", names[j].name); printf("%d (0x%x)", value, value); } } printf("\n"); } int main(int argc, char** argv) { EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; EGLint s_configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLSurface surface; EGLint w, h; EGLDisplay dpy; checkEglError(""); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (dpy == EGL_NO_DISPLAY) { printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); return 0; } returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); if (returnValue != EGL_TRUE) { printf("eglInitialize failed\n"); return 0; } WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); if (returnValue) { printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); return 1; } checkEglError("EGLUtils::selectConfigForNativeWindow"); printf("Chose this configuration:\n"); printEGLConfiguration(dpy, myConfig); surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (surface == EGL_NO_SURFACE) { printf("gelCreateWindowSurface failed.\n"); return 1; } context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { printf("eglCreateContext failed\n"); return 1; } returnValue = eglMakeCurrent(dpy, surface, surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { return 1; } eglQuerySurface(dpy, surface, EGL_WIDTH, &w); checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); checkEglError("eglQuerySurface"); GLint dim = w < h ? w : h; fprintf(stderr, "Window dimensions: %d x %d\n", w, h); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); if(!setupYuvTexSurface(dpy, context)) { fprintf(stderr, "Could not set up texture surface.\n"); return 1; } if(!setupGraphics(w, h)) { fprintf(stderr, "Could not set up graphics.\n"); return 1; } for (;;) { static int dir = -1; renderFrame(w, h); eglSwapBuffers(dpy, surface); checkEglError("eglSwapBuffers"); if (w <= 10 || h <= 10) { dir = -dir; } if (w >= 1300 || h >= 900) { dir = -dir; } w += dir; h += dir; } return 0; } opengl/tests/gldual/0040755 0000000 0000000 00000000000 13077405420 013510 5ustar000000000 0000000 opengl/tests/gldual/Android.mk0100644 0000000 0000000 00000002050 13077405420 015413 0ustar000000000 0000000 ######################################################################### # OpenGL ES JNI sample # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GLDual LOCAL_JNI_SHARED_LIBRARIES := libgldualjni include $(BUILD_PACKAGE) ######################################################################### # Build JNI Shared Library ######################################################################### LOCAL_PATH:= $(LOCAL_PATH)/jni include $(CLEAR_VARS) # Optional tag would mean it doesn't get installed by default LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter LOCAL_SRC_FILES:= \ gl_code.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libEGL \ libGLESv2 LOCAL_MODULE := libgldualjni include $(BUILD_SHARED_LIBRARY) opengl/tests/gldual/AndroidManifest.xml0100644 0000000 0000000 00000002463 13077405420 017303 0ustar000000000 0000000 opengl/tests/gldual/jni/0040755 0000000 0000000 00000000000 13077405420 014270 5ustar000000000 0000000 opengl/tests/gldual/jni/gl_code.cpp0100644 0000000 0000000 00000011502 13077405420 016364 0ustar000000000 0000000 // OpenGL ES 2.0 code #include #define LOG_TAG "GL2JNI gl_code.cpp" #include #include #include #include #include #include #include static void printGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); ALOGI("GL %s = %s\n", name, v); } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { ALOGI("after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 vPosition;\n" "void main() {\n" " gl_Position = vPosition;\n" "}\n"; static const char gFragmentShader[] = "precision mediump float;\n" "void main() {\n" " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; GLuint loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); ALOGE("Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); ALOGE("Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } GLuint gProgram; GLuint gvPositionHandle; bool setupGraphics(int w, int h) { printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); ALOGI("setupGraphics(%d, %d)", w, h); gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { ALOGE("Could not create program."); return false; } gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); checkGlError("glGetAttribLocation"); ALOGI("glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f }; void renderFrame() { static float grey; grey += 0.01f; if (grey > 1.0f) { grey = 0.0f; } glClearColor(grey, grey, grey, 1.0f); checkGlError("glClearColor"); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); checkGlError("glVertexAttribPointer"); glEnableVertexAttribArray(gvPositionHandle); checkGlError("glEnableVertexAttribArray"); glDrawArrays(GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); } extern "C" { JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj); }; JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_init(JNIEnv * env, jobject obj, jint width, jint height) { setupGraphics(width, height); } JNIEXPORT void JNICALL Java_com_android_gldual_GLDualLib_step(JNIEnv * env, jobject obj) { renderFrame(); } opengl/tests/gldual/res/0040755 0000000 0000000 00000000000 13077405420 014301 5ustar000000000 0000000 opengl/tests/gldual/res/layout/0040755 0000000 0000000 00000000000 13077405420 015616 5ustar000000000 0000000 opengl/tests/gldual/res/layout/gldual_activity.xml0100644 0000000 0000000 00000002331 13077405420 021520 0ustar000000000 0000000 opengl/tests/gldual/res/values/0040755 0000000 0000000 00000000000 13077405420 015600 5ustar000000000 0000000 opengl/tests/gldual/res/values/strings.xml0100644 0000000 0000000 00000001625 13077405420 020014 0ustar000000000 0000000 GLDual opengl/tests/gldual/src/0040755 0000000 0000000 00000000000 13077405420 014277 5ustar000000000 0000000 opengl/tests/gldual/src/com/0040755 0000000 0000000 00000000000 13077405420 015055 5ustar000000000 0000000 opengl/tests/gldual/src/com/android/0040755 0000000 0000000 00000000000 13077405420 016475 5ustar000000000 0000000 opengl/tests/gldual/src/com/android/gldual/0040755 0000000 0000000 00000000000 13077405420 017745 5ustar000000000 0000000 opengl/tests/gldual/src/com/android/gldual/GLDualActivity.java0100644 0000000 0000000 00000003146 13077405420 023436 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gldual; import android.app.Activity; import android.content.Context; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; public class GLDualActivity extends Activity { GLSurfaceView mGLView; GLDualGL2View mGL2View; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); View root = getLayoutInflater().inflate(R.layout.gldual_activity, null); mGLView = (GLSurfaceView) root.findViewById(R.id.gl1); mGLView.setEGLConfigChooser(5,6,5,0,0,0); mGLView.setRenderer(new TriangleRenderer()); mGL2View = (GLDualGL2View) root.findViewById(R.id.gl2); setContentView(root); } @Override protected void onPause() { super.onPause(); mGLView.onPause(); mGL2View.onPause(); } @Override protected void onResume() { super.onResume(); mGLView.onResume(); mGL2View.onResume(); } } opengl/tests/gldual/src/com/android/gldual/GLDualGL2View.java0100644 0000000 0000000 00000027074 13077405420 023067 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.gldual; /* * Copyright (C) 2008 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. */ import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class GLDualGL2View extends GLSurfaceView { private static String TAG = "GLDualGL2View"; public GLDualGL2View(Context context) { super(context); init(false, 0, 0); } public GLDualGL2View(Context context, AttributeSet set) { super(context, set); init(false, 0, 0); } public GLDualGL2View(Context context, boolean translucent, int depth, int stencil) { super(context); init(translucent, depth, stencil); } private void init(boolean translucent, int depth, int stencil) { setEGLContextFactory(new ContextFactory()); setEGLConfigChooser( translucent ? new ConfigChooser(8,8,8,8, depth, stencil) : new ConfigChooser(5,6,5,0, depth, stencil)); setRenderer(new Renderer()); } private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES 2.0 context"); checkEglError("Before eglCreateContext", egl); int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); checkEglError("After eglCreateContext", egl); return context; } public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { egl.eglDestroyContext(display, context); } } private static void checkEglError(String prompt, EGL10 egl) { int error; while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); } } private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { mRedSize = r; mGreenSize = g; mBlueSize = b; mAlphaSize = a; mDepthSize = depth; mStencilSize = stencil; } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException("No configs match configSpec"); } EGLConfig[] configs = new EGLConfig[numConfigs]; egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); // printConfigs(egl, display, configs); return chooseConfig(egl, display, configs); } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { EGLConfig closestConfig = null; int closestDistance = 1000; 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); int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize); if (distance < closestDistance) { closestDistance = distance; closestConfig = config; } } } return closestConfig; } 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; } private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { int numConfigs = configs.length; Log.w(TAG, String.format("%d configurations", numConfigs)); for (int i = 0; i < numConfigs; i++) { Log.w(TAG, String.format("Configuration %d:\n", i)); printConfig(egl, display, configs[i]); } } private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config) { int[] attributes = { EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE, EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_CONFIG_ID, EGL10.EGL_LEVEL, EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH, EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE, 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE, 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE, EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE, 0x3042 // EGL10.EGL_CONFORMANT }; String[] names = { "EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT", "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT", "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH", "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES", "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE", "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE", "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL", "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT" }; int[] value = new int[1]; for (int i = 0; i < attributes.length; i++) { int attribute = attributes[i]; String name = names[i]; if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { Log.w(TAG, String.format(" %s: %d\n", name, value[0])); } else { // Log.w(TAG, String.format(" %s: failed\n", name)); while (egl.eglGetError() != EGL10.EGL_SUCCESS); } } } // Subclasses can adjust these values: protected int mRedSize; protected int mGreenSize; protected int mBlueSize; protected int mAlphaSize; protected int mDepthSize; protected int mStencilSize; private int[] mValue = new int[1]; } private static class Renderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl) { GLDualLib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GLDualLib.init(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } } } opengl/tests/gldual/src/com/android/gldual/GLDualLib.java0100644 0000000 0000000 00000001720 13077405420 022344 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.gldual; // Wrapper for native library public class GLDualLib { static { System.loadLibrary("gldualjni"); } /** * @param width the current view width * @param height the current view height */ public static native void init(int width, int height); public static native void step(); } opengl/tests/gldual/src/com/android/gldual/TriangleRenderer.java0100644 0000000 0000000 00000011560 13077405420 024044 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.gldual; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView; import android.opengl.GLU; import android.os.SystemClock; public class TriangleRenderer implements GLSurfaceView.Renderer{ public TriangleRenderer() { mTriangle = new Triangle(); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { /* * By default, OpenGL enables features that improve quality * but reduce performance. One might want to tweak that * especially on software renderer. */ gl.glDisable(GL10.GL_DITHER); /* * Some one-time OpenGL initialization can be made here * probably based on features of this particular context */ gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); gl.glClearColor(.5f, .5f, .5f, 1); gl.glShadeModel(GL10.GL_SMOOTH); } public void onDrawFrame(GL10 gl) { /* * By default, OpenGL enables features that improve quality * but reduce performance. One might want to tweak that * especially on software renderer. */ gl.glDisable(GL10.GL_DITHER); /* * Usually, the first thing one might want to do is to clear * the screen. The most efficient way of doing this is to use * glClear(). */ gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); /* * Now we're ready to draw some 3D objects */ gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); long time = SystemClock.uptimeMillis() % 4000L; float angle = 0.090f * ((int) time); gl.glRotatef(angle, 0, 0, 1.0f); mTriangle.draw(gl); } public void onSurfaceChanged(GL10 gl, int w, int h) { gl.glViewport(0, 0, w, h); /* * Set our projection matrix. This doesn't have to be done * each time we draw, but usually a new projection needs to * be set when the viewport is resized. */ float ratio = (float) w / h; gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); } private Triangle mTriangle; } class Triangle { public Triangle() { // Buffers to be passed to gl*Pointer() functions // must be direct, i.e., they must be placed on the // native heap where the garbage collector cannot // move them. // // Buffers with multi-byte datatypes (e.g., short, int, float) // must have their byte order set to native order ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4); vbb.order(ByteOrder.nativeOrder()); mFVertexBuffer = vbb.asFloatBuffer(); ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4); tbb.order(ByteOrder.nativeOrder()); ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2); ibb.order(ByteOrder.nativeOrder()); mIndexBuffer = ibb.asShortBuffer(); // A unit-sided equalateral triangle centered on the origin. float[] coords = { // X, Y, Z -0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0 }; for (int i = 0; i < VERTS; i++) { for(int j = 0; j < 3; j++) { mFVertexBuffer.put(coords[i*3+j] * 2.0f); } } for(int i = 0; i < VERTS; i++) { mIndexBuffer.put((short) i); } mFVertexBuffer.position(0); mIndexBuffer.position(0); } public void draw(GL10 gl) { gl.glFrontFace(GL10.GL_CCW); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer); gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS, GL10.GL_UNSIGNED_SHORT, mIndexBuffer); } private final static int VERTS = 3; private FloatBuffer mFVertexBuffer; private ShortBuffer mIndexBuffer; } opengl/tests/gralloc/0040755 0000000 0000000 00000000000 13077405420 013663 5ustar000000000 0000000 opengl/tests/gralloc/Android.mk0100644 0000000 0000000 00000000375 13077405420 015576 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ gralloc.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libui LOCAL_MODULE:= test-opengl-gralloc LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/gralloc/gralloc.cpp0100644 0000000 0000000 00000005110 13077405420 016004 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ #define LOG_TAG "StopWatch" #include #include #include #include #include #include using namespace android; void* lamecpy(void* d, void const* s, size_t size) { char* dst = (char*)d; char const* src = (char const*)s; while (size) { *dst++ = *src++; size--; } return d; } int main(int argc, char** argv) { size_t size = 128*256*4; void* temp = malloc(size); void* temp2 = malloc(size); memset(temp, 0, size); memset(temp2, 0, size); sp buffer = new GraphicBuffer(128, 256, HAL_PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); status_t err = buffer->initCheck(); if (err != NO_ERROR) { printf("%s\n", strerror(-err)); return 0; } void* vaddr; buffer->lock( GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr); { StopWatch watch("memset"); for (int i=0 ; i<10 ; i++) memset(vaddr, 0, size); } { StopWatch watch("memcpy baseline"); for (int i=0 ; i<10 ; i++) memcpy(temp, temp2, size); } { StopWatch watch("memcpy from gralloc"); for (int i=0 ; i<10 ; i++) memcpy(temp, vaddr, size); } { StopWatch watch("memcpy into gralloc"); for (int i=0 ; i<10 ; i++) memcpy(vaddr, temp, size); } { StopWatch watch("lamecpy baseline"); for (int i=0 ; i<10 ; i++) lamecpy(temp, temp2, size); } { StopWatch watch("lamecpy from gralloc"); for (int i=0 ; i<10 ; i++) lamecpy(temp, vaddr, size); } { StopWatch watch("lamecpy into gralloc"); for (int i=0 ; i<10 ; i++) lamecpy(vaddr, temp, size); } buffer->unlock(); return 0; } opengl/tests/hwc/0040755 0000000 0000000 00000000000 13077405420 013021 5ustar000000000 0000000 opengl/tests/hwc/Android.mk0100644 0000000 0000000 00000007160 13077405420 014733 0ustar000000000 0000000 # Copyright (C) 2010 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE_TAGS := tests LOCAL_MODULE:= libhwcTest LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcTestLib.cpp LOCAL_C_INCLUDES += system/extras/tests/include \ $(call include-path-for, opengl-tests-includes) \ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE:= hwcStress LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcStress.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libutils \ liblog \ libui \ libhardware \ LOCAL_STATIC_LIBRARIES := \ libtestUtil \ libglTest \ libhwcTest \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE:= hwcRects LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcRects.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libutils \ liblog \ libui \ libhardware \ LOCAL_STATIC_LIBRARIES := \ libtestUtil \ libglTest \ libhwcTest \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE:= hwcColorEquiv LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcColorEquiv.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libutils \ liblog \ libui \ libhardware \ LOCAL_STATIC_LIBRARIES := \ libtestUtil \ libglTest \ libhwcTest \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE:= hwcCommit LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcCommit.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv2 \ libutils \ liblog \ libui \ libhardware \ LOCAL_STATIC_LIBRARIES := \ libtestUtil \ libglTest \ libhwcTest \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) opengl/tests/hwc/hwcColorEquiv.cpp0100644 0000000 0000000 00000035410 13077405420 016317 0ustar000000000 0000000 /* * 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. * */ /* * Hardware Composer Color Equivalence * * Synopsis * hwc_colorequiv [options] eFmt * * options: -v - verbose * -s <0.##, 0.##, 0.##> - Start color (default: <0.0, 0.0, 0.0> * -e <0.##, 0.##, 0.##> - Ending color (default: <1.0, 1.0, 1.0> * -r fmt - reference graphic format * -D #.## - End of test delay * * graphic formats: * RGBA8888 (reference frame default) * RGBX8888 * RGB888 * RGB565 * BGRA8888 * RGBA5551 * RGBA4444 * YV12 * * Description * Renders a horizontal blend in two frames. The first frame is rendered * in the upper third of the display and is called the reference frame. * The second frame is displayed in the middle third and is called the * equivalence frame. The primary purpose of this utility is to verify * that the colors produced in the reference and equivalence frames are * the same. The colors are the same when the colors are the same * vertically between the reference and equivalence frames. * * By default the reference frame is rendered through the use of the * RGBA8888 graphic format. The -r option can be used to specify a * non-default reference frame graphic format. The graphic format of * the equivalence frame is determined by a single required positional * parameter. Intentionally there is no default for the graphic format * of the equivalence frame. * * The horizontal blend in the reference frame is produced from a linear * interpolation from a start color (default: <0.0, 0.0, 0.0> on the left * side to an end color (default <1.0, 1.0, 1.0> on the right side. Where * possible the equivalence frame is rendered with the equivalent color * from the reference frame. A color of black is used in the equivalence * frame for cases where an equivalent color does not exist. */ #define LOG_TAG "hwcColorEquivTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hwcTestLib.h" using namespace std; using namespace android; // Defaults for command-line options const bool defaultVerbose = false; const ColorFract defaultStartColor(0.0, 0.0, 0.0); const ColorFract defaultEndColor(1.0, 1.0, 1.0); const char *defaultRefFormat = "RGBA8888"; const float defaultEndDelay = 2.0; // Default delay after rendering graphics // Defines #define MAXSTR 100 #define MAXCMD 200 #define BITSPERBYTE 8 // TODO: Obtain from , once // it has been added #define CMD_STOP_FRAMEWORK "stop 2>&1" #define CMD_START_FRAMEWORK "start 2>&1" // Macros #define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array #define MEMCLR(addr, size) do { \ memset((addr), 0, (size)); \ } while (0) // Globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; // Functions prototypes void init(void); void printSyntax(const char *cmd); // Command-line option settings static bool verbose = defaultVerbose; static ColorFract startRefColor = defaultStartColor; static ColorFract endRefColor = defaultEndColor; static float endDelay = defaultEndDelay; static const struct hwcTestGraphicFormat *refFormat = hwcTestGraphicFormatLookup(defaultRefFormat); static const struct hwcTestGraphicFormat *equivFormat; /* * Main * * Performs the following high-level sequence of operations: * * 1. Command-line parsing * * 2. Stop framework * * 3. Initialization * * 4. Create Hardware Composer description of reference and equivalence frames * * 5. Have Hardware Composer render the reference and equivalence frames * * 6. Delay for amount of time given by endDelay * * 7. Start framework */ int main(int argc, char *argv[]) { int rv, opt; bool error; char *chptr; char cmd[MAXCMD]; string str; testSetLogCatTag(LOG_TAG); assert(refFormat != NULL); testSetLogCatTag(LOG_TAG); // Parse command line arguments while ((opt = getopt(argc, argv, "vs:e:r:D:?h")) != -1) { switch (opt) { case 'D': // End of test delay // Delay between completion of final pass and restart // of framework endDelay = strtod(optarg, &chptr); if ((*chptr != '\0') || (endDelay < 0.0)) { testPrintE("Invalid command-line specified end of test delay " "of: %s", optarg); exit(1); } break; case 's': // Starting reference color str = optarg; while (optind < argc) { if (*argv[optind] == '-') { break; } char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; if ((endChar == '>') || (endChar == ']')) { break; } str += " " + string(argv[optind++]); } { istringstream in(str); startRefColor = hwcTestParseColor(in, error); // Any parse error or characters not used by parser if (error || (((unsigned int) in.tellg() != in.str().length()) && (in.tellg() != (streampos) -1))) { testPrintE("Invalid command-line specified start " "reference color of: %s", str.c_str()); exit(2); } } break; case 'e': // Ending reference color str = optarg; while (optind < argc) { if (*argv[optind] == '-') { break; } char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; if ((endChar == '>') || (endChar == ']')) { break; } str += " " + string(argv[optind++]); } { istringstream in(str); endRefColor = hwcTestParseColor(in, error); // Any parse error or characters not used by parser if (error || (((unsigned int) in.tellg() != in.str().length()) && (in.tellg() != (streampos) -1))) { testPrintE("Invalid command-line specified end " "reference color of: %s", str.c_str()); exit(3); } } break; case 'r': // Reference graphic format refFormat = hwcTestGraphicFormatLookup(optarg); if (refFormat == NULL) { testPrintE("Unkown command-line specified reference graphic " "format of: %s", optarg); printSyntax(basename(argv[0])); exit(4); } break; case 'v': // Verbose verbose = true; break; case 'h': // Help case '?': default: printSyntax(basename(argv[0])); exit(((optopt == 0) || (optopt == '?')) ? 0 : 5); } } // Expect a single positional parameter, which specifies the // equivalence graphic format. if (argc != (optind + 1)) { testPrintE("Expected a single command-line postional parameter"); printSyntax(basename(argv[0])); exit(6); } equivFormat = hwcTestGraphicFormatLookup(argv[optind]); if (equivFormat == NULL) { testPrintE("Unkown command-line specified equivalence graphic " "format of: %s", argv[optind]); printSyntax(basename(argv[0])); exit(7); } testPrintI("refFormat: %u %s", refFormat->format, refFormat->desc); testPrintI("equivFormat: %u %s", equivFormat->format, equivFormat->desc); testPrintI("startRefColor: %s", ((string) startRefColor).c_str()); testPrintI("endRefColor: %s", ((string) endRefColor).c_str()); testPrintI("endDelay: %f", endDelay); // Stop framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); exit(8); } testExecCmd(cmd); testDelay(1.0); // TODO - needs means to query whether asynchronous stop // framework operation has completed. For now, just wait // a long time. init(); // Use the upper third of the display for the reference frame and // the middle third for the equivalence frame. unsigned int refHeight = height / 3; unsigned int refPosX = 0; // Reference frame X position unsigned int refWidth = width - refPosX; if ((refWidth & refFormat->wMod) != 0) { refWidth += refFormat->wMod - (refWidth % refFormat->wMod); } unsigned int equivHeight = height / 3; unsigned int equivPosX = 0; // Equivalence frame X position unsigned int equivWidth = width - equivPosX; if ((equivWidth & equivFormat->wMod) != 0) { equivWidth += equivFormat->wMod - (equivWidth % equivFormat->wMod); } // Create reference and equivalence graphic buffers const unsigned int numFrames = 2; sp refFrame; refFrame = new GraphicBuffer(refWidth, refHeight, refFormat->format, texUsage); if ((rv = refFrame->initCheck()) != NO_ERROR) { testPrintE("refFrame initCheck failed, rv: %i", rv); testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, refFormat->format, hwcTestGraphicFormat2str(refFormat->format)); exit(9); } testPrintI("refFrame width: %u height: %u format: %u %s", refWidth, refHeight, refFormat->format, hwcTestGraphicFormat2str(refFormat->format)); sp equivFrame; equivFrame = new GraphicBuffer(equivWidth, equivHeight, equivFormat->format, texUsage); if ((rv = refFrame->initCheck()) != NO_ERROR) { testPrintE("refFrame initCheck failed, rv: %i", rv); testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, refFormat->format, hwcTestGraphicFormat2str(refFormat->format)); exit(10); } testPrintI("equivFrame width: %u height: %u format: %u %s", equivWidth, equivHeight, equivFormat->format, hwcTestGraphicFormat2str(equivFormat->format)); // Fill the frames with a horizontal blend hwcTestFillColorHBlend(refFrame.get(), refFormat->format, startRefColor, endRefColor); hwcTestFillColorHBlend(equivFrame.get(), refFormat->format, startRefColor, endRefColor); hwc_display_contents_1_t *list; size_t size = sizeof(hwc_display_contents_1_t) + numFrames * sizeof(hwc_layer_1_t); if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { testPrintE("Allocate list failed"); exit(11); } list->flags = HWC_GEOMETRY_CHANGED; list->numHwLayers = numFrames; hwc_layer_1_t *layer = &list->hwLayers[0]; layer->handle = refFrame->handle; layer->blending = HWC_BLENDING_NONE; layer->sourceCrop.left = 0; layer->sourceCrop.top = 0; layer->sourceCrop.right = width; layer->sourceCrop.bottom = refHeight; layer->displayFrame.left = 0; layer->displayFrame.top = 0; layer->displayFrame.right = width; layer->displayFrame.bottom = refHeight; layer->visibleRegionScreen.numRects = 1; layer->visibleRegionScreen.rects = &layer->displayFrame; layer++; layer->handle = equivFrame->handle; layer->blending = HWC_BLENDING_NONE; layer->sourceCrop.left = 0; layer->sourceCrop.top = 0; layer->sourceCrop.right = width; layer->sourceCrop.bottom = equivHeight; layer->displayFrame.left = 0; layer->displayFrame.top = refHeight; layer->displayFrame.right = width; layer->displayFrame.bottom = layer->displayFrame.top + equivHeight; layer->visibleRegionScreen.numRects = 1; layer->visibleRegionScreen.rects = &layer->displayFrame; // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); } // Turn off the geometry changed flag list->flags &= ~HWC_GEOMETRY_CHANGED; if (verbose) {hwcTestDisplayListHandles(list); } list->dpy = dpy; list->sur = surface; hwcDevice->set(hwcDevice, 1, &list); testDelay(endDelay); // Start framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); exit(12); } testExecCmd(cmd); return 0; } void init(void) { // Seed pseudo random number generator // Seeding causes fill horizontal blend to fill the pad area with // a deterministic set of values. srand48(0); hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); hwcTestOpenHwc(&hwcDevice); } void printSyntax(const char *cmd) { testPrintE(" %s [options] graphicFormat", cmd); testPrintE(" options:"); testPrintE(" -s <0.##, 0.##, 0.##> - Starting reference color"); testPrintE(" -e <0.##, 0.##, 0.##> - Ending reference color"); testPrintE(" -r format - Reference graphic format"); testPrintE(" -D #.## - End of test delay"); testPrintE(" -v Verbose"); testPrintE(""); testPrintE(" graphic formats:"); for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { testPrintE(" %s", hwcTestGraphicFormat[n1].desc); } } opengl/tests/hwc/hwcCommit.cpp0100644 0000000 0000000 00000151154 13077405420 015463 0ustar000000000 0000000 /* * 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. * */ /* * Hardware Composer Commit Points * * Synopsis * hwcCommit [options] graphicFormat ... * options: * -s [width, height] - Starting dimension * -v - Verbose * * graphic formats: * RGBA8888 (reference frame default) * RGBX8888 * RGB888 * RGB565 * BGRA8888 * RGBA5551 * RGBA4444 * YV12 * * Description * The Hardware Composer (HWC) Commit test is a benchmark that * discovers the points at which the HWC will commit to rendering an * overlay(s). Before rendering a set of overlays, the HWC is shown * the list through a prepare call. During the prepare call the HWC * is able to examine the list and specify which overlays it is able * to handle. The overlays that it can't handle are typically composited * by a higher level (e.g. Surface Flinger) and then the original list * plus a composit of what HWC passed on are provided back to the HWC * for rendering. * * Once an implementation of the HWC has been shipped, a regression would * likely occur if a latter implementation started passing on conditions * that it used to commit to. The primary purpose of this benchmark * is the automated discovery of the commit points, where an implementation * is on the edge between committing and not committing. These are commonly * referred to as commit points. Between implementations changes to the * commit points are allowed, as long as they improve what the HWC commits * to. Once an implementation of the HWC is shipped, the commit points are * not allowed to regress in future implementations. * * This benchmark takes a sampling and then adjusts until it finds a * commit point. It doesn't exhaustively check all possible conditions, * which do to the number of combinations would be impossible. Instead * it starts its search from a starting dimension, that can be changed * via the -s option. The search is also bounded by a set of search * limits, that are hard-coded into a structure of constants named * searchLimits. Results that happen to reach a searchLimit are prefixed * with >=, so that it is known that the value could possibly be larger. * * Measurements are made for each of the graphic formats specified as * positional parameters on the command-line. If no graphic formats * are specified on the command line, then by default measurements are * made and reported for each of the known graphic format. */ #define LOG_TAG "hwcCommitTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hwcTestLib.h" using namespace std; using namespace android; // Defaults const HwcTestDim defaultStartDim = HwcTestDim(100, 100); const bool defaultVerbose = false; const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; const int32_t defaultTransform = 0; const uint32_t defaultBlend = HWC_BLENDING_NONE; const ColorFract defaultColor(0.5, 0.5, 0.5); const float defaultAlpha = 1.0; // Opaque const HwcTestDim defaultSourceDim(1, 1); // Global Constants const uint32_t printFieldWidth = 2; const struct searchLimits { uint32_t numOverlays; HwcTestDim sourceCrop; } searchLimits = { 10, HwcTestDim(3000, 2000), }; const struct transformType { const char *desc; uint32_t id; } transformType[] = { {"fliph", HWC_TRANSFORM_FLIP_H}, {"flipv", HWC_TRANSFORM_FLIP_V}, {"rot90", HWC_TRANSFORM_ROT_90}, {"rot180", HWC_TRANSFORM_ROT_180}, {"rot270", HWC_TRANSFORM_ROT_270}, }; const struct blendType { const char *desc; uint32_t id; } blendType[] = { {"none", HWC_BLENDING_NONE}, {"premult", HWC_BLENDING_PREMULT}, {"coverage", HWC_BLENDING_COVERAGE}, }; // Defines #define MAXCMD 200 #define CMD_STOP_FRAMEWORK "stop 2>&1" #define CMD_START_FRAMEWORK "start 2>&1" // Macros #define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array // Local types class Rectangle { public: Rectangle(uint32_t graphicFormat = defaultFormat, HwcTestDim dfDim = HwcTestDim(1, 1), HwcTestDim sDim = HwcTestDim(1, 1)); void setSourceDim(HwcTestDim dim); uint32_t format; uint32_t transform; int32_t blend; ColorFract color; float alpha; HwcTestDim sourceDim; struct hwc_rect sourceCrop; struct hwc_rect displayFrame; }; class Range { public: Range(void) : _l(0), _u(0) {} Range(uint32_t lower, uint32_t upper) : _l(lower), _u(upper) {} uint32_t lower(void) { return _l; } uint32_t upper(void) { return _u; } operator string(); private: uint32_t _l; // lower uint32_t _u; // upper }; Range::operator string() { ostringstream out; out << '[' << _l << ", " << _u << ']'; return out.str(); } class Rational { public: Rational(void) : _n(0), _d(1) {} Rational(uint32_t n, uint32_t d) : _n(n), _d(d) {} uint32_t numerator(void) { return _n; } uint32_t denominator(void) { return _d; } void setNumerator(uint32_t numerator) { _n = numerator; } bool operator==(const Rational& other) const; bool operator!=(const Rational& other) const { return !(*this == other); } bool operator<(const Rational& other) const; bool operator>(const Rational& other) const { return (!(*this == other) && !(*this < other)); } static void double2Rational(double f, Range nRange, Range dRange, Rational& lower, Rational& upper); operator string() const; operator double() const { return (double) _n / (double) _d; } private: uint32_t _n; uint32_t _d; }; // Globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; static size_t maxHeadingLen; static vector formats; // Measurements struct meas { uint32_t format; uint32_t startDimOverlays; uint32_t maxNonOverlapping; uint32_t maxOverlapping; list transforms; list blends; struct displayFrame { uint32_t minWidth; uint32_t minHeight; HwcTestDim minDim; uint32_t maxWidth; uint32_t maxHeight; HwcTestDim maxDim; } df; struct sourceCrop { uint32_t minWidth; uint32_t minHeight; HwcTestDim minDim; uint32_t maxWidth; uint32_t maxHeight; HwcTestDim maxDim; Rational hScale; HwcTestDim hScaleBestDf; HwcTestDim hScaleBestSc; Rational vScale; HwcTestDim vScaleBestDf; HwcTestDim vScaleBestSc; } sc; vector overlapBlendNone; vector overlapBlendPremult; vector overlapBlendCoverage; }; vector measurements; // Function prototypes uint32_t numOverlays(list& rectList); uint32_t maxOverlays(uint32_t format, bool allowOverlap); list supportedTransforms(uint32_t format); list supportedBlends(uint32_t format); uint32_t dfMinWidth(uint32_t format); uint32_t dfMinHeight(uint32_t format); uint32_t dfMaxWidth(uint32_t format); uint32_t dfMaxHeight(uint32_t format); HwcTestDim dfMinDim(uint32_t format); HwcTestDim dfMaxDim(uint32_t format); uint32_t scMinWidth(uint32_t format, const HwcTestDim& dfDim); uint32_t scMinHeight(uint32_t format, const HwcTestDim& dfDim); uint32_t scMaxWidth(uint32_t format, const HwcTestDim& dfDim); uint32_t scMaxHeight(uint32_t format, const HwcTestDim& dfDim); HwcTestDim scMinDim(uint32_t format, const HwcTestDim& dfDim); HwcTestDim scMaxDim(uint32_t format, const HwcTestDim& dfDim); Rational scHScale(uint32_t format, const HwcTestDim& dfMin, const HwcTestDim& dfMax, const HwcTestDim& scMin, const HwcTestDim& scMax, HwcTestDim& outBestDf, HwcTestDim& outBestSc); Rational scVScale(uint32_t format, const HwcTestDim& dfMin, const HwcTestDim& dfMax, const HwcTestDim& scMin, const HwcTestDim& scMax, HwcTestDim& outBestDf, HwcTestDim& outBestSc); uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat, uint32_t backgroundBlend, uint32_t foregroundBlend); string transformList2str(const list& transformList); string blendList2str(const list& blendList); void init(void); void printFormatHeadings(size_t indent); void printOverlapLine(size_t indent, const string formatStr, const vector& results); void printSyntax(const char *cmd); // Command-line option settings static bool verbose = defaultVerbose; static HwcTestDim startDim = defaultStartDim; /* * Main * * Performs the following high-level sequence of operations: * * 1. Command-line parsing * * 2. Form a list of command-line specified graphic formats. If * no formats are specified, then form a list of all known formats. * * 3. Stop framework * Only one user at a time is allowed to use the HWC. Surface * Flinger uses the HWC and is part of the framework. Need to * stop the framework so that Surface Flinger will stop using * the HWC. * * 4. Initialization * * 5. For each graphic format in the previously formed list perform * measurements on that format and report the results. * * 6. Start framework */ int main(int argc, char *argv[]) { int rv, opt; bool error; string str; char cmd[MAXCMD]; list rectList; testSetLogCatTag(LOG_TAG); // Parse command line arguments while ((opt = getopt(argc, argv, "s:v?h")) != -1) { switch (opt) { case 's': // Start Dimension // Use arguments until next starts with a dash // or current ends with a > or ] str = optarg; while (optind < argc) { if (*argv[optind] == '-') { break; } char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; if ((endChar == '>') || (endChar == ']')) { break; } str += " " + string(argv[optind++]); } { istringstream in(str); startDim = hwcTestParseDim(in, error); // Any parse error or characters not used by parser if (error || (((unsigned int) in.tellg() != in.str().length()) && (in.tellg() != (streampos) -1))) { testPrintE("Invalid command-line specified start " "dimension of: %s", str.c_str()); exit(8); } } break; case 'v': // Verbose verbose = true; break; case 'h': // Help case '?': default: printSyntax(basename(argv[0])); exit(((optopt == 0) || (optopt == '?')) ? 0 : 11); } } // Positional parameters // Positional parameters provide the names of graphic formats that // measurements are to be made on. Measurements are made on all // known graphic formats when no positional parameters are provided. if (optind == argc) { // No command-line specified graphic formats // Add all graphic formats to the list of formats to be measured for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { formats.push_back(hwcTestGraphicFormat[n1].desc); } } else { // Add names of command-line specified graphic formats to the // list of formats to be tested for (; argv[optind] != NULL; optind++) { formats.push_back(argv[optind]); } } // Determine length of longest specified graphic format. // This value is used for output formating for (vector::iterator it = formats.begin(); it != formats.end(); ++it) { maxHeadingLen = max(maxHeadingLen, it->length()); } // Stop framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); exit(14); } testExecCmd(cmd); testDelay(1.0); // TODO - needs means to query whether asynchronous stop // framework operation has completed. For now, just wait // a long time. testPrintI("startDim: %s", ((string) startDim).c_str()); init(); // For each of the graphic formats for (vector::iterator itFormat = formats.begin(); itFormat != formats.end(); ++itFormat) { // Locate hwcTestLib structure that describes this format const struct hwcTestGraphicFormat *format; format = hwcTestGraphicFormatLookup((*itFormat).c_str()); if (format == NULL) { testPrintE("Unknown graphic format of: %s", (*itFormat).c_str()); exit(1); } // Display format header testPrintI("format: %s", format->desc); // Create area to hold the measurements struct meas meas; struct meas *measPtr; meas.format = format->format; measurements.push_back(meas); measPtr = &measurements[measurements.size() - 1]; // Start dimension num overlays Rectangle rect(format->format, startDim); rectList.clear(); rectList.push_back(rect); measPtr->startDimOverlays = numOverlays(rectList); testPrintI(" startDimOverlays: %u", measPtr->startDimOverlays); // Skip the rest of the measurements, when the start dimension // doesn't produce an overlay if (measPtr->startDimOverlays == 0) { continue; } // Max Overlays measPtr->maxNonOverlapping = maxOverlays(format->format, false); testPrintI(" max nonOverlapping overlays: %s%u", (measPtr->maxNonOverlapping == searchLimits.numOverlays) ? ">= " : "", measPtr->maxNonOverlapping); measPtr->maxOverlapping = maxOverlays(format->format, true); testPrintI(" max Overlapping overlays: %s%u", (measPtr->maxOverlapping == searchLimits.numOverlays) ? ">= " : "", measPtr->maxOverlapping); // Transforms and blends measPtr->transforms = supportedTransforms(format->format); testPrintI(" transforms: %s", transformList2str(measPtr->transforms).c_str()); measPtr->blends = supportedBlends(format->format); testPrintI(" blends: %s", blendList2str(measPtr->blends).c_str()); // Display frame measurements measPtr->df.minWidth = dfMinWidth(format->format); testPrintI(" dfMinWidth: %u", measPtr->df.minWidth); measPtr->df.minHeight = dfMinHeight(format->format); testPrintI(" dfMinHeight: %u", measPtr->df.minHeight); measPtr->df.maxWidth = dfMaxWidth(format->format); testPrintI(" dfMaxWidth: %u", measPtr->df.maxWidth); measPtr->df.maxHeight = dfMaxHeight(format->format); testPrintI(" dfMaxHeight: %u", measPtr->df.maxHeight); measPtr->df.minDim = dfMinDim(format->format); testPrintI(" dfMinDim: %s", ((string) measPtr->df.minDim).c_str()); measPtr->df.maxDim = dfMaxDim(format->format); testPrintI(" dfMaxDim: %s", ((string) measPtr->df.maxDim).c_str()); // Source crop measurements measPtr->sc.minWidth = scMinWidth(format->format, measPtr->df.minDim); testPrintI(" scMinWidth: %u", measPtr->sc.minWidth); measPtr->sc.minHeight = scMinHeight(format->format, measPtr->df.minDim); testPrintI(" scMinHeight: %u", measPtr->sc.minHeight); measPtr->sc.maxWidth = scMaxWidth(format->format, measPtr->df.maxDim); testPrintI(" scMaxWidth: %s%u", (measPtr->sc.maxWidth == searchLimits.sourceCrop.width()) ? ">= " : "", measPtr->sc.maxWidth); measPtr->sc.maxHeight = scMaxHeight(format->format, measPtr->df.maxDim); testPrintI(" scMaxHeight: %s%u", (measPtr->sc.maxHeight == searchLimits.sourceCrop.height()) ? ">= " : "", measPtr->sc.maxHeight); measPtr->sc.minDim = scMinDim(format->format, measPtr->df.minDim); testPrintI(" scMinDim: %s", ((string) measPtr->sc.minDim).c_str()); measPtr->sc.maxDim = scMaxDim(format->format, measPtr->df.maxDim); testPrintI(" scMaxDim: %s%s", ((measPtr->sc.maxDim.width() >= searchLimits.sourceCrop.width()) || (measPtr->sc.maxDim.width() >= searchLimits.sourceCrop.height())) ? ">= " : "", ((string) measPtr->sc.maxDim).c_str()); measPtr->sc.hScale = scHScale(format->format, measPtr->df.minDim, measPtr->df.maxDim, measPtr->sc.minDim, measPtr->sc.maxDim, measPtr->sc.hScaleBestDf, measPtr->sc.hScaleBestSc); testPrintI(" scHScale: %s%f", (measPtr->sc.hScale >= Rational(searchLimits.sourceCrop.width(), measPtr->df.minDim.width())) ? ">= " : "", (double) measPtr->sc.hScale); testPrintI(" HScale Best Display Frame: %s", ((string) measPtr->sc.hScaleBestDf).c_str()); testPrintI(" HScale Best Source Crop: %s", ((string) measPtr->sc.hScaleBestSc).c_str()); measPtr->sc.vScale = scVScale(format->format, measPtr->df.minDim, measPtr->df.maxDim, measPtr->sc.minDim, measPtr->sc.maxDim, measPtr->sc.vScaleBestDf, measPtr->sc.vScaleBestSc); testPrintI(" scVScale: %s%f", (measPtr->sc.vScale >= Rational(searchLimits.sourceCrop.height(), measPtr->df.minDim.height())) ? ">= " : "", (double) measPtr->sc.vScale); testPrintI(" VScale Best Display Frame: %s", ((string) measPtr->sc.vScaleBestDf).c_str()); testPrintI(" VScale Best Source Crop: %s", ((string) measPtr->sc.vScaleBestSc).c_str()); // Overlap two graphic formats and different blends // Results displayed after all overlap measurments with // current format in the foreground // TODO: make measurments with background blend other than // none. All of these measurements are done with a // background blend of HWC_BLENDING_NONE, with the // blend type of the foregound being varied. uint32_t foregroundFormat = format->format; for (vector::iterator it = formats.begin(); it != formats.end(); ++it) { uint32_t num; const struct hwcTestGraphicFormat *backgroundFormatPtr = hwcTestGraphicFormatLookup((*it).c_str()); uint32_t backgroundFormat = backgroundFormatPtr->format; num = numOverlapping(backgroundFormat, foregroundFormat, HWC_BLENDING_NONE, HWC_BLENDING_NONE); measPtr->overlapBlendNone.push_back(num); num = numOverlapping(backgroundFormat, foregroundFormat, HWC_BLENDING_NONE, HWC_BLENDING_PREMULT); measPtr->overlapBlendPremult.push_back(num); num = numOverlapping(backgroundFormat, foregroundFormat, HWC_BLENDING_NONE, HWC_BLENDING_COVERAGE); measPtr->overlapBlendCoverage.push_back(num); } } // Display overlap results size_t indent = 2; testPrintI("overlapping blend: none"); printFormatHeadings(indent); for (vector::iterator it = formats.begin(); it != formats.end(); ++it) { printOverlapLine(indent, *it, measurements[it - formats.begin()].overlapBlendNone); } testPrintI(""); testPrintI("overlapping blend: premult"); printFormatHeadings(indent); for (vector::iterator it = formats.begin(); it != formats.end(); ++it) { printOverlapLine(indent, *it, measurements[it - formats.begin()].overlapBlendPremult); } testPrintI(""); testPrintI("overlapping blend: coverage"); printFormatHeadings(indent); for (vector::iterator it = formats.begin(); it != formats.end(); ++it) { printOverlapLine(indent, *it, measurements[it - formats.begin()].overlapBlendCoverage); } testPrintI(""); // Start framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); exit(21); } testExecCmd(cmd); return 0; } // Determine the maximum number of overlays that are all of the same format // that the HWC will commit to. If allowOverlap is true, then the rectangles // are laid out on a diagonal starting from the upper left corner. With // each rectangle adjust one pixel to the right and one pixel down. // When allowOverlap is false, the rectangles are tiled in column major // order. Note, column major ordering is used so that the initial rectangles // are all on different horizontal scan rows. It is common that hardware // has limits on the number of objects it can handle on any single row. uint32_t maxOverlays(uint32_t format, bool allowOverlap) { unsigned int max = 0; for (unsigned int numRects = 1; numRects <= searchLimits.numOverlays; numRects++) { list rectList; for (unsigned int x = 0; (x + startDim.width()) < (unsigned int) width; x += (allowOverlap) ? 1 : startDim.width()) { for (unsigned int y = 0; (y + startDim.height()) < (unsigned int) height; y += (allowOverlap) ? 1 : startDim.height()) { Rectangle rect(format, startDim, startDim); rect.displayFrame.left = x; rect.displayFrame.top = y; rect.displayFrame.right = x + startDim.width(); rect.displayFrame.bottom = y + startDim.height(); rectList.push_back(rect); if (rectList.size() >= numRects) { break; } } if (rectList.size() >= numRects) { break; } } uint32_t num = numOverlays(rectList); if (num > max) { max = num; } } return max; } // Measures what transforms (i.e. flip horizontal, rotate 180) are // supported by the specified format list supportedTransforms(uint32_t format) { list rv; list rectList; Rectangle rect(format, startDim); // For each of the transform types for (unsigned int idx = 0; idx < NUMA(transformType); idx++) { unsigned int id = transformType[idx].id; rect.transform = id; rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num == 1) { rv.push_back(id); } } return rv; } // Determines which types of blends (i.e. none, premult, coverage) are // supported by the specified format list supportedBlends(uint32_t format) { list rv; list rectList; Rectangle rect(format, startDim); // For each of the blend types for (unsigned int idx = 0; idx < NUMA(blendType); idx++) { unsigned int id = blendType[idx].id; rect.blend = id; rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num == 1) { rv.push_back(id); } } return rv; } // Determines the minimum width of any display frame of the given format // that the HWC will commit to. uint32_t dfMinWidth(uint32_t format) { uint32_t w; list rectList; for (w = 1; w <= startDim.width(); w++) { HwcTestDim dim(w, startDim.height()); Rectangle rect(format, dim); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return w; } } if (w > startDim.width()) { testPrintE("Failed to locate display frame min width"); exit(33); } return w; } // Display frame minimum height uint32_t dfMinHeight(uint32_t format) { uint32_t h; list rectList; for (h = 1; h <= startDim.height(); h++) { HwcTestDim dim(startDim.width(), h); Rectangle rect(format, dim); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return h; } } if (h > startDim.height()) { testPrintE("Failed to locate display frame min height"); exit(34); } return h; } // Display frame maximum width uint32_t dfMaxWidth(uint32_t format) { uint32_t w; list rectList; for (w = width; w >= startDim.width(); w--) { HwcTestDim dim(w, startDim.height()); Rectangle rect(format, dim); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return w; } } if (w < startDim.width()) { testPrintE("Failed to locate display frame max width"); exit(35); } return w; } // Display frame maximum height uint32_t dfMaxHeight(uint32_t format) { uint32_t h; for (h = height; h >= startDim.height(); h--) { HwcTestDim dim(startDim.width(), h); Rectangle rect(format, dim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return h; } } if (h < startDim.height()) { testPrintE("Failed to locate display frame max height"); exit(36); } return h; } // Determine the minimum number of pixels that the HWC will ever commit to. // Note, this might be different that dfMinWidth * dfMinHeight, in that this // function adjusts both the width and height from the starting dimension. HwcTestDim dfMinDim(uint32_t format) { uint64_t bestMinPixels = 0; HwcTestDim bestDim; bool bestSet = false; // True when value has been assigned to // bestMinPixels and bestDim bool origVerbose = verbose; // Temporarily turn off verbose verbose = false; for (uint32_t w = 1; w <= startDim.width(); w++) { for (uint32_t h = 1; h <= startDim.height(); h++) { if (bestSet && ((w > bestMinPixels) || (h > bestMinPixels))) { break; } HwcTestDim dim(w, h); Rectangle rect(format, dim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { uint64_t pixels = dim.width() * dim.height(); if (!bestSet || (pixels < bestMinPixels)) { bestMinPixels = pixels; bestDim = dim; bestSet = true; } } } } verbose = origVerbose; if (!bestSet) { testPrintE("Unable to locate display frame min dimension"); exit(20); } return bestDim; } // Display frame maximum dimension HwcTestDim dfMaxDim(uint32_t format) { uint64_t bestMaxPixels = 0; HwcTestDim bestDim; bool bestSet = false; // True when value has been assigned to // bestMaxPixels and bestDim; // Potentially increase benchmark performance by first checking // for the common case of supporting a full display frame. HwcTestDim dim(width, height); Rectangle rect(format, dim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num == 1) { return dim; } // TODO: Use a binary search bool origVerbose = verbose; // Temporarily turn off verbose verbose = false; for (uint32_t w = startDim.width(); w <= (uint32_t) width; w++) { for (uint32_t h = startDim.height(); h <= (uint32_t) height; h++) { if (bestSet && ((w * h) <= bestMaxPixels)) { continue; } HwcTestDim dim(w, h); Rectangle rect(format, dim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { uint64_t pixels = dim.width() * dim.height(); if (!bestSet || (pixels > bestMaxPixels)) { bestMaxPixels = pixels; bestDim = dim; bestSet = true; } } } } verbose = origVerbose; if (!bestSet) { testPrintE("Unable to locate display frame max dimension"); exit(21); } return bestDim; } // Source crop minimum width uint32_t scMinWidth(uint32_t format, const HwcTestDim& dfDim) { uint32_t w; list rectList; // Source crop frame min width for (w = 1; w <= dfDim.width(); w++) { Rectangle rect(format, dfDim, HwcTestDim(w, dfDim.height())); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return w; } } testPrintE("Failed to locate source crop min width"); exit(35); } // Source crop minimum height uint32_t scMinHeight(uint32_t format, const HwcTestDim& dfDim) { uint32_t h; list rectList; for (h = 1; h <= dfDim.height(); h++) { Rectangle rect(format, dfDim, HwcTestDim(dfDim.width(), h)); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return h; } } testPrintE("Failed to locate source crop min height"); exit(36); } // Source crop maximum width uint32_t scMaxWidth(uint32_t format, const HwcTestDim& dfDim) { uint32_t w; list rectList; for (w = searchLimits.sourceCrop.width(); w >= dfDim.width(); w--) { Rectangle rect(format, dfDim, HwcTestDim(w, dfDim.height())); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return w; } } testPrintE("Failed to locate source crop max width"); exit(35); } // Source crop maximum height uint32_t scMaxHeight(uint32_t format, const HwcTestDim& dfDim) { uint32_t h; list rectList; for (h = searchLimits.sourceCrop.height(); h >= dfDim.height(); h--) { Rectangle rect(format, dfDim, HwcTestDim(dfDim.width(), h)); rectList.clear(); rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { return h; } } testPrintE("Failed to locate source crop max height"); exit(36); } // Source crop minimum dimension // Discovers the source crop with the least number of pixels that the // HWC will commit to. Note, this may be different from scMinWidth // * scMinHeight, in that this function searches for a combination of // width and height. While the other routines always keep one of the // dimensions equal to the corresponding start dimension. HwcTestDim scMinDim(uint32_t format, const HwcTestDim& dfDim) { uint64_t bestMinPixels = 0; HwcTestDim bestDim; bool bestSet = false; // True when value has been assigned to // bestMinPixels and bestDim bool origVerbose = verbose; // Temporarily turn off verbose verbose = false; for (uint32_t w = 1; w <= dfDim.width(); w++) { for (uint32_t h = 1; h <= dfDim.height(); h++) { if (bestSet && ((w > bestMinPixels) || (h > bestMinPixels))) { break; } HwcTestDim dim(w, h); Rectangle rect(format, dfDim, HwcTestDim(w, h)); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { uint64_t pixels = dim.width() * dim.height(); if (!bestSet || (pixels < bestMinPixels)) { bestMinPixels = pixels; bestDim = dim; bestSet = true; } } } } verbose = origVerbose; if (!bestSet) { testPrintE("Unable to locate source crop min dimension"); exit(20); } return bestDim; } // Source crop maximum dimension HwcTestDim scMaxDim(uint32_t format, const HwcTestDim& dfDim) { uint64_t bestMaxPixels = 0; HwcTestDim bestDim; bool bestSet = false; // True when value has been assigned to // bestMaxPixels and bestDim; // Potentially increase benchmark performance by first checking // for the common case of supporting the maximum checked source size HwcTestDim dim = searchLimits.sourceCrop; Rectangle rect(format, dfDim, searchLimits.sourceCrop); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num == 1) { return dim; } // TODO: Use a binary search bool origVerbose = verbose; // Temporarily turn off verbose verbose = false; for (uint32_t w = dfDim.width(); w <= searchLimits.sourceCrop.width(); w++) { for (uint32_t h = dfDim.height(); h <= searchLimits.sourceCrop.height(); h++) { if (bestSet && ((w * h) <= bestMaxPixels)) { continue; } HwcTestDim dim(w, h); Rectangle rect(format, dfDim, dim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (num > 0) { uint64_t pixels = dim.width() * dim.height(); if (!bestSet || (pixels > bestMaxPixels)) { bestMaxPixels = pixels; bestDim = dim; bestSet = true; } } } } verbose = origVerbose; if (!bestSet) { testPrintE("Unable to locate source crop max dimension"); exit(21); } return bestDim; } // Source crop horizontal scale // Determines the maximum factor by which the source crop can be larger // that the display frame. The commit point is discovered through a // binary search of rational numbers. The numerator in each of the // rational numbers contains the dimension for the source crop, while // the denominator specifies the dimension for the display frame. On // each pass of the binary search the mid-point between the greatest // point committed to (best) and the smallest point in which a commit // has failed is calculated. This mid-point is then passed to a function // named double2Rational, which determines the closest rational numbers // just below and above the mid-point. By default the lower rational // number is used for the scale factor on the next pass of the binary // search. The upper value is only used when best is already equal // to the lower value. This only occurs when the lower value has already // been tried. Rational scHScale(uint32_t format, const HwcTestDim& dfMin, const HwcTestDim& dfMax, const HwcTestDim& scMin, const HwcTestDim& scMax, HwcTestDim& outBestDf, HwcTestDim& outBestSc) { HwcTestDim scDim, dfDim; // Source crop and display frame dimension Rational best(0, 1), minBad; // Current bounds for a binary search // MinGood is set below the lowest // possible scale. The value of minBad, // will be set by the first pass // of the binary search. // Perform the passes of the binary search bool firstPass = true; do { // On first pass try the maximum scale within the search limits if (firstPass) { // Try the maximum possible scale, within the search limits scDim = HwcTestDim(searchLimits.sourceCrop.width(), scMin.height()); dfDim = dfMin; } else { // Subsequent pass // Halve the difference between best and minBad. Rational lower, upper, selected; // Try the closest ratio halfway between minBood and minBad; // TODO: Avoid rounding issue by using Rational type for // midpoint. For now will use double, which should // have more than sufficient resolution. double mid = (double) best + ((double) minBad - (double) best) / 2.0; Rational::double2Rational(mid, Range(scMin.width(), scMax.width()), Range(dfMin.width(), dfMax.width()), lower, upper); if (((lower == best) && (upper == minBad))) { return best; } // Use lower value unless its already been tried selected = (lower != best) ? lower : upper; // Assign the size of the source crop and display frame // from the selected ratio of source crop to display frame. scDim = HwcTestDim(selected.numerator(), scMin.height()); dfDim = HwcTestDim(selected.denominator(), dfMin.height()); } // See if the HWC will commit to this combination Rectangle rect(format, dfDim, scDim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (verbose) { testPrintI(" scHscale num: %u scale: %f dfDim: %s scDim: %s", num, (float) Rational(scDim.width(), dfDim.width()), ((string) dfDim).c_str(), ((string) scDim).c_str()); } if (num == 1) { // HWC committed to the combination // This is the best scale factor seen so far. Report the // dimensions to the caller, in case nothing better is seen. outBestDf = dfDim; outBestSc = scDim; // Success on the first pass means the largest possible scale // is supported, in which case no need to search any further. if (firstPass) { return Rational(scDim.width(), dfDim.width()); } // Update the lower bound of the binary search best = Rational(scDim.width(), dfDim.width()); } else { // HWC didn't commit to this combination, so update the // upper bound of the binary search. minBad = Rational(scDim.width(), dfDim.width()); } firstPass = false; } while (best != minBad); return best; } // Source crop vertical scale // Determines the maximum factor by which the source crop can be larger // that the display frame. The commit point is discovered through a // binary search of rational numbers. The numerator in each of the // rational numbers contains the dimension for the source crop, while // the denominator specifies the dimension for the display frame. On // each pass of the binary search the mid-point between the greatest // point committed to (best) and the smallest point in which a commit // has failed is calculated. This mid-point is then passed to a function // named double2Rational, which determines the closest rational numbers // just below and above the mid-point. By default the lower rational // number is used for the scale factor on the next pass of the binary // search. The upper value is only used when best is already equal // to the lower value. This only occurs when the lower value has already // been tried. Rational scVScale(uint32_t format, const HwcTestDim& dfMin, const HwcTestDim& dfMax, const HwcTestDim& scMin, const HwcTestDim& scMax, HwcTestDim& outBestDf, HwcTestDim& outBestSc) { HwcTestDim scDim, dfDim; // Source crop and display frame dimension Rational best(0, 1), minBad; // Current bounds for a binary search // MinGood is set below the lowest // possible scale. The value of minBad, // will be set by the first pass // of the binary search. // Perform the passes of the binary search bool firstPass = true; do { // On first pass try the maximum scale within the search limits if (firstPass) { // Try the maximum possible scale, within the search limits scDim = HwcTestDim(scMin.width(), searchLimits.sourceCrop.height()); dfDim = dfMin; } else { // Subsequent pass // Halve the difference between best and minBad. Rational lower, upper, selected; // Try the closest ratio halfway between minBood and minBad; // TODO: Avoid rounding issue by using Rational type for // midpoint. For now will use double, which should // have more than sufficient resolution. double mid = (double) best + ((double) minBad - (double) best) / 2.0; Rational::double2Rational(mid, Range(scMin.height(), scMax.height()), Range(dfMin.height(), dfMax.height()), lower, upper); if (((lower == best) && (upper == minBad))) { return best; } // Use lower value unless its already been tried selected = (lower != best) ? lower : upper; // Assign the size of the source crop and display frame // from the selected ratio of source crop to display frame. scDim = HwcTestDim(scMin.width(), selected.numerator()); dfDim = HwcTestDim(dfMin.width(), selected.denominator()); } // See if the HWC will commit to this combination Rectangle rect(format, dfDim, scDim); list rectList; rectList.push_back(rect); uint32_t num = numOverlays(rectList); if (verbose) { testPrintI(" scHscale num: %u scale: %f dfDim: %s scDim: %s", num, (float) Rational(scDim.height(), dfDim.height()), ((string) dfDim).c_str(), ((string) scDim).c_str()); } if (num == 1) { // HWC committed to the combination // This is the best scale factor seen so far. Report the // dimensions to the caller, in case nothing better is seen. outBestDf = dfDim; outBestSc = scDim; // Success on the first pass means the largest possible scale // is supported, in which case no need to search any further. if (firstPass) { return Rational(scDim.height(), dfDim.height()); } // Update the lower bound of the binary search best = Rational(scDim.height(), dfDim.height()); } else { // HWC didn't commit to this combination, so update the // upper bound of the binary search. minBad = Rational(scDim.height(), dfDim.height()); } firstPass = false; } while (best != minBad); return best; } uint32_t numOverlapping(uint32_t backgroundFormat, uint32_t foregroundFormat, uint32_t backgroundBlend, uint32_t foregroundBlend) { list rectList; Rectangle background(backgroundFormat, startDim, startDim); background.blend = backgroundBlend; rectList.push_back(background); // TODO: Handle cases where startDim is so small that adding 5 // causes frames not to overlap. // TODO: Handle cases where startDim is so large that adding 5 // cause a portion or all of the foreground displayFrame // to be off the display. Rectangle foreground(foregroundFormat, startDim, startDim); foreground.displayFrame.left += 5; foreground.displayFrame.top += 5; foreground.displayFrame.right += 5; foreground.displayFrame.bottom += 5; background.blend = foregroundBlend; rectList.push_back(foreground); uint32_t num = numOverlays(rectList); return num; } Rectangle::Rectangle(uint32_t graphicFormat, HwcTestDim dfDim, HwcTestDim sDim) : format(graphicFormat), transform(defaultTransform), blend(defaultBlend), color(defaultColor), alpha(defaultAlpha), sourceCrop(sDim), displayFrame(dfDim) { // Set source dimension // Can't use a base initializer, because the setting of format // must be done before setting the sourceDimension. setSourceDim(sDim); } void Rectangle::setSourceDim(HwcTestDim dim) { this->sourceDim = dim; const struct hwcTestGraphicFormat *attrib; attrib = hwcTestGraphicFormatLookup(this->format); if (attrib != NULL) { if (sourceDim.width() % attrib->wMod) { sourceDim.setWidth(sourceDim.width() + attrib->wMod - (sourceDim.width() % attrib->wMod)); } if (sourceDim.height() % attrib->hMod) { sourceDim.setHeight(sourceDim.height() + attrib->hMod - (sourceDim.height() % attrib->hMod)); } } } // Rational member functions bool Rational::operator==(const Rational& other) const { if (((uint64_t) _n * other._d) == ((uint64_t) _d * other._n)) { return true; } return false; } bool Rational::operator<(const Rational& other) const { if (((uint64_t) _n * other._d) < ((uint64_t) _d * other._n)) { return true; } return false; } Rational::operator string() const { ostringstream out; out << _n << '/' << _d; return out.str(); } void Rational::double2Rational(double f, Range nRange, Range dRange, Rational& lower, Rational& upper) { Rational bestLower(nRange.lower(), dRange.upper()); Rational bestUpper(nRange.upper(), dRange.lower()); // Search for a better solution for (uint32_t d = dRange.lower(); d <= dRange.upper(); d++) { Rational val(d * f, d); // Lower, because double to int cast truncates if ((val.numerator() < nRange.lower()) || (val.numerator() > nRange.upper())) { continue; } if (((double) val > (double) bestLower) && ((double) val <= f)) { bestLower = val; } val.setNumerator(val.numerator() + 1); if (val.numerator() > nRange.upper()) { continue; } if (((double) val < (double) bestUpper) && ((double) val >= f)) { bestUpper = val; } } lower = bestLower; upper = bestUpper; } // Local functions // Num Overlays // Given a list of rectangles, determine how many HWC will commit to render uint32_t numOverlays(list& rectList) { hwc_display_contents_1_t *hwcList; list > buffers; hwcList = hwcTestCreateLayerList(rectList.size()); if (hwcList == NULL) { testPrintE("numOverlays create hwcList failed"); exit(30); } hwc_layer_1_t *layer = &hwcList->hwLayers[0]; for (std::list::iterator it = rectList.begin(); it != rectList.end(); ++it, ++layer) { // Allocate the texture for the source frame // and push it onto the buffers list, so that it // stays in scope until a return from this function. sp texture; texture = new GraphicBuffer(it->sourceDim.width(), it->sourceDim.height(), it->format, texUsage); buffers.push_back(texture); layer->handle = texture->handle; layer->blending = it->blend; layer->transform = it->transform; layer->sourceCrop = it->sourceCrop; layer->displayFrame = it->displayFrame; layer->visibleRegionScreen.numRects = 1; layer->visibleRegionScreen.rects = &layer->displayFrame; } // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(hwcList); } hwcDevice->prepare(hwcDevice, 1, &hwcList); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(hwcList); } // Count the number of overlays uint32_t total = 0; for (unsigned int n1 = 0; n1 < hwcList->numHwLayers; n1++) { if (hwcList->hwLayers[n1].compositionType == HWC_OVERLAY) { total++; } } // Free the layer list and graphic buffers hwcTestFreeLayerList(hwcList); return total; } string transformList2str(const list& transformList) { ostringstream out; for (list::const_iterator it = transformList.begin(); it != transformList.end(); ++it) { uint32_t id = *it; if (it != transformList.begin()) { out << ", "; } out << id; for (unsigned int idx = 0; idx < NUMA(transformType); idx++) { if (id == transformType[idx].id) { out << " (" << transformType[idx].desc << ')'; break; } } } return out.str(); } string blendList2str(const list& blendList) { ostringstream out; for (list::const_iterator it = blendList.begin(); it != blendList.end(); ++it) { uint32_t id = *it; if (it != blendList.begin()) { out << ", "; } out << id; for (unsigned int idx = 0; idx < NUMA(blendType); idx++) { if (id == blendType[idx].id) { out << " (" << blendType[idx].desc << ')'; break; } } } return out.str(); } void init(void) { srand48(0); hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); hwcTestOpenHwc(&hwcDevice); } void printFormatHeadings(size_t indent) { for (size_t row = 0; row <= maxHeadingLen; row++) { ostringstream line; for(vector::iterator it = formats.begin(); it != formats.end(); ++it) { if ((maxHeadingLen - row) <= it->length()) { if (row != maxHeadingLen) { char ch = (*it)[it->length() - (maxHeadingLen - row)]; line << ' ' << setw(printFieldWidth) << ch; } else { line << ' ' << string(printFieldWidth, '-'); } } else { line << ' ' << setw(printFieldWidth) << ""; } } testPrintI("%*s%s", indent + maxHeadingLen, "", line.str().c_str()); } } void printOverlapLine(size_t indent, const string formatStr, const vector& results) { ostringstream line; line << setw(indent + maxHeadingLen - formatStr.length()) << ""; line << formatStr; for (vector::const_iterator it = results.begin(); it != results.end(); ++it) { line << ' ' << setw(printFieldWidth) << *it; } testPrintI("%s", line.str().c_str()); } void printSyntax(const char *cmd) { testPrintE(" %s [options] [graphicFormat] ...", cmd); testPrintE(" options:"); testPrintE(" -s [width, height] - start dimension"); testPrintE(" -v - Verbose"); testPrintE(""); testPrintE(" graphic formats:"); for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { testPrintE(" %s", hwcTestGraphicFormat[n1].desc); } } opengl/tests/hwc/hwcRects.cpp0100644 0000000 0000000 00000045205 13077405420 015312 0ustar000000000 0000000 /* * 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. */ /* * Hardware Composer Rectangles * * Synopsis * hwcRects [options] (graphicFormat displayFrame [attributes],)... * options: * -D #.## - End of test delay * -v - Verbose * * graphic formats: * RGBA8888 (reference frame default) * RGBX8888 * RGB888 * RGB565 * BGRA8888 * RGBA5551 * RGBA4444 * YV12 * * displayFrame * [left, top, right, bottom] * * attributes: * transform: none | fliph | flipv | rot90 | rot180 | rot270 * blend: none | premult | coverage * color: [0.##, 0.##, 0.##] * alpha: 0.## * sourceDim: [width, height] * sourceCrop: [left, top, right, bottom] * * Example: * # White YV12 rectangle, with overlapping turquoise * # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency * hwcRects -v -D 30.0 \ * YV12 [50, 80, 200, 300] transform: none \ * color: [1.0, 0.5, 0.5], \ * RGBA8888 [100, 150, 300, 400] blend: coverage \ * color: [0.251, 0.878, 0.816] alpha: 0.7 \ * sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15] * * Description * Constructs a Hardware Composer (HWC) list of frames from * command-line specified parameters. Then sends it to the HWC * be rendered. The intended purpose of this tool is as a means to * reproduce and succinctly specify an observed HWC operation, with * no need to modify/compile a program. * * The command-line syntax consists of a few standard command-line * options and then a description of one or more frames. The frame * descriptions are separated from one another via a comma. The * beginning of a frame description requires the specification * of the graphic format and then the display frame rectangle where * the frame will be displayed. The display frame rectangle is * specified as follows, with the right and bottom coordinates being * exclusive values: * * [left, top, right, bottom] * * After these two required parameters each frame description can * specify 1 or more optional attributes. The name of each optional * attribute is preceded by a colon. The current implementation * then requires white space after the colon and then the value of * the attribute is specified. See the synopsis section above for * a list of attributes and the format of their expected value. */ #define LOG_TAG "hwcRectsTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hwcTestLib.h" using namespace std; using namespace android; // Defaults const bool defaultVerbose = false; const float defaultEndDelay = 2.0; // Default delay after rendering graphics const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; const int32_t defaultTransform = 0; const uint32_t defaultBlend = HWC_BLENDING_NONE; const ColorFract defaultColor(0.5, 0.5, 0.5); const float defaultAlpha = 1.0; // Opaque const HwcTestDim defaultSourceDim(1, 1); const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1}; const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100}; // Defines #define MAXCMD 200 #define CMD_STOP_FRAMEWORK "stop 2>&1" #define CMD_START_FRAMEWORK "start 2>&1" // Macros #define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array // Local types class Rectangle { public: Rectangle() : format(defaultFormat), transform(defaultTransform), blend(defaultBlend), color(defaultColor), alpha(defaultAlpha), sourceDim(defaultSourceDim), sourceCrop(defaultSourceCrop), displayFrame(defaultDisplayFrame) {}; uint32_t format; uint32_t transform; int32_t blend; ColorFract color; float alpha; HwcTestDim sourceDim; struct hwc_rect sourceCrop; struct hwc_rect displayFrame; sp texture; }; // Globals list rectangle; static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; // Function prototypes static Rectangle parseRect(string rectStr); void init(void); void printSyntax(const char *cmd); // Command-line option settings static bool verbose = defaultVerbose; static float endDelay = defaultEndDelay; /* * Main * * Performs the following high-level sequence of operations: * * 1. Parse command-line options * * 2. Stop framework * * 3. Initialization * * 4. Parse frame descriptions * * 5. Create HWC list from frame descriptions * * 6. Have HWC render the list description of the frames * * 7. Delay for amount of time given by endDelay * * 8. Start framework */ int main(int argc, char *argv[]) { int rv, opt; char *chptr; string str; char cmd[MAXCMD]; testSetLogCatTag(LOG_TAG); // Parse command line arguments while ((opt = getopt(argc, argv, "D:v?h")) != -1) { switch (opt) { case 'D': // End of test delay endDelay = strtod(optarg, &chptr); if ((*chptr != '\0') || (endDelay < 0.0)) { testPrintE("Invalid command-line specified end of test delay " "of: %s", optarg); exit(1); } break; case 'v': // Verbose verbose = true; break; case 'h': // Help case '?': default: printSyntax(basename(argv[0])); exit(((optopt == 0) || (optopt == '?')) ? 0 : 2); } } // Stop framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); exit(3); } testExecCmd(cmd); testDelay(1.0); // TODO - needs means to query whether asyncronous stop // framework operation has completed. For now, just wait // a long time. init(); // Parse rectangle descriptions int numOpen = 0; // Current number of unmatched <[ string rectDesc(""); // String description of a single rectangle while (optind < argc) { string argNext = string(argv[optind++]); if (rectDesc.length()) { rectDesc += ' '; } rectDesc += argNext; // Count number of opening <[ and matching >] // At this point not worried about an opening character being // matched by it's corresponding closing character. For example, // "<1.0, 2.0]" is incorrect because the opening < should be matched // with a closing >, instead of the closing ]. Such errors are // detected when the actual value is parsed. for (unsigned int n1 = 0; n1 < argNext.length(); n1++) { switch(argNext[n1]) { case '[': case '<': numOpen++; break; case ']': case '>': numOpen--; break; } // Error anytime there is more closing then opening characters if (numOpen < 0) { testPrintI("Mismatched number of opening <[ with " "closing >] in: %s", rectDesc.c_str()); exit(4); } } // Description of a rectangle is complete when all opening // <[ are closed with >] and the string ends with a comma or // there are no more args. if ((numOpen == 0) && rectDesc.length() && ((rectDesc[rectDesc.length() - 1] == ',') || (optind == argc))) { // Remove trailing comma if it is present if (rectDesc[rectDesc.length() - 1] == ',') { rectDesc.erase(rectDesc.length() - 1); } // Parse string description of rectangle Rectangle rect = parseRect(rectDesc); // Add to the list of rectangles rectangle.push_back(rect); // Prepare for description of another rectangle rectDesc = string(""); } } // Create list of frames hwc_display_contents_1_t *list; list = hwcTestCreateLayerList(rectangle.size()); if (list == NULL) { testPrintE("hwcTestCreateLayerList failed"); exit(5); } hwc_layer_1_t *layer = &list->hwLayers[0]; for (std::list::iterator it = rectangle.begin(); it != rectangle.end(); ++it, ++layer) { layer->handle = it->texture->handle; layer->blending = it->blend; layer->transform = it->transform; layer->sourceCrop = it->sourceCrop; layer->displayFrame = it->displayFrame; layer->visibleRegionScreen.numRects = 1; layer->visibleRegionScreen.rects = &layer->displayFrame; } // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); } // Turn off the geometry changed flag list->flags &= ~HWC_GEOMETRY_CHANGED; // Perform the set operation(s) if (verbose) {testPrintI("Set:"); } if (verbose) { hwcTestDisplayListHandles(list); } list->dpy = dpy; list->sur = surface; hwcDevice->set(hwcDevice, 1, &list); testDelay(endDelay); // Start framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); exit(6); } testExecCmd(cmd); return 0; } // Parse string description of rectangle and add it to list of rectangles // to be rendered. static Rectangle parseRect(string rectStr) { int rv; string str; bool error; istringstream in(rectStr); const struct hwcTestGraphicFormat *format; Rectangle rect; // Graphic Format in >> str; if (!in) { testPrintE("Error parsing format from: %s", rectStr.c_str()); exit(20); } format = hwcTestGraphicFormatLookup(str.c_str()); if (format == NULL) { testPrintE("Unknown graphic format in: %s", rectStr.c_str()); exit(21); } rect.format = format->format; // Display Frame rect.displayFrame = hwcTestParseHwcRect(in, error); if (error) { testPrintE("Invalid display frame in: %s", rectStr.c_str()); exit(22); } // Set default sourceDim and sourceCrop based on size of display frame. // Default is source size equal to the size of the display frame, with // the source crop being the entire size of the source frame. rect.sourceDim = HwcTestDim(rect.displayFrame.right - rect.displayFrame.left, rect.displayFrame.bottom - rect.displayFrame.top); rect.sourceCrop.left = 0; rect.sourceCrop.top = 0; rect.sourceCrop.right = rect.sourceDim.width(); rect.sourceCrop.bottom = rect.sourceDim.height(); // Optional settings while ((in.tellg() < (streampos) in.str().length()) && (in.tellg() != (streampos) -1)) { string attrName; in >> attrName; if (in.eof()) { break; } if (!in) { testPrintE("Error reading attribute name in: %s", rectStr.c_str()); exit(23); } // Transform if (attrName == "transform:") { // Transform string str; in >> str; if (str == "none") { rect.transform = 0; } else if (str == "fliph") { rect.transform = HWC_TRANSFORM_FLIP_H; } else if (str == "flipv") { rect.transform = HWC_TRANSFORM_FLIP_V; } else if (str == "rot90") { rect.transform = HWC_TRANSFORM_ROT_90; } else if (str == "rot180") { rect.transform = HWC_TRANSFORM_ROT_180; } else if (str == "rot270") { rect.transform = HWC_TRANSFORM_ROT_270; } else { testPrintE("Unknown transform of \"%s\" in: %s", str.c_str(), rectStr.c_str()); exit(24); } } else if (attrName == "blend:") { // Blend string str; in >> str; if (str == string("none")) { rect.blend = HWC_BLENDING_NONE; } else if (str == "premult") { rect.blend = HWC_BLENDING_PREMULT; } else if (str == "coverage") { rect.blend = HWC_BLENDING_COVERAGE; } else { testPrintE("Unknown blend of \"%s\" in: %s", str.c_str(), rectStr.c_str()); exit(25); } } else if (attrName == "color:") { // Color rect.color = hwcTestParseColor(in, error); if (error) { testPrintE("Error parsing color in: %s", rectStr.c_str()); exit(26); } } else if (attrName == "alpha:") { // Alpha in >> rect.alpha; if (!in) { testPrintE("Error parsing value for alpha attribute in: %s", rectStr.c_str()); exit(27); } } else if (attrName == "sourceDim:") { // Source Dimension rect.sourceDim = hwcTestParseDim(in, error); if (error) { testPrintE("Error parsing source dimenision in: %s", rectStr.c_str()); exit(28); } } else if (attrName == "sourceCrop:") { // Source Crop rect.sourceCrop = hwcTestParseHwcRect(in, error); if (error) { testPrintE("Error parsing source crop in: %s", rectStr.c_str()); exit(29); } } else { // Unknown attribute testPrintE("Unknown attribute of \"%s\" in: %s", attrName.c_str(), rectStr.c_str()); exit(30); } } // Validate if (((uint32_t) rect.sourceCrop.left >= rect.sourceDim.width()) || ((uint32_t) rect.sourceCrop.right > rect.sourceDim.width()) || ((uint32_t) rect.sourceCrop.top >= rect.sourceDim.height()) || ((uint32_t) rect.sourceCrop.bottom > rect.sourceDim.height())) { testPrintE("Invalid source crop in: %s", rectStr.c_str()); exit(31); } if ((rect.displayFrame.left >= width) || (rect.displayFrame.right > width) || (rect.displayFrame.top >= height) || (rect.displayFrame.bottom > height)) { testPrintE("Invalid display frame in: %s", rectStr.c_str()); exit(32); } if ((rect.alpha < 0.0) || (rect.alpha > 1.0)) { testPrintE("Invalid alpha in: %s", rectStr.c_str()); exit(33); } // Create source texture rect.texture = new GraphicBuffer(rect.sourceDim.width(), rect.sourceDim.height(), rect.format, texUsage); if ((rv = rect.texture->initCheck()) != NO_ERROR) { testPrintE("source texture initCheck failed, rv: %i", rv); testPrintE(" %s", rectStr.c_str()); } // Fill with uniform color hwcTestFillColor(rect.texture.get(), rect.color, rect.alpha); if (verbose) { testPrintI(" buf: %p handle: %p format: %s width: %u height: %u " "color: %s alpha: %f", rect.texture.get(), rect.texture->handle, format->desc, rect.sourceDim.width(), rect.sourceDim.height(), string(rect.color).c_str(), rect.alpha); } return rect; } void init(void) { // Seed pseudo random number generator // Needed so that the pad areas of frames are filled with a deterministic // pseudo random value. srand48(0); hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); hwcTestOpenHwc(&hwcDevice); } void printSyntax(const char *cmd) { testPrintE(" %s [options] (graphicFormat displayFrame [attributes],)...", cmd); testPrintE(" options:"); testPrintE(" -D End of test delay"); testPrintE(" -v Verbose"); testPrintE(""); testPrintE(" graphic formats:"); for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { testPrintE(" %s", hwcTestGraphicFormat[n1].desc); } testPrintE(""); testPrintE(" displayFrame"); testPrintE(" [left, top, right, bottom]"); testPrintE(""); testPrintE(" attributes:"); testPrintE(" transform: none | fliph | flipv | rot90 | rot180 " " | rot270"); testPrintE(" blend: none | premult | coverage"); testPrintE(" color: [0.##, 0.##, 0.##]"); testPrintE(" alpha: 0.##"); testPrintE(" sourceDim: [width, height]"); testPrintE(" sourceCrop: [left, top, right, bottom]"); testPrintE(""); testPrintE(" Example:"); testPrintE(" # White YV12 rectangle, with overlapping turquoise "); testPrintE(" # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency"); testPrintE(" %s -v -D 30.0 \\", cmd); testPrintE(" YV12 [50, 80, 200, 300] transform: none \\"); testPrintE(" color: [1.0, 0.5, 0.5], \\"); testPrintE(" RGBA8888 [100, 150, 300, 400] blend: coverage \\"); testPrintE(" color: [0.251, 0.878, 0.816] alpha: 0.7 \\"); testPrintE(" sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]"); } opengl/tests/hwc/hwcStress.cpp0100644 0000000 0000000 00000057703 13077405420 015523 0ustar000000000 0000000 /* * Copyright (C) 2010 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. * */ /* * Hardware Composer stress test * * Performs a pseudo-random (prandom) sequence of operations to the * Hardware Composer (HWC), for a specified number of passes or for * a specified period of time. By default the period of time is FLT_MAX, * so that the number of passes will take precedence. * * The passes are grouped together, where (pass / passesPerGroup) specifies * which group a particular pass is in. This causes every passesPerGroup * worth of sequential passes to be within the same group. Computationally * intensive operations are performed just once at the beginning of a group * of passes and then used by all the passes in that group. This is done * so as to increase both the average and peak rate of graphic operations, * by moving computationally intensive operations to the beginning of a group. * In particular, at the start of each group of passes a set of * graphic buffers are created, then used by the first and remaining * passes of that group of passes. * * The per-group initialization of the graphic buffers is performed * by a function called initFrames. This function creates an array * of smart pointers to the graphic buffers, in the form of a vector * of vectors. The array is accessed in row major order, so each * row is a vector of smart pointers. All the pointers of a single * row point to graphic buffers which use the same pixel format and * have the same dimension, although it is likely that each one is * filled with a different color. This is done so that after doing * the first HWC prepare then set call, subsequent set calls can * be made with each of the layer handles changed to a different * graphic buffer within the same row. Since the graphic buffers * in a particular row have the same pixel format and dimension, * additional HWC set calls can be made, without having to perform * an HWC prepare call. * * This test supports the following command-line options: * * -v Verbose * -s num Starting pass * -e num Ending pass * -p num Execute the single pass specified by num * -n num Number of set operations to perform after each prepare operation * -t float Maximum time in seconds to execute the test * -d float Delay in seconds performed after each set operation * -D float Delay in seconds performed after the last pass is executed * * Typically the test is executed for a large range of passes. By default * passes 0 through 99999 (100,000 passes) are executed. Although this test * does not validate the generated image, at times it is useful to reexecute * a particular pass and leave the displayed image on the screen for an * extended period of time. This can be done either by setting the -s * and -e options to the desired pass, along with a large value for -D. * This can also be done via the -p option, again with a large value for * the -D options. * * So far this test only contains code to create graphic buffers with * a continuous solid color. Although this test is unable to validate the * image produced, any image that contains other than rectangles of a solid * color are incorrect. Note that the rectangles may use a transparent * color and have a blending operation that causes the color in overlapping * rectangles to be mixed. In such cases the overlapping portions may have * a different color from the rest of the rectangle. */ #define LOG_TAG "hwcStressTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hwcTestLib.h" using namespace std; using namespace android; const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch // larger than the default screen size const unsigned int passesPerGroup = 10; // A group of passes all use the same // graphic buffers // Ratios at which rare and frequent conditions should be produced const float rareRatio = 0.1; const float freqRatio = 0.9; // Defaults for command-line options const bool defaultVerbose = false; const unsigned int defaultStartPass = 0; const unsigned int defaultEndPass = 99999; const unsigned int defaultPerPassNumSet = 10; const float defaultPerSetDelay = 0.0; // Default delay after each set // operation. Default delay of // zero used so as to perform the // the set operations as quickly // as possible. const float defaultEndDelay = 2.0; // Default delay between completion of // final pass and restart of framework const float defaultDuration = FLT_MAX; // A fairly long time, so that // range of passes will have // precedence // Command-line option settings static bool verbose = defaultVerbose; static unsigned int startPass = defaultStartPass; static unsigned int endPass = defaultEndPass; static unsigned int numSet = defaultPerPassNumSet; static float perSetDelay = defaultPerSetDelay; static float endDelay = defaultEndDelay; static float duration = defaultDuration; // Command-line mutual exclusion detection flags. // Corresponding flag set true once an option is used. bool eFlag, sFlag, pFlag; #define MAXSTR 100 #define MAXCMD 200 #define BITSPERBYTE 8 // TODO: Obtain from , once // it has been added #define CMD_STOP_FRAMEWORK "stop 2>&1" #define CMD_START_FRAMEWORK "start 2>&1" #define NUMA(a) (sizeof(a) / sizeof(a [0])) #define MEMCLR(addr, size) do { \ memset((addr), 0, (size)); \ } while (0) // File scope constants const unsigned int blendingOps[] = { HWC_BLENDING_NONE, HWC_BLENDING_PREMULT, HWC_BLENDING_COVERAGE, }; const unsigned int layerFlags[] = { HWC_SKIP_LAYER, }; const vector vecLayerFlags(layerFlags, layerFlags + NUMA(layerFlags)); const unsigned int transformFlags[] = { HWC_TRANSFORM_FLIP_H, HWC_TRANSFORM_FLIP_V, HWC_TRANSFORM_ROT_90, // ROT_180 & ROT_270 intentionally not listed, because they // they are formed from combinations of the flags already listed. }; const vector vecTransformFlags(transformFlags, transformFlags + NUMA(transformFlags)); // File scope globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; static hwc_composer_device_1_t *hwcDevice; static EGLDisplay dpy; static EGLSurface surface; static EGLint width, height; static vector > > frames; // File scope prototypes void init(void); void initFrames(unsigned int seed); template vector vectorRandSelect(const vector& vec, size_t num); template T vectorOr(const vector& vec); /* * Main * * Performs the following high-level sequence of operations: * * 1. Command-line parsing * * 2. Initialization * * 3. For each pass: * * a. If pass is first pass or in a different group from the * previous pass, initialize the array of graphic buffers. * * b. Create a HWC list with room to specify a prandomly * selected number of layers. * * c. Select a subset of the rows from the graphic buffer array, * such that there is a unique row to be used for each * of the layers in the HWC list. * * d. Prandomly fill in the HWC list with handles * selected from any of the columns of the selected row. * * e. Pass the populated list to the HWC prepare call. * * f. Pass the populated list to the HWC set call. * * g. If additional set calls are to be made, then for each * additional set call, select a new set of handles and * perform the set call. */ int main(int argc, char *argv[]) { int rv, opt; char *chptr; unsigned int pass; char cmd[MAXCMD]; struct timeval startTime, currentTime, delta; testSetLogCatTag(LOG_TAG); // Parse command line arguments while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) { switch (opt) { case 'd': // Delay after each set operation perSetDelay = strtod(optarg, &chptr); if ((*chptr != '\0') || (perSetDelay < 0.0)) { testPrintE("Invalid command-line specified per pass delay of: " "%s", optarg); exit(1); } break; case 'D': // End of test delay // Delay between completion of final pass and restart // of framework endDelay = strtod(optarg, &chptr); if ((*chptr != '\0') || (endDelay < 0.0)) { testPrintE("Invalid command-line specified end of test delay " "of: %s", optarg); exit(2); } break; case 't': // Duration duration = strtod(optarg, &chptr); if ((*chptr != '\0') || (duration < 0.0)) { testPrintE("Invalid command-line specified duration of: %s", optarg); exit(3); } break; case 'n': // Num set operations per pass numSet = strtoul(optarg, &chptr, 10); if (*chptr != '\0') { testPrintE("Invalid command-line specified num set per pass " "of: %s", optarg); exit(4); } break; case 's': // Starting Pass sFlag = true; if (pFlag) { testPrintE("Invalid combination of command-line options."); testPrintE(" The -p option is mutually exclusive from the"); testPrintE(" -s and -e options."); exit(5); } startPass = strtoul(optarg, &chptr, 10); if (*chptr != '\0') { testPrintE("Invalid command-line specified starting pass " "of: %s", optarg); exit(6); } break; case 'e': // Ending Pass eFlag = true; if (pFlag) { testPrintE("Invalid combination of command-line options."); testPrintE(" The -p option is mutually exclusive from the"); testPrintE(" -s and -e options."); exit(7); } endPass = strtoul(optarg, &chptr, 10); if (*chptr != '\0') { testPrintE("Invalid command-line specified ending pass " "of: %s", optarg); exit(8); } break; case 'p': // Run a single specified pass pFlag = true; if (sFlag || eFlag) { testPrintE("Invalid combination of command-line options."); testPrintE(" The -p option is mutually exclusive from the"); testPrintE(" -s and -e options."); exit(9); } startPass = endPass = strtoul(optarg, &chptr, 10); if (*chptr != '\0') { testPrintE("Invalid command-line specified pass of: %s", optarg); exit(10); } break; case 'v': // Verbose verbose = true; break; case 'h': // Help case '?': default: testPrintE(" %s [options]", basename(argv[0])); testPrintE(" options:"); testPrintE(" -p Execute specified pass"); testPrintE(" -s Starting pass"); testPrintE(" -e Ending pass"); testPrintE(" -t Duration"); testPrintE(" -d Delay after each set operation"); testPrintE(" -D End of test delay"); testPrintE(" -n Num set operations per pass"); testPrintE(" -v Verbose"); exit(((optopt == 0) || (optopt == '?')) ? 0 : 11); } } if (endPass < startPass) { testPrintE("Unexpected ending pass before starting pass"); testPrintE(" startPass: %u endPass: %u", startPass, endPass); exit(12); } if (argc != optind) { testPrintE("Unexpected command-line postional argument"); testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]", basename(argv[0])); exit(13); } testPrintI("duration: %g", duration); testPrintI("startPass: %u", startPass); testPrintI("endPass: %u", endPass); testPrintI("numSet: %u", numSet); // Stop framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); exit(14); } testExecCmd(cmd); testDelay(1.0); // TODO - need means to query whether asyncronous stop // framework operation has completed. For now, just wait // a long time. init(); // For each pass gettimeofday(&startTime, NULL); for (pass = startPass; pass <= endPass; pass++) { // Stop if duration of work has already been performed gettimeofday(¤tTime, NULL); delta = tvDelta(&startTime, ¤tTime); if (tv2double(&delta) > duration) { break; } // Regenerate a new set of test frames when this pass is // either the first pass or is in a different group then // the previous pass. A group of passes are passes that // all have the same quotient when their pass number is // divided by passesPerGroup. if ((pass == startPass) || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) { initFrames(pass / passesPerGroup); } testPrintI("==== Starting pass: %u", pass); // Cause deterministic sequence of prandom numbers to be // generated for this pass. srand48(pass); hwc_display_contents_1_t *list; list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1); if (list == NULL) { testPrintE("hwcTestCreateLayerList failed"); exit(20); } // Prandomly select a subset of frames to be used by this pass. vector > > selectedFrames; selectedFrames = vectorRandSelect(frames, list->numHwLayers); // Any transform tends to create a layer that the hardware // composer is unable to support and thus has to leave for // SurfaceFlinger. Place heavy bias on specifying no transforms. bool noTransform = testRandFract() > rareRatio; for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { unsigned int idx = testRandMod(selectedFrames[n1].size()); sp gBuf = selectedFrames[n1][idx]; hwc_layer_1_t *layer = &list->hwLayers[n1]; layer->handle = gBuf->handle; layer->blending = blendingOps[testRandMod(NUMA(blendingOps))]; layer->flags = (testRandFract() > rareRatio) ? 0 : vectorOr(vectorRandSelect(vecLayerFlags, testRandMod(vecLayerFlags.size() + 1))); layer->transform = (noTransform || testRandFract() > rareRatio) ? 0 : vectorOr(vectorRandSelect(vecTransformFlags, testRandMod(vecTransformFlags.size() + 1))); layer->sourceCrop.left = testRandMod(gBuf->getWidth()); layer->sourceCrop.top = testRandMod(gBuf->getHeight()); layer->sourceCrop.right = layer->sourceCrop.left + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1; layer->sourceCrop.bottom = layer->sourceCrop.top + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1; layer->displayFrame.left = testRandMod(width); layer->displayFrame.top = testRandMod(height); layer->displayFrame.right = layer->displayFrame.left + testRandMod(width - layer->displayFrame.left) + 1; layer->displayFrame.bottom = layer->displayFrame.top + testRandMod(height - layer->displayFrame.top) + 1; // Increase the frequency that a scale factor of 1.0 from // the sourceCrop to displayFrame occurs. This is the // most common scale factor used by applications and would // be rarely produced by this stress test without this // logic. if (testRandFract() <= freqRatio) { // Only change to scale factor to 1.0 if both the // width and height will fit. int sourceWidth = layer->sourceCrop.right - layer->sourceCrop.left; int sourceHeight = layer->sourceCrop.bottom - layer->sourceCrop.top; if (((layer->displayFrame.left + sourceWidth) <= width) && ((layer->displayFrame.top + sourceHeight) <= height)) { layer->displayFrame.right = layer->displayFrame.left + sourceWidth; layer->displayFrame.bottom = layer->displayFrame.top + sourceHeight; } } layer->visibleRegionScreen.numRects = 1; layer->visibleRegionScreen.rects = &layer->displayFrame; } // Perform prepare operation if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } hwcDevice->prepare(hwcDevice, 1, &list); if (verbose) { testPrintI("Post Prepare:"); hwcTestDisplayListPrepareModifiable(list); } // Turn off the geometry changed flag list->flags &= ~HWC_GEOMETRY_CHANGED; // Perform the set operation(s) if (verbose) {testPrintI("Set:"); } for (unsigned int n1 = 0; n1 < numSet; n1++) { if (verbose) { hwcTestDisplayListHandles(list); } list->dpy = dpy; list->sur = surface; hwcDevice->set(hwcDevice, 1, &list); // Prandomly select a new set of handles for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { unsigned int idx = testRandMod(selectedFrames[n1].size()); sp gBuf = selectedFrames[n1][idx]; hwc_layer_1_t *layer = &list->hwLayers[n1]; layer->handle = (native_handle_t *) gBuf->handle; } testDelay(perSetDelay); } hwcTestFreeLayerList(list); testPrintI("==== Completed pass: %u", pass); } testDelay(endDelay); // Start framework rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); if (rv >= (signed) sizeof(cmd) - 1) { testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); exit(21); } testExecCmd(cmd); testPrintI("Successfully completed %u passes", pass - startPass); return 0; } void init(void) { srand48(0); // Defensively set pseudo random number generator. // Should not need to set this, because a stress test // sets the seed on each pass. Defensively set it here // so that future code that uses pseudo random numbers // before the first pass will be deterministic. hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); hwcTestOpenHwc(&hwcDevice); } /* * Initialize Frames * * Creates an array of graphic buffers, within the global variable * named frames. The graphic buffers are contained within a vector of * vectors. All the graphic buffers in a particular row are of the same * format and dimension. Each graphic buffer is uniformly filled with a * prandomly selected color. It is likely that each buffer, even * in the same row, will be filled with a unique color. */ void initFrames(unsigned int seed) { int rv; const size_t maxRows = 5; const size_t minCols = 2; // Need at least double buffering const size_t maxCols = 4; // One more than triple buffering if (verbose) { testPrintI("initFrames seed: %u", seed); } srand48(seed); size_t rows = testRandMod(maxRows) + 1; frames.clear(); frames.resize(rows); for (unsigned int row = 0; row < rows; row++) { // All frames within a row have to have the same format and // dimensions. Width and height need to be >= 1. unsigned int formatIdx = testRandMod(NUMA(hwcTestGraphicFormat)); const struct hwcTestGraphicFormat *formatPtr = &hwcTestGraphicFormat[formatIdx]; int format = formatPtr->format; // Pick width and height, which must be >= 1 and the size // mod the wMod/hMod value must be equal to 0. size_t w = (width * maxSizeRatio) * testRandFract(); size_t h = (height * maxSizeRatio) * testRandFract(); w = max(size_t(1u), w); h = max(size_t(1u), h); if ((w % formatPtr->wMod) != 0) { w += formatPtr->wMod - (w % formatPtr->wMod); } if ((h % formatPtr->hMod) != 0) { h += formatPtr->hMod - (h % formatPtr->hMod); } if (verbose) { testPrintI(" frame %u width: %u height: %u format: %u %s", row, w, h, format, hwcTestGraphicFormat2str(format)); } size_t cols = testRandMod((maxCols + 1) - minCols) + minCols; frames[row].resize(cols); for (unsigned int col = 0; col < cols; col++) { ColorFract color(testRandFract(), testRandFract(), testRandFract()); float alpha = testRandFract(); frames[row][col] = new GraphicBuffer(w, h, format, texUsage); if ((rv = frames[row][col]->initCheck()) != NO_ERROR) { testPrintE("GraphicBuffer initCheck failed, rv: %i", rv); testPrintE(" frame %u width: %u height: %u format: %u %s", row, w, h, format, hwcTestGraphicFormat2str(format)); exit(80); } hwcTestFillColor(frames[row][col].get(), color, alpha); if (verbose) { testPrintI(" buf: %p handle: %p color: %s alpha: %f", frames[row][col].get(), frames[row][col]->handle, string(color).c_str(), alpha); } } } } /* * Vector Random Select * * Prandomly selects and returns num elements from vec. */ template vector vectorRandSelect(const vector& vec, size_t num) { vector rv = vec; while (rv.size() > num) { rv.erase(rv.begin() + testRandMod(rv.size())); } return rv; } /* * Vector Or * * Or's togethen the values of each element of vec and returns the result. */ template T vectorOr(const vector& vec) { T rv = 0; for (size_t n1 = 0; n1 < vec.size(); n1++) { rv |= vec[n1]; } return rv; } opengl/tests/hwc/hwcTestLib.cpp0100644 0000000 0000000 00000104174 13077405420 015601 0ustar000000000 0000000 /* * 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. * */ /* * Hardware Composer Test Library * Utility library functions for use by the Hardware Composer test cases */ #include // For ntohl() and htonl() #include #include #include #include "hwcTestLib.h" #include "EGLUtils.h" // Defines #define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Function Prototypes static void printGLString(const char *name, GLenum s); static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config); using namespace std; using namespace android; #define BITSPERBYTE 8 // TODO: Obtain from , once // it has been added // Initialize Display void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, EGLint *width, EGLint *height) { static EGLContext context; EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint sConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint majorVersion, minorVersion; checkEglError(""); *dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); if (*dpy == EGL_NO_DISPLAY) { testPrintE("eglGetDisplay returned EGL_NO_DISPLAY"); exit(70); } returnValue = eglInitialize(*dpy, &majorVersion, &minorVersion); checkEglError("eglInitialize", returnValue); if (verbose) { testPrintI("EGL version %d.%d", majorVersion, minorVersion); } if (returnValue != EGL_TRUE) { testPrintE("eglInitialize failed"); exit(71); } // The tests want to stop the framework and play with the hardware // composer, which means it doesn't make sense to use WindowSurface // here. android_createDisplaySurface() is going away, so just // politely fail here. EGLNativeWindowType window = NULL; //android_createDisplaySurface(); if (window == NULL) { testPrintE("android_createDisplaySurface failed"); exit(72); } returnValue = EGLUtils::selectConfigForNativeWindow(*dpy, sConfigAttribs, window, &myConfig); if (returnValue) { testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); exit(73); } checkEglError("EGLUtils::selectConfigForNativeWindow"); if (verbose) { testPrintI("Chose this configuration:"); printEGLConfiguration(*dpy, myConfig); } *surface = eglCreateWindowSurface(*dpy, myConfig, window, NULL); checkEglError("eglCreateWindowSurface"); if (*surface == EGL_NO_SURFACE) { testPrintE("gelCreateWindowSurface failed."); exit(74); } context = eglCreateContext(*dpy, myConfig, EGL_NO_CONTEXT, contextAttribs); checkEglError("eglCreateContext"); if (context == EGL_NO_CONTEXT) { testPrintE("eglCreateContext failed"); exit(75); } returnValue = eglMakeCurrent(*dpy, *surface, *surface, context); checkEglError("eglMakeCurrent", returnValue); if (returnValue != EGL_TRUE) { testPrintE("eglMakeCurrent failed"); exit(76); } eglQuerySurface(*dpy, *surface, EGL_WIDTH, width); checkEglError("eglQuerySurface"); eglQuerySurface(*dpy, *surface, EGL_HEIGHT, height); checkEglError("eglQuerySurface"); if (verbose) { testPrintI("Window dimensions: %d x %d", *width, *height); printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); } } // Open Hardware Composer Device void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr) { int rv; hw_module_t const *hwcModule; if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) { testPrintE("hw_get_module failed, rv: %i", rv); errno = -rv; perror(NULL); exit(77); } if ((rv = hwc_open_1(hwcModule, hwcDevicePtr)) != 0) { testPrintE("hwc_open failed, rv: %i", rv); errno = -rv; perror(NULL); exit(78); } } // Color fraction class to string conversion ColorFract::operator string() { ostringstream out; out << '[' << this->c1() << ", " << this->c2() << ", " << this->c3() << ']'; return out.str(); } // Dimension class to string conversion HwcTestDim::operator string() { ostringstream out; out << '[' << this->width() << ", " << this->height() << ']'; return out.str(); } // Dimension class to hwc_rect conversion HwcTestDim::operator hwc_rect() const { hwc_rect rect; rect.left = rect.top = 0; rect.right = this->_w; rect.bottom = this->_h; return rect; } // Hardware Composer rectangle to string conversion string hwcTestRect2str(const struct hwc_rect& rect) { ostringstream out; out << '['; out << rect.left << ", "; out << rect.top << ", "; out << rect.right << ", "; out << rect.bottom; out << ']'; return out.str(); } // Parse HWC rectangle description of form [left, top, right, bottom] struct hwc_rect hwcTestParseHwcRect(istringstream& in, bool& error) { struct hwc_rect rect; char chStart, ch; // Defensively specify that an error occurred. Will clear // error flag if all of parsing succeeds. error = true; // First character should be a [ or < in >> chStart; if (!in || ((chStart != '<') && (chStart != '['))) { return rect; } // Left in >> rect.left; if (!in) { return rect; } in >> ch; if (!in || (ch != ',')) { return rect; } // Top in >> rect.top; if (!in) { return rect; } in >> ch; if (!in || (ch != ',')) { return rect; } // Right in >> rect.right; if (!in) { return rect; } in >> ch; if (!in || (ch != ',')) { return rect; } // Bottom in >> rect.bottom; if (!in) { return rect; } // Closing > or ] in >> ch; if (!in) { return rect; } if (((chStart == '<') && (ch != '>')) || ((chStart == '[') && (ch != ']'))) { return rect; } // Validate right and bottom are greater than left and top if ((rect.right <= rect.left) || (rect.bottom <= rect.top)) { return rect; } // Made It, clear error indicator error = false; return rect; } // Parse dimension of form [width, height] HwcTestDim hwcTestParseDim(istringstream& in, bool& error) { HwcTestDim dim; char chStart, ch; uint32_t val; // Defensively specify that an error occurred. Will clear // error flag if all of parsing succeeds. error = true; // First character should be a [ or < in >> chStart; if (!in || ((chStart != '<') && (chStart != '['))) { return dim; } // Width in >> val; if (!in) { return dim; } dim.setWidth(val); in >> ch; if (!in || (ch != ',')) { return dim; } // Height in >> val; if (!in) { return dim; } dim.setHeight(val); // Closing > or ] in >> ch; if (!in) { return dim; } if (((chStart == '<') && (ch != '>')) || ((chStart == '[') && (ch != ']'))) { return dim; } // Validate width and height greater than 0 if ((dim.width() <= 0) || (dim.height() <= 0)) { return dim; } // Made It, clear error indicator error = false; return dim; } // Parse fractional color of form [0.##, 0.##, 0.##] // Fractional values can be from 0.0 to 1.0 inclusive. Note, integer // values of 0.0 and 1.0, which are non-fractional, are considered valid. // They are an exception, all other valid inputs are fractions. ColorFract hwcTestParseColor(istringstream& in, bool& error) { ColorFract color; char chStart, ch; float c1, c2, c3; // Defensively specify that an error occurred. Will clear // error flag if all of parsing succeeds. error = true; // First character should be a [ or < in >> chStart; if (!in || ((chStart != '<') && (chStart != '['))) { return color; } // 1st Component in >> c1; if (!in) { return color; } if ((c1 < 0.0) || (c1 > 1.0)) { return color; } in >> ch; if (!in || (ch != ',')) { return color; } // 2nd Component in >> c2; if (!in) { return color; } if ((c2 < 0.0) || (c2 > 1.0)) { return color; } in >> ch; if (!in || (ch != ',')) { return color; } // 3rd Component in >> c3; if (!in) { return color; } if ((c3 < 0.0) || (c3 > 1.0)) { return color; } // Closing > or ] in >> ch; if (!in) { return color; } if (((chStart == '<') && (ch != '>')) || ((chStart == '[') && (ch != ']'))) { return color; } // Are all the components fractional if ((c1 < 0.0) || (c1 > 1.0) || (c2 < 0.0) || (c2 > 1.0) || (c3 < 0.0) || (c3 > 1.0)) { return color; } // Made It, clear error indicator error = false; return ColorFract(c1, c2, c3); } // Look up and return pointer to structure with the characteristics // of the graphic format named by the desc parameter. Search failure // indicated by the return of NULL. const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc) { for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { if (string(desc) == string(hwcTestGraphicFormat[n1].desc)) { return &hwcTestGraphicFormat[n1]; } } return NULL; } // Look up and return pointer to structure with the characteristics // of the graphic format specified by the id parameter. Search failure // indicated by the return of NULL. const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(uint32_t id) { for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { if (id == hwcTestGraphicFormat[n1].format) { return &hwcTestGraphicFormat[n1]; } } return NULL; } // Given the integer ID of a graphic format, return a pointer to // a string that describes the format. const char *hwcTestGraphicFormat2str(uint32_t format) { const static char *unknown = "unknown"; for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { if (format == hwcTestGraphicFormat[n1].format) { return hwcTestGraphicFormat[n1].desc; } } return unknown; } /* * hwcTestCreateLayerList * Dynamically creates layer list with numLayers worth * of hwLayers entries. */ hwc_display_contents_1_t *hwcTestCreateLayerList(size_t numLayers) { hwc_display_contents_1_t *list; size_t size = sizeof(hwc_display_contents_1_t) + numLayers * sizeof(hwc_layer_1_t); if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { return NULL; } list->flags = HWC_GEOMETRY_CHANGED; list->numHwLayers = numLayers; return list; } /* * hwcTestFreeLayerList * Frees memory previous allocated via hwcTestCreateLayerList(). */ void hwcTestFreeLayerList(hwc_display_contents_1_t *list) { free(list); } // Display the settings of the layer list pointed to by list void hwcTestDisplayList(hwc_display_contents_1_t *list) { testPrintI(" flags: %#x%s", list->flags, (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : ""); testPrintI(" numHwLayers: %u", list->numHwLayers); for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { testPrintI(" layer %u compositionType: %#x%s%s", layer, list->hwLayers[layer].compositionType, (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) ? " FRAMEBUFFER" : "", (list->hwLayers[layer].compositionType == HWC_OVERLAY) ? " OVERLAY" : ""); testPrintI(" hints: %#x", list->hwLayers[layer].hints, (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) ? " TRIPLE_BUFFER" : "", (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) ? " CLEAR_FB" : ""); testPrintI(" flags: %#x%s", list->hwLayers[layer].flags, (list->hwLayers[layer].flags & HWC_SKIP_LAYER) ? " SKIP_LAYER" : ""); testPrintI(" handle: %p", list->hwLayers[layer].handle); // Intentionally skipped display of ROT_180 & ROT_270, // which are formed from combinations of the other flags. testPrintI(" transform: %#x%s%s%s", list->hwLayers[layer].transform, (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H) ? " FLIP_H" : "", (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V) ? " FLIP_V" : "", (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90) ? " ROT_90" : ""); testPrintI(" blending: %#x%s%s%s", list->hwLayers[layer].blending, (list->hwLayers[layer].blending == HWC_BLENDING_NONE) ? " NONE" : "", (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT) ? " PREMULT" : "", (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE) ? " COVERAGE" : ""); testPrintI(" sourceCrop: %s", hwcTestRect2str(list->hwLayers[layer].sourceCrop).c_str()); testPrintI(" displayFrame: %s", hwcTestRect2str(list->hwLayers[layer].displayFrame).c_str()); testPrintI(" scaleFactor: [%f, %f]", (float) (list->hwLayers[layer].sourceCrop.right - list->hwLayers[layer].sourceCrop.left) / (float) (list->hwLayers[layer].displayFrame.right - list->hwLayers[layer].displayFrame.left), (float) (list->hwLayers[layer].sourceCrop.bottom - list->hwLayers[layer].sourceCrop.top) / (float) (list->hwLayers[layer].displayFrame.bottom - list->hwLayers[layer].displayFrame.top)); } } /* * Display List Prepare Modifiable * * Displays the portions of a list that are meant to be modified by * a prepare call. */ void hwcTestDisplayListPrepareModifiable(hwc_display_contents_1_t *list) { uint32_t numOverlays = 0; for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { if (list->hwLayers[layer].compositionType == HWC_OVERLAY) { numOverlays++; } testPrintI(" layer %u compositionType: %#x%s%s", layer, list->hwLayers[layer].compositionType, (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) ? " FRAMEBUFFER" : "", (list->hwLayers[layer].compositionType == HWC_OVERLAY) ? " OVERLAY" : ""); testPrintI(" hints: %#x%s%s", list->hwLayers[layer].hints, (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) ? " TRIPLE_BUFFER" : "", (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) ? " CLEAR_FB" : ""); } testPrintI(" numOverlays: %u", numOverlays); } /* * Display List Handles * * Displays the handles of all the graphic buffers in the list. */ void hwcTestDisplayListHandles(hwc_display_contents_1_t *list) { const unsigned int maxLayersPerLine = 6; ostringstream str(" layers:"); for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { str << ' ' << list->hwLayers[layer].handle; if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1)) && (layer != list->numHwLayers - 1)) { testPrintI("%s", str.str().c_str()); str.str(" "); } } testPrintI("%s", str.str().c_str()); } // Returns a uint32_t that contains a format specific representation of a // single pixel of the given color and alpha values. uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha) { const struct attrib { uint32_t format; bool hostByteOrder; size_t bytes; size_t c1Offset; size_t c1Size; size_t c2Offset; size_t c2Size; size_t c3Offset; size_t c3Size; size_t aOffset; size_t aSize; } attributes[] = { {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8}, {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0}, {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0}, {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0}, {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8}, {HAL_PIXEL_FORMAT_YV12, true, 3, 16, 8, 8, 8, 0, 8, 0, 0}, }; const struct attrib *attrib; for (attrib = attributes; attrib < attributes + NUMA(attributes); attrib++) { if (attrib->format == format) { break; } } if (attrib >= attributes + NUMA(attributes)) { testPrintE("colorFract2Pixel unsupported format of: %u", format); exit(80); } uint32_t pixel; pixel = htonl((uint32_t) round((((1 << attrib->c1Size) - 1) * color.c1())) << ((sizeof(pixel) * BITSPERBYTE) - (attrib->c1Offset + attrib->c1Size))); pixel |= htonl((uint32_t) round((((1 << attrib->c2Size) - 1) * color.c2())) << ((sizeof(pixel) * BITSPERBYTE) - (attrib->c2Offset + attrib->c2Size))); pixel |= htonl((uint32_t) round((((1 << attrib->c3Size) - 1) * color.c3())) << ((sizeof(pixel) * BITSPERBYTE) - (attrib->c3Offset + attrib->c3Size))); if (attrib->aSize) { pixel |= htonl((uint32_t) round((((1 << attrib->aSize) - 1) * alpha)) << ((sizeof(pixel) * BITSPERBYTE) - (attrib->aOffset + attrib->aSize))); } if (attrib->hostByteOrder) { pixel = ntohl(pixel); pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE; } return pixel; } // Sets the pixel at the given x and y coordinates to the color and alpha // value given by pixel. The contents of pixel is format specific. It's // value should come from a call to hwcTestColor2Pixel(). void hwcTestSetPixel(GraphicBuffer *gBuf, unsigned char *buf, uint32_t x, uint32_t y, uint32_t pixel) { const struct attrib { int format; size_t bytes; } attributes[] = { {HAL_PIXEL_FORMAT_RGBA_8888, 4}, {HAL_PIXEL_FORMAT_RGBX_8888, 4}, {HAL_PIXEL_FORMAT_RGB_888, 3}, {HAL_PIXEL_FORMAT_RGB_565, 2}, {HAL_PIXEL_FORMAT_BGRA_8888, 4}, }; if (gBuf->getPixelFormat() == HAL_PIXEL_FORMAT_YV12) { uint32_t yPlaneOffset, uPlaneOffset, vPlaneOffset; uint32_t yPlaneStride = gBuf->getStride(); uint32_t uPlaneStride = ((gBuf->getStride() / 2) + 0xf) & ~0xf; uint32_t vPlaneStride = uPlaneStride; yPlaneOffset = 0; vPlaneOffset = yPlaneOffset + yPlaneStride * gBuf->getHeight(); uPlaneOffset = vPlaneOffset + vPlaneStride * (gBuf->getHeight() / 2); *(buf + yPlaneOffset + y * yPlaneStride + x) = pixel & 0xff; *(buf + uPlaneOffset + (y / 2) * uPlaneStride + (x / 2)) = (pixel & 0xff00) >> 8; *(buf + vPlaneOffset + (y / 2) * vPlaneStride + (x / 2)) = (pixel & 0xff0000) >> 16; return; } const struct attrib *attrib; for (attrib = attributes; attrib < attributes + NUMA(attributes); attrib++) { if (attrib->format == gBuf->getPixelFormat()) { break; } } if (attrib >= attributes + NUMA(attributes)) { testPrintE("setPixel unsupported format of: %u", gBuf->getPixelFormat()); exit(90); } memmove(buf + ((gBuf->getStride() * attrib->bytes) * y) + (attrib->bytes * x), &pixel, attrib->bytes); } // Fill a given graphic buffer with a uniform color and alpha void hwcTestFillColor(GraphicBuffer *gBuf, ColorFract color, float alpha) { unsigned char* buf = NULL; status_t err; uint32_t pixel; pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, alpha); err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); if (err != 0) { testPrintE("hwcTestFillColor lock failed: %d", err); exit(100); } for (unsigned int x = 0; x < gBuf->getStride(); x++) { for (unsigned int y = 0; y < gBuf->getHeight(); y++) { hwcTestSetPixel(gBuf, buf, x, y, (x < gBuf->getWidth()) ? pixel : testRand()); } } err = gBuf->unlock(); if (err != 0) { testPrintE("hwcTestFillColor unlock failed: %d", err); exit(101); } } // Fill the given buffer with a horizontal blend of colors, with the left // side color given by startColor and the right side color given by // endColor. The startColor and endColor values are specified in the format // given by colorFormat, which might be different from the format of the // graphic buffer. When different, a color conversion is done when possible // to the graphic format of the graphic buffer. A color of black is // produced for cases where the conversion is impossible (e.g. out of gamut // values). void hwcTestFillColorHBlend(GraphicBuffer *gBuf, uint32_t colorFormat, ColorFract startColor, ColorFract endColor) { status_t err; unsigned char* buf = NULL; const uint32_t width = gBuf->getWidth(); const uint32_t height = gBuf->getHeight(); const uint32_t stride = gBuf->getStride(); err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); if (err != 0) { testPrintE("hwcTestFillColorHBlend lock failed: %d", err); exit(110); } for (unsigned int x = 0; x < stride; x++) { uint32_t pixel; if (x < width) { ColorFract color(startColor.c1() + (endColor.c1() - startColor.c1()) * ((float) x / (float) (width - 1)), startColor.c2() + (endColor.c2() - startColor.c2()) * ((float) x / (float) (width - 1)), startColor.c3() + (endColor.c3() - startColor.c3()) * ((float) x / (float) (width - 1))); // When formats differ, convert colors. // Important to not convert when formats are the same, since // out of gamut colors are always converted to black. if (colorFormat != (uint32_t) gBuf->getPixelFormat()) { hwcTestColorConvert(colorFormat, gBuf->getPixelFormat(), color); } pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, 1.0); } else { // Fill pad with random values pixel = testRand(); } for (unsigned int y = 0; y < height; y++) { hwcTestSetPixel(gBuf, buf, x, y, pixel); } } err = gBuf->unlock(); if (err != 0) { testPrintE("hwcTestFillColorHBlend unlock failed: %d", err); exit(111); } } /* * When possible, converts color specified as a full range value in * the fromFormat, into an equivalent full range color in the toFormat. * When conversion is impossible (e.g. out of gamut color) a color * or black in the full range output format is produced. The input * color is given as a fractional color in the parameter named color. * The produced color is written over the same parameter used to * provide the input color. * * Each graphic format has 3 color components and each of these * components has both a full and in gamut range. This function uses * a table that provides the full and in gamut ranges of each of the * supported graphic formats. The full range is given by members named * c[123]Min to c[123]Max, while the in gamut range is given by members * named c[123]Low to c[123]High. In most cases the full and in gamut * ranges are equivalent. This occurs when the c[123]Min == c[123]Low and * c[123]High == c[123]Max. * * The input and produced colors are both specified as a fractional amount * of the full range. The diagram below provides an overview of the * conversion process. The main steps are: * * 1. Produce black if the input color is out of gamut. * * 2. Convert the in gamut color into the fraction of the fromFromat * in gamut range. * * 3. Convert from the fraction of the in gamut from format range to * the fraction of the in gamut to format range. Produce black * if an equivalent color does not exists. * * 4. Covert from the fraction of the in gamut to format to the * fraction of the full range to format. * * From Format To Format * max high high max * ----+ +-----------+ * high \ / \ high * ------\-------------+ +--------> * \ * \ +--- black --+ * \ / \ * \ / +--> * low \ / low * -------- ---+-- black --+ * min low low min * ^ ^ ^ ^ ^ * | | | | | * | | | | +-- fraction of full range * | | | +-- fraction of valid range * | | +-- fromFormat to toFormat color conversion * | +-- fraction of valid range * +-- fraction of full range */ void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat, ColorFract& color) { const struct attrib { uint32_t format; bool rgb; bool yuv; int c1Min, c1Low, c1High, c1Max; int c2Min, c2Low, c2High, c2Max; int c3Min, c3Low, c3High, c3Max; } attributes[] = { {HAL_PIXEL_FORMAT_RGBA_8888, true, false, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, {HAL_PIXEL_FORMAT_RGBX_8888, true, false, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, {HAL_PIXEL_FORMAT_RGB_888, true, false, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, {HAL_PIXEL_FORMAT_RGB_565, true, false, 0, 0, 31, 31, 0, 0, 63, 63, 0, 0, 31, 31}, {HAL_PIXEL_FORMAT_BGRA_8888, true, false, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, {HAL_PIXEL_FORMAT_YV12, false, true, 0, 16, 235, 255, 0, 16, 240, 255, 0, 16, 240, 255}, }; const struct attrib *fromAttrib; for (fromAttrib = attributes; fromAttrib < attributes + NUMA(attributes); fromAttrib++) { if (fromAttrib->format == fromFormat) { break; } } if (fromAttrib >= attributes + NUMA(attributes)) { testPrintE("hwcTestColorConvert unsupported from format of: %u", fromFormat); exit(120); } const struct attrib *toAttrib; for (toAttrib = attributes; toAttrib < attributes + NUMA(attributes); toAttrib++) { if (toAttrib->format == toFormat) { break; } } if (toAttrib >= attributes + NUMA(attributes)) { testPrintE("hwcTestColorConvert unsupported to format of: %u", toFormat); exit(121); } // Produce black if any of the from components are outside the // valid color range float c1Val = fromAttrib->c1Min + ((float) (fromAttrib->c1Max - fromAttrib->c1Min) * color.c1()); float c2Val = fromAttrib->c2Min + ((float) (fromAttrib->c2Max - fromAttrib->c2Min) * color.c2()); float c3Val = fromAttrib->c3Min + ((float) (fromAttrib->c3Max - fromAttrib->c3Min) * color.c3()); if ((c1Val < fromAttrib->c1Low) || (c1Val > fromAttrib->c1High) || (c2Val < fromAttrib->c2Low) || (c2Val > fromAttrib->c2High) || (c3Val < fromAttrib->c3Low) || (c3Val > fromAttrib->c3High)) { // Return black // Will use representation of black from RGBA8888 graphic format // and recursively convert it to the requested graphic format. color = ColorFract(0.0, 0.0, 0.0); hwcTestColorConvert(HAL_PIXEL_FORMAT_RGBA_8888, toFormat, color); return; } // Within from format, convert from fraction of full range // to fraction of valid range color = ColorFract((c1Val - fromAttrib->c1Low) / (fromAttrib->c1High - fromAttrib->c1Low), (c2Val - fromAttrib->c2Low) / (fromAttrib->c2High - fromAttrib->c2Low), (c3Val - fromAttrib->c3Low) / (fromAttrib->c3High - fromAttrib->c3Low)); // If needed perform RGB to YUV conversion float wr = 0.2126, wg = 0.7152, wb = 0.0722; // ITU709 recommended constants if (fromAttrib->rgb && toAttrib->yuv) { float r = color.c1(), g = color.c2(), b = color.c3(); float y = wr * r + wg * g + wb * b; float u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5; float v = 0.5 * ((r - y) / (1.0 - wr)) + 0.5; // Produce black if color is outside the YUV gamut if ((y < 0.0) || (y > 1.0) || (u < 0.0) || (u > 1.0) || (v < 0.0) || (v > 1.0)) { y = 0.0; u = v = 0.5; } color = ColorFract(y, u, v); } // If needed perform YUV to RGB conversion // Equations determined from the ITU709 equations for RGB to YUV // conversion, plus the following algebra: // // u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5 // 0.5 * ((b - y) / (1.0 - wb)) = u - 0.5 // (b - y) / (1.0 - wb) = 2 * (u - 0.5) // b - y = 2 * (u - 0.5) * (1.0 - wb) // b = 2 * (u - 0.5) * (1.0 - wb) + y // // v = 0.5 * ((r -y) / (1.0 - wr)) + 0.5 // 0.5 * ((r - y) / (1.0 - wr)) = v - 0.5 // (r - y) / (1.0 - wr) = 2 * (v - 0.5) // r - y = 2 * (v - 0.5) * (1.0 - wr) // r = 2 * (v - 0.5) * (1.0 - wr) + y // // y = wr * r + wg * g + wb * b // wr * r + wg * g + wb * b = y // wg * g = y - wr * r - wb * b // g = (y - wr * r - wb * b) / wg if (fromAttrib->yuv && toAttrib->rgb) { float y = color.c1(), u = color.c2(), v = color.c3(); float r = 2.0 * (v - 0.5) * (1.0 - wr) + y; float b = 2.0 * (u - 0.5) * (1.0 - wb) + y; float g = (y - wr * r - wb * b) / wg; // Produce black if color is outside the RGB gamut if ((r < 0.0) || (r > 1.0) || (g < 0.0) || (g > 1.0) || (b < 0.0) || (b > 1.0)) { r = g = b = 0.0; } color = ColorFract(r, g, b); } // Within to format, convert from fraction of valid range // to fraction of full range c1Val = (toAttrib->c1Low + (float) (toAttrib->c1High - toAttrib->c1Low) * color.c1()); c2Val = (toAttrib->c1Low + (float) (toAttrib->c2High - toAttrib->c2Low) * color.c2()); c3Val = (toAttrib->c1Low + (float) (toAttrib->c3High - toAttrib->c3Low) * color.c3()); color = ColorFract((float) (c1Val - toAttrib->c1Min) / (float) (toAttrib->c1Max - toAttrib->c1Min), (float) (c2Val - toAttrib->c2Min) / (float) (toAttrib->c2Max - toAttrib->c2Min), (float) (c3Val - toAttrib->c3Min) / (float) (toAttrib->c3Max - toAttrib->c3Min)); } // TODO: Use PrintGLString, CechckGlError, and PrintEGLConfiguration // from libglTest static void printGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); if (v == NULL) { testPrintI("GL %s unknown", name); } else { testPrintI("GL %s = %s", name, v); } } static void checkEglError(const char* op, EGLBoolean returnVal) { if (returnVal != EGL_TRUE) { testPrintE("%s() returned %d", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { testPrintE("after %s() eglError %s (0x%x)", op, EGLUtils::strerror(error), error); } } static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { testPrintI(" %s: %d (%#x)", names[j].name, value, value); } } testPrintI(""); } opengl/tests/hwc/hwcTestLib.h0100644 0000000 0000000 00000010627 13077405420 015245 0ustar000000000 0000000 /* * 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. * */ /* * Hardware Composer Test Library Header */ #include #include #include #include #include #include #include #include #include #include // Characteristics of known graphic formats const struct hwcTestGraphicFormat { uint32_t format; const char *desc; uint32_t wMod, hMod; // Width/height mod this value must equal zero } hwcTestGraphicFormat[] = { {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1}, {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1}, {HAL_PIXEL_FORMAT_RGB_888, "RGB888", 1, 1}, {HAL_PIXEL_FORMAT_RGB_565, "RGB565", 1, 1}, {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1}, {HAL_PIXEL_FORMAT_YV12, "YV12", 2, 2}, }; // Represent RGB color as fraction of color components. // Each of the color components are expected in the range [0.0, 1.0] class ColorFract { public: ColorFract(): _c1(0.0), _c2(0.0), _c3(0.0) {}; ColorFract(float c1, float c2, float c3): _c1(c1), _c2(c2), _c3(c3) {}; float c1(void) const { return _c1; } float c2(void) const { return _c2; } float c3(void) const { return _c3; } operator std::string(); private: float _c1; float _c2; float _c3; }; // Represent RGB color as fraction of color components. // Each of the color components are expected in the range [0.0, 1.0] class ColorRGB { public: ColorRGB(): _r(0.0), _g(0.0), _b(0.0) {}; ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray ColorRGB(float r, float g, float b): _r(r), _g(g), _b(b) {}; float r(void) const { return _r; } float g(void) const { return _g; } float b(void) const { return _b; } private: float _r; float _g; float _b; }; // Dimension - width and height of a rectanguler area class HwcTestDim { public: HwcTestDim(): _w(0), _h(0) {}; HwcTestDim(uint32_t w, uint32_t h) : _w(w), _h(h) {} uint32_t width(void) const { return _w; } uint32_t height(void) const { return _h; } void setWidth(uint32_t w) { _w = w; } void setHeight(uint32_t h) { _h = h; } operator std::string(); operator hwc_rect() const; private: uint32_t _w; uint32_t _h; }; // Function Prototypes void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, EGLint *width, EGLint *height); void hwcTestOpenHwc(hwc_composer_device_1_t **hwcDevicePtr); const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc); const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(uint32_t id); const char *hwcTestGraphicFormat2str(uint32_t format); std::string hwcTestRect2str(const struct hwc_rect& rect); hwc_display_contents_1_t *hwcTestCreateLayerList(size_t numLayers); void hwcTestFreeLayerList(hwc_display_contents_1_t *list); void hwcTestDisplayList(hwc_display_contents_1_t *list); void hwcTestDisplayListPrepareModifiable(hwc_display_contents_1_t *list); void hwcTestDisplayListHandles(hwc_display_contents_1_t *list); uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha); void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat, ColorFract& color); void hwcTestSetPixel(android::GraphicBuffer *gBuf, unsigned char *buf, uint32_t x, uint32_t y, uint32_t pixel); void hwcTestFillColor(android::GraphicBuffer *gBuf, ColorFract color, float alpha); void hwcTestFillColorHBlend(android::GraphicBuffer *gBuf, uint32_t colorFormat, ColorFract startColor, ColorFract endColor); ColorFract hwcTestParseColor(std::istringstream& in, bool& error); struct hwc_rect hwcTestParseHwcRect(std::istringstream& in, bool& error); HwcTestDim hwcTestParseDim(std::istringstream& in, bool& error); opengl/tests/include/0040755 0000000 0000000 00000000000 13077405420 013663 5ustar000000000 0000000 opengl/tests/include/EGLUtils.h0100644 0000000 0000000 00000010307 13077405420 015462 0ustar000000000 0000000 /* * Copyright (C) 2009 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_UI_EGLUTILS_H #define ANDROID_UI_EGLUTILS_H #include #include #include #include #include // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- class EGLUtils { public: static inline const char *strerror(EGLint err); static inline status_t selectConfigForPixelFormat( EGLDisplay dpy, EGLint const* attrs, int32_t format, EGLConfig* outConfig); static inline status_t selectConfigForNativeWindow( EGLDisplay dpy, EGLint const* attrs, EGLNativeWindowType window, EGLConfig* outConfig); }; // ---------------------------------------------------------------------------- const char *EGLUtils::strerror(EGLint err) { switch (err){ case EGL_SUCCESS: return "EGL_SUCCESS"; case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; default: return "UNKNOWN"; } } status_t EGLUtils::selectConfigForPixelFormat( EGLDisplay dpy, EGLint const* attrs, int32_t format, EGLConfig* outConfig) { EGLint numConfigs = -1, n=0; if (!attrs) return BAD_VALUE; if (outConfig == NULL) return BAD_VALUE; // Get all the "potential match" configs... if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE) return BAD_VALUE; EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs); if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) { free(configs); return BAD_VALUE; } int i; EGLConfig config = NULL; for (i=0 ; i0 && format == nativeVisualId) { config = configs[i]; break; } } free(configs); if (iquery(window, NATIVE_WINDOW_FORMAT, &format)) < 0) { return err; } return selectConfigForPixelFormat(dpy, attrs, format, outConfig); } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- #endif /* ANDROID_UI_EGLUTILS_H */ opengl/tests/include/WindowSurface.h0100644 0000000 0000000 00000002447 13077405420 016620 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef OPENGL_TESTS_WINDOWSURFACE_H #define OPENGL_TESTS_WINDOWSURFACE_H #include #include namespace android { /* * A window that covers the entire display surface. * * The window is destroyed when this object is destroyed, so don't try * to use the surface after that point. */ class WindowSurface { public: // Creates the window. WindowSurface(); // Retrieves a handle to the window. EGLNativeWindowType getSurface() const; private: WindowSurface(const WindowSurface&); WindowSurface& operator=(const WindowSurface&); sp mSurfaceControl; }; } // namespace android #endif /* OPENGL_TESTS_WINDOWSURFACE_H */ opengl/tests/include/glTestLib.h0100644 0000000 0000000 00000001774 13077405420 015733 0ustar000000000 0000000 /* * 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. * */ /* * Graphics Test Library Header */ #include #include #include #include #include "EGLUtils.h" void glTestPrintGLString(const char *name, GLenum s); void glTestCheckEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); void glTestCheckGlError(const char* op); void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config); opengl/tests/lib/0040755 0000000 0000000 00000000000 13077405420 013006 5ustar000000000 0000000 opengl/tests/lib/Android.mk0100644 0000000 0000000 00000002005 13077405420 014711 0ustar000000000 0000000 # Copyright (C) 2010 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE_TAGS := tests LOCAL_MODULE:= libglTest LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp LOCAL_C_INCLUDES += system/extras/tests/include \ $(call include-path-for, opengl-tests-includes) LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror include $(BUILD_STATIC_LIBRARY) opengl/tests/lib/WindowSurface.cpp0100644 0000000 0000000 00000005247 13077405420 016277 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include using namespace android; WindowSurface::WindowSurface() { status_t err; sp surfaceComposerClient = new SurfaceComposerClient; err = surfaceComposerClient->initCheck(); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); return; } // Get main display parameters. sp mainDpy = SurfaceComposerClient::getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain); DisplayInfo mainDpyInfo; err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); if (err != NO_ERROR) { fprintf(stderr, "ERROR: unable to get display characteristics\n"); return; } uint32_t width, height; if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 && mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) { // rotated width = mainDpyInfo.h; height = mainDpyInfo.w; } else { width = mainDpyInfo.w; height = mainDpyInfo.h; } sp sc = surfaceComposerClient->createSurface( String8("Benchmark"), width, height, PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque); if (sc == NULL || !sc->isValid()) { fprintf(stderr, "Failed to create SurfaceControl\n"); return; } SurfaceComposerClient::openGlobalTransaction(); err = sc->setLayer(0x7FFFFFFF); // always on top if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); return; } err = sc->show(); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); return; } SurfaceComposerClient::closeGlobalTransaction(); mSurfaceControl = sc; } EGLNativeWindowType WindowSurface::getSurface() const { sp anw = mSurfaceControl->getSurface(); return (EGLNativeWindowType) anw.get(); } opengl/tests/lib/glTestLib.cpp0100644 0000000 0000000 00000006115 13077405420 015403 0ustar000000000 0000000 /* * 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. * */ /* * Graphics Test Library */ #include #include #include #include #include #include "EGLUtils.h" #include #include using namespace android; void glTestPrintGLString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); if (v == NULL) { testPrintI("GL %s unknown", name); } else { testPrintI("GL %s = %s", name, v); } } void glTestCheckEglError(const char* op, EGLBoolean returnVal) { if (returnVal != EGL_TRUE) { testPrintE("%s() returned %d", op, returnVal); } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { testPrintE("after %s() eglError %s (0x%x)", op, EGLUtils::strerror(error), error); } } void glTestCheckGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { testPrintE("after %s() glError (0x%x)", op, error); } } void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config) { #define X(VAL) {VAL, #VAL} struct {EGLint attribute; const char* name;} names[] = { X(EGL_BUFFER_SIZE), X(EGL_ALPHA_SIZE), X(EGL_BLUE_SIZE), X(EGL_GREEN_SIZE), X(EGL_RED_SIZE), X(EGL_DEPTH_SIZE), X(EGL_STENCIL_SIZE), X(EGL_CONFIG_CAVEAT), X(EGL_CONFIG_ID), X(EGL_LEVEL), X(EGL_MAX_PBUFFER_HEIGHT), X(EGL_MAX_PBUFFER_PIXELS), X(EGL_MAX_PBUFFER_WIDTH), X(EGL_NATIVE_RENDERABLE), X(EGL_NATIVE_VISUAL_ID), X(EGL_NATIVE_VISUAL_TYPE), X(EGL_SAMPLES), X(EGL_SAMPLE_BUFFERS), X(EGL_SURFACE_TYPE), X(EGL_TRANSPARENT_TYPE), X(EGL_TRANSPARENT_RED_VALUE), X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE), X(EGL_BIND_TO_TEXTURE_RGB), X(EGL_BIND_TO_TEXTURE_RGBA), X(EGL_MIN_SWAP_INTERVAL), X(EGL_MAX_SWAP_INTERVAL), X(EGL_LUMINANCE_SIZE), X(EGL_ALPHA_MASK_SIZE), X(EGL_COLOR_BUFFER_TYPE), X(EGL_RENDERABLE_TYPE), X(EGL_CONFORMANT), }; #undef X for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { EGLint value = -1; EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); EGLint error = eglGetError(); if (returnVal && error == EGL_SUCCESS) { testPrintI(" %s: %d (%#x)", names[j].name, value, value); } } testPrintI(""); } opengl/tests/lighting1709/0040755 0000000 0000000 00000000000 13077405420 014366 5ustar000000000 0000000 opengl/tests/lighting1709/Android.mk0100644 0000000 0000000 00000000334 13077405420 016274 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LightingTest LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) opengl/tests/lighting1709/AndroidManifest.xml0100644 0000000 0000000 00000001033 13077405420 020151 0ustar000000000 0000000 opengl/tests/lighting1709/src/0040755 0000000 0000000 00000000000 13077405420 015155 5ustar000000000 0000000 opengl/tests/lighting1709/src/com/0040755 0000000 0000000 00000000000 13077405420 015733 5ustar000000000 0000000 opengl/tests/lighting1709/src/com/android/0040755 0000000 0000000 00000000000 13077405420 017353 5ustar000000000 0000000 opengl/tests/lighting1709/src/com/android/lightingtest/0040755 0000000 0000000 00000000000 13077405420 022060 5ustar000000000 0000000 opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java0100644 0000000 0000000 00000012547 13077405420 025474 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.lightingtest; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.content.Context; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; public class ClearActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new ClearGLSurfaceView(this); setContentView(mGLView); } @Override protected void onPause() { super.onPause(); mGLView.onPause(); } @Override protected void onResume() { super.onResume(); mGLView.onResume(); } private GLSurfaceView mGLView; } class ClearGLSurfaceView extends GLSurfaceView { public ClearGLSurfaceView(Context context) { super(context); mRenderer = new ClearRenderer(); setRenderer(mRenderer); } ClearRenderer mRenderer; } class ClearRenderer implements GLSurfaceView.Renderer { public ClearRenderer() { } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing special. } public void onSurfaceChanged(GL10 gl, int w, int h) { // Compute the projection matrix gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); // Compute the boundaries of the frustum float fl = (float) (-(w / 2)) / 288; float fr = (float) (w / 2) / 288; float ft = (float) (h / 2) / 288; float fb = (float) (-(h / 2)) / 288; // Set the view frustum gl.glFrustumf(fl, fr, fb, ft, 1.0f, 2000.0f); // Set the viewport dimensions gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glViewport(0, 0, w, h); } public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); final float lightOff[] = {0.0f, 0.0f, 0.0f, 1.0f}; final float lightAmbient[] = {5.0f, 0.0f, 0.0f, 1.0f}; final float lightDiffuse[] = {0.0f, 2.0f, 0.0f, 0.0f}; final float lightPosSpot[] = {0.0f, 0.0f, -8.0f, 1.0f}; final float pos[] = { -5.0f, -1.5f, 0.0f, 0.0f, -1.5f, 0.0f, 5.0f, -1.5f, 0.0f, }; final float v[] = new float[9]; ByteBuffer vbb = ByteBuffer.allocateDirect(v.length*4); vbb.order(ByteOrder.nativeOrder()); FloatBuffer vb = vbb.asFloatBuffer(); gl.glDisable(GL10.GL_DITHER); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, lightOff, 0); gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPosSpot, 0); gl.glEnable(GL10.GL_LIGHT0); gl.glEnable(GL10.GL_LIGHTING); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glNormal3f(0, 0, 1); // draw first 3 triangles, without using transforms for (int i=0 ; i<3 ; i++) { v[0] = -1; v[1] =-1; v[2] = -10; v[3] = 0; v[4] = 1; v[5] = -10; v[6] = 1; v[7] =-1; v[8] = -10; for (int j=0 ; j<3 ; j++) { v[j*3+0] -= pos[i*3+0]; v[j*3+1] -= pos[i*3+1]; v[j*3+2] -= pos[i*3+2]; } vb.put(v).position(0); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3); } // draw the 2nd batch this time with transforms v[0] = -1; v[1] =-1; v[2] = -10; v[3] = 0; v[4] = 1; v[5] = -10; v[6] = 1; v[7] =-1; v[8] = -10; vb.put(v).position(0); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb); // draw lower left triangle gl.glPushMatrix(); gl.glTranslatef(pos[0], pos[1], pos[2]); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3); gl.glPopMatrix(); // draw lower middle triangle gl.glPushMatrix(); gl.glTranslatef(pos[3], pos[4], pos[5]); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3); gl.glPopMatrix(); // draw lower right triangle gl.glPushMatrix(); gl.glTranslatef(pos[6], pos[7], pos[8]); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3); gl.glPopMatrix(); } public int[] getConfigSpec() { int[] configSpec = { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE }; return configSpec; } } opengl/tests/linetex/0040755 0000000 0000000 00000000000 13077405420 013710 5ustar000000000 0000000 opengl/tests/linetex/Android.mk0100644 0000000 0000000 00000000616 13077405420 015621 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ linetex.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv1_CM \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-linetex LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/linetex/linetex.cpp0100644 0000000 0000000 00000006512 13077405420 016065 0ustar000000000 0000000 /* ** ** Copyright 2006, 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 #include #include #include #include #include #include #include #include using namespace android; int main(int argc, char** argv) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLSurface surface; EGLint w, h; EGLDisplay dpy; WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); return 0; } surface = eglCreateWindowSurface(dpy, config, window, NULL); context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); printf("w=%d, h=%d\n", w, h); glBindTexture(GL_TEXTURE_2D, 0); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glDisable(GL_DITHER); glDisable(GL_BLEND); glEnable(GL_TEXTURE_2D); glColor4f(1,1,1,1); // default pack-alignment is 4 const uint16_t t16[64] = { 0xFFFF, 0, 0xF800, 0, 0x07E0, 0, 0x001F, 0 }; const GLfloat fh = h; const GLfloat fw2 = w/2; const GLfloat vertices[4][2] = { { fw2, 0 }, { fw2, fh } }; const GLfloat texCoords[4][2] = { { 0, 0 }, { 1, 1 } }; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, w, 0, h, 0, 1); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_LINES, 0, 2); eglSwapBuffers(dpy, surface); usleep(5*1000000); eglTerminate(dpy); return 0; } opengl/tests/swapinterval/0040755 0000000 0000000 00000000000 13077405420 014757 5ustar000000000 0000000 opengl/tests/swapinterval/Android.mk0100644 0000000 0000000 00000000625 13077405420 016670 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ swapinterval.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libEGL \ libGLESv1_CM \ libui \ libgui LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-swapinterval LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) opengl/tests/swapinterval/swapinterval.cpp0100644 0000000 0000000 00000007027 13077405420 020205 0ustar000000000 0000000 /* ** ** Copyright 2006, 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 #include #include #include #include #include #include #include using namespace android; int main(int argc, char** argv) { EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLint numConfigs=0; EGLSurface surface; EGLint w, h; EGLDisplay dpy; WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); eglGetConfigs(dpy, NULL, 0, &numConfigs); printf("# configs = %d\n", numConfigs); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "error: %s", EGLUtils::strerror(eglGetError())); eglTerminate(dpy); return 0; } EGLint r,g,b,a, vid; eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r); eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g); eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b); eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a); eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid); surface = eglCreateWindowSurface(dpy, config, window, NULL); if (surface == EGL_NO_SURFACE) { EGLint err = eglGetError(); fprintf(stderr, "error: %s, config=%p, format = %d-%d-%d-%d, visual-id = %d\n", EGLUtils::strerror(err), config, r,g,b,a, vid); eglTerminate(dpy); return 0; } else { printf("config=%p, format = %d-%d-%d-%d, visual-id = %d\n", config, r,g,b,a, vid); } context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); printf("w=%d, h=%d\n", w, h); glDisable(GL_DITHER); glEnable(GL_BLEND); glViewport(0, 0, w, h); glOrthof(0, w, 0, h, 0, 1); eglSwapInterval(dpy, 1); glClearColor(1,0,0,0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(dpy, surface); int time = 10; printf("screen should flash red/green quickly for %d s...\n", time); int c = 0; nsecs_t start = systemTime(); nsecs_t t; do { glClearColor(1,0,0,0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(dpy, surface); glClearColor(0,1,0,0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(dpy, surface); t = systemTime() - start; c += 2; } while (int(ns2s(t))<=time); double p = (double(t) / c) / 1000000000.0; printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0); eglTerminate(dpy); return 0; } opengl/tests/testFramerate/0040755 0000000 0000000 00000000000 13077405420 015046 5ustar000000000 0000000 opengl/tests/testFramerate/Android.mk0100644 0000000 0000000 00000000661 13077405420 016757 0ustar000000000 0000000 ######################################################################### # Test framerate and look for hiccups ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TestFramerate include $(BUILD_PACKAGE) opengl/tests/testFramerate/AndroidManifest.xml0100644 0000000 0000000 00000002627 13077405420 020643 0ustar000000000 0000000 opengl/tests/testFramerate/res/0040755 0000000 0000000 00000000000 13077405420 015637 5ustar000000000 0000000 opengl/tests/testFramerate/res/values/0040755 0000000 0000000 00000000000 13077405420 017136 5ustar000000000 0000000 opengl/tests/testFramerate/res/values/strings.xml0100644 0000000 0000000 00000001643 13077405420 021352 0ustar000000000 0000000 TestFramerate opengl/tests/testFramerate/src/0040755 0000000 0000000 00000000000 13077405420 015635 5ustar000000000 0000000 opengl/tests/testFramerate/src/com/0040755 0000000 0000000 00000000000 13077405420 016413 5ustar000000000 0000000 opengl/tests/testFramerate/src/com/android/0040755 0000000 0000000 00000000000 13077405420 020033 5ustar000000000 0000000 opengl/tests/testFramerate/src/com/android/testframerate/0040755 0000000 0000000 00000000000 13077405420 022701 5ustar000000000 0000000 opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateActivity.java0100644 0000000 0000000 00000002434 13077405420 030027 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.testframerate; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; import java.io.File; public class TestFramerateActivity extends Activity { TestFramerateView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new TestFramerateView(getApplication()); setContentView(mView); mView.setFocusableInTouchMode(true); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/testFramerate/src/com/android/testframerate/TestFramerateView.java0100644 0000000 0000000 00000005724 13077405420 027152 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.testframerate; import android.content.Context; import android.opengl.GLSurfaceView; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLES20; class TestFramerateView extends GLSurfaceView { private static String TAG = "TestFramerateView"; public TestFramerateView(Context context) { super(context); setEGLContextClientVersion(2); setRenderer(new Renderer()); } private long mLastTime_us = 0; private long mNumShortFramesElapsed = 0; private void registerTime(long now_us) { long longFrameTime_ms = Integer.parseInt(SystemProperties.get("debug.longframe_ms", "16")); long elapsedTime_us = now_us - mLastTime_us; float fps = 1000000.f / elapsedTime_us; if (mLastTime_us > 0 && elapsedTime_us > longFrameTime_ms*1000) { Log.v(TAG, "Long frame: " + elapsedTime_us/1000.f + " ms (" + fps + " fps)"); if (mNumShortFramesElapsed > 0) { Log.v(TAG, " Short frames since last long frame: " + mNumShortFramesElapsed); mNumShortFramesElapsed = 0; } } else { ++mNumShortFramesElapsed; } mLastTime_us = now_us; } private class Renderer implements GLSurfaceView.Renderer { public Renderer() { } public void onDrawFrame(GL10 gl) { long now_us = System.nanoTime() / 1000; registerTime(now_us); float red = (now_us % 1000000) / 1000000.f; float green = (now_us % 2000000) / 2000000.f; float blue = (now_us % 3000000) / 3000000.f; GLES20.glClearColor(red, green, blue, 1.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); } public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { } } } opengl/tests/testLatency/0040755 0000000 0000000 00000000000 13077405420 014537 5ustar000000000 0000000 opengl/tests/testLatency/Android.mk0100644 0000000 0000000 00000000673 13077405420 016453 0ustar000000000 0000000 ######################################################################### # Test end-to-end latency. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SDK_VERSION := 8 LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TestLatency include $(BUILD_PACKAGE) opengl/tests/testLatency/AndroidManifest.xml0100644 0000000 0000000 00000002621 13077405420 020326 0ustar000000000 0000000 opengl/tests/testLatency/res/0040755 0000000 0000000 00000000000 13077405420 015330 5ustar000000000 0000000 opengl/tests/testLatency/res/values/0040755 0000000 0000000 00000000000 13077405420 016627 5ustar000000000 0000000 opengl/tests/testLatency/res/values/strings.xml0100644 0000000 0000000 00000001637 13077405420 021046 0ustar000000000 0000000 TestLatency opengl/tests/testLatency/src/0040755 0000000 0000000 00000000000 13077405420 015326 5ustar000000000 0000000 opengl/tests/testLatency/src/com/0040755 0000000 0000000 00000000000 13077405420 016104 5ustar000000000 0000000 opengl/tests/testLatency/src/com/android/0040755 0000000 0000000 00000000000 13077405420 017524 5ustar000000000 0000000 opengl/tests/testLatency/src/com/android/testlatency/0040755 0000000 0000000 00000000000 13077405420 022063 5ustar000000000 0000000 opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java0100644 0000000 0000000 00000002424 13077405420 026701 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.testlatency; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; import java.io.File; public class TestLatencyActivity extends Activity { TestLatencyView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new TestLatencyView(getApplication()); setContentView(mView); mView.setFocusableInTouchMode(true); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java0100644 0000000 0000000 00000023276 13077405420 026027 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.testlatency; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLES20; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class TestLatencyView extends GLSurfaceView { private static String TAG = "TestLatencyiew"; private float mX; private float mY; private float mDX; private float mDY; private long mT; private long mDT; public TestLatencyView(Context context) { super(context); setEGLContextClientVersion(2); setRenderer(new Renderer()); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: float x = event.getX(); float y = event.getY(); long t = event.getEventTime(); synchronized(this) { mDT = t - mT; mT = t; mDX = x - mX; mX = x; mDY = y - mY; mY = y; } break; default: break; } return true; } private class Renderer implements GLSurfaceView.Renderer { private float mScaleX, mScaleY, mOffsetX, mOffsetY; private final float MS_PER_FRAME = 1000 / 60; public Renderer() { mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); } public void onDrawFrame(GL10 gl) { GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.0f); GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUseProgram(mProgram); checkGlError("glUseProgram"); float x, y, dx, dy; long t, dt; synchronized(TestLatencyView.this) { x = mX; y = mY; dx = mDX; dy = mDY; dt = mDT; } if (dt > 0) { dx = dx * MS_PER_FRAME / dt; dy = dy * MS_PER_FRAME / dt; } GLES20.glEnableVertexAttribArray(mvPositionHandle); checkGlError("glEnableVertexAttribArray"); GLES20.glEnableVertexAttribArray(mvColorHandle); checkGlError("glEnableVertexAttribArray"); for(int step = 0; step < 8; step++) { float sx = (x + dx * step) * mScaleX + mOffsetX; float sy = (y + dy * step) * mScaleY + mOffsetY; int cbase = step * 4; for (int i = 0; i < mTriangleVerticesData.length; i += 6) { mTriangleVerticesData2[i] = sx + mTriangleVerticesData[i]; mTriangleVerticesData2[i+1] = -sy + mTriangleVerticesData[i+1]; mTriangleVerticesData2[i+2] = mColors[cbase]; mTriangleVerticesData2[i+3] = mColors[cbase+1]; mTriangleVerticesData2[i+4] = mColors[cbase+2]; mTriangleVerticesData2[i+5] = mColors[cbase+3]; } mTriangleVertices.position(0); mTriangleVertices.put(mTriangleVerticesData2).position(0); GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices); checkGlError("glVertexAttribPointer mvPosition"); mTriangleVertices.put(mTriangleVerticesData2).position(2); GLES20.glVertexAttribPointer(mvColorHandle, 4, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices); checkGlError("glVertexAttribPointer mvColor"); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); checkGlError("glDrawArrays"); } } public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); mScaleX = 2.0f / width; mScaleY = 2.0f / height; mOffsetX = -1f; mOffsetY = -1f; } public void onSurfaceCreated(GL10 gl, EGLConfig config) { mProgram = createProgram(mVertexShader, mFragmentShader); if (mProgram == 0) { return; } mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); checkGlError("glGetAttribLocation"); if (mvPositionHandle == -1) { throw new RuntimeException("Could not get attrib location for vPosition"); } mvColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor"); checkGlError("glGetAttribLocation"); if (mvColorHandle == -1) { throw new RuntimeException("Could not get attrib location for vColor"); } } private int loadShader(int shaderType, String source) { int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compiled = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e(TAG, "Could not compile shader " + shaderType + ":"); Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } private int createProgram(String vertexSource, String fragmentSource) { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } int program = GLES20.glCreateProgram(); if (program != 0) { GLES20.glAttachShader(program, vertexShader); checkGlError("glAttachShader vertexShader"); GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader pixelShader"); GLES20.glLinkProgram(program); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES20.GL_TRUE) { Log.e(TAG, "Could not link program: "); Log.e(TAG, GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; } private void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e(TAG, op + ": glError " + error); throw new RuntimeException(op + ": glError " + error); } } // X, Y, R G B A private final float[] mTriangleVerticesData = { -0.025f, 0.3f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f , 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.025f, 0.3f, 1.0f, 1.0f, 255.0f, 1.0f }; // Color cascade: private final float[] mColors = { 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; private float[] mTriangleVerticesData2 = new float[mTriangleVerticesData.length]; private FloatBuffer mTriangleVertices; private final String mVertexShader = "attribute vec4 aPosition;\n" + "attribute vec4 aColor;\n" + "varying vec4 vColor;\n" + "void main() {\n" + " gl_Position = aPosition;\n" + " vColor = aColor;\n" + "}\n"; private final String mFragmentShader = "precision mediump float;\n" + "varying vec4 vColor;\n" + "void main() {\n" + " gl_FragColor = vColor;\n" + "}\n"; private int mProgram; private int mvPositionHandle; private int mvColorHandle; } } opengl/tests/testPauseResume/0040755 0000000 0000000 00000000000 13077405420 015376 5ustar000000000 0000000 opengl/tests/testPauseResume/Android.mk0100644 0000000 0000000 00000000730 13077405420 017304 0ustar000000000 0000000 ######################################################################### # OpenGL ES JNI sample # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TestEGL include $(BUILD_PACKAGE) opengl/tests/testPauseResume/AndroidManifest.xml0100644 0000000 0000000 00000002764 13077405420 021175 0ustar000000000 0000000 opengl/tests/testPauseResume/README0100644 0000000 0000000 00000003000 13077405420 016244 0ustar000000000 0000000 Repro steps: build, install and run the attached test program TestEgl.apk The program does not draw anything to the screen, it just prints to the log, so use adb logcat to watch the output. Expected behavior: constantly increasing "step" count: W/TestActivity( 1885): ****** step 235 resume W/TestActivity( 1885): step 236 pause W/TestActivity( 1885): ****** step 236 resume and so on. Actual behavior: W/TestActivity( 1466): ****** step 25 resume W/TestActivity( 1466): step 26 pause W/TestActivity( 1466): ****** step 26 resume W/dalvikvm( 1466): threadid=8: thread exiting with uncaught exception (group=0x4001d7f0) E/AndroidRuntime( 1466): FATAL EXCEPTION: GLThread 9 E/AndroidRuntime( 1466): java.lang.RuntimeException: createContext failed: EGL_BAD_ALLOC E/AndroidRuntime( 1466): at android.opengl.GLSurfaceView$EglHelper.throwEglException(GLSurfaceView.java:1067) E/AndroidRuntime( 1466): at android.opengl.GLSurfaceView$EglHelper.throwEglException(GLSurfaceView.java:1059) E/AndroidRuntime( 1466): at android.opengl.GLSurfaceView$EglHelper.start(GLSurfaceView.java:925) E/AndroidRuntime( 1466): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1236) E/AndroidRuntime( 1466): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1106) W/TestActivity( 1466): step 27 pause W/TestActivity( 1466): ****** step 27 resume W/TestActivity( 1466): step 28 pause W/TestActivity( 1466): ****** step 28 resume See http://b/issue?id=2550745 for further details. opengl/tests/testPauseResume/res/0040755 0000000 0000000 00000000000 13077405420 016167 5ustar000000000 0000000 opengl/tests/testPauseResume/res/values/0040755 0000000 0000000 00000000000 13077405420 017466 5ustar000000000 0000000 opengl/tests/testPauseResume/res/values/strings.xml0100644 0000000 0000000 00000001625 13077405420 021702 0ustar000000000 0000000 Test Egl opengl/tests/testPauseResume/src/0040755 0000000 0000000 00000000000 13077405420 016165 5ustar000000000 0000000 opengl/tests/testPauseResume/src/com/0040755 0000000 0000000 00000000000 13077405420 016743 5ustar000000000 0000000 opengl/tests/testPauseResume/src/com/android/0040755 0000000 0000000 00000000000 13077405420 020363 5ustar000000000 0000000 opengl/tests/testPauseResume/src/com/android/test/0040755 0000000 0000000 00000000000 13077405420 021342 5ustar000000000 0000000 opengl/tests/testPauseResume/src/com/android/test/TestActivity.java0100644 0000000 0000000 00000003425 13077405420 024642 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.test; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class TestActivity extends Activity { private final static String TAG = "TestActivity"; TestView mView; boolean mToggle; int mCount; final static int PAUSE_DELAY = 100; Runnable mRunnable = new Runnable() { public void run() { if (mToggle) { Log.w(TAG, "****** step " + mCount + " resume"); mCount++; mView.onResume(); } else { Log.w(TAG, "step " + mCount + " pause"); mView.onPause(); } mToggle = ! mToggle; mView.postDelayed(mRunnable, PAUSE_DELAY); } }; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new TestView(getApplication()); mView.setFocusableInTouchMode(true); setContentView(mView); mView.postDelayed(mRunnable, PAUSE_DELAY); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/testPauseResume/src/com/android/test/TestView.java0100644 0000000 0000000 00000005165 13077405420 023763 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.test; /* * Copyright (C) 2008 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. */ import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class TestView extends GLSurfaceView { TestView(Context context) { super(context); init(); } public TestView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setRenderer(new Renderer()); } private class Renderer implements GLSurfaceView.Renderer { private static final String TAG = "Renderer"; public void onDrawFrame(GL10 gl) { // Do nothing. } public void onSurfaceChanged(GL10 gl, int width, int height) { // Do nothing. } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } } } opengl/tests/testViewport/0040755 0000000 0000000 00000000000 13077405420 014757 5ustar000000000 0000000 opengl/tests/testViewport/Android.mk0100644 0000000 0000000 00000001053 13077405420 016664 0ustar000000000 0000000 ######################################################################### # OpenGL ES JNI sample # This makefile builds both an activity and a shared library. ######################################################################### TOP_LOCAL_PATH:= $(call my-dir) # Build activity LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TestViewport # Set a specific SDK version so we can run on Froyo. LOCAL_SDK_VERSION := 8 include $(BUILD_PACKAGE) opengl/tests/testViewport/AndroidManifest.xml0100644 0000000 0000000 00000002734 13077405420 020553 0ustar000000000 0000000 opengl/tests/testViewport/README0100644 0000000 0000000 00000001406 13077405420 015635 0ustar000000000 0000000 Repro steps: build, install and run the attached test program TestViewport.apk Run on Sapphire with Froyo. The program clears the screen to blue, then draws a full screen white quad that is alligned to the screen. (Therefore the whole screen should appear to be white.) Note that screen is all white. Rotate screen 90 degrees. Expected: screen is still all white. Actual: screen is blue with offset white rectangle. This bug only happens on Sapphire, it works correctly on Passion. What happens: I think the bug is that the gl.glViewport() call in onSurfaceChanged() is being ignored by the OpenGL driver. NOTE: If a gl.glViewport call is added at the beginning of the onDrawFrame() call (which means it is called before every draw), the program runs correctly. opengl/tests/testViewport/res/0040755 0000000 0000000 00000000000 13077405420 015550 5ustar000000000 0000000 opengl/tests/testViewport/res/values/0040755 0000000 0000000 00000000000 13077405420 017047 5ustar000000000 0000000 opengl/tests/testViewport/res/values/strings.xml0100644 0000000 0000000 00000001632 13077405420 021261 0ustar000000000 0000000 Test Viewport opengl/tests/testViewport/src/0040755 0000000 0000000 00000000000 13077405420 015546 5ustar000000000 0000000 opengl/tests/testViewport/src/com/0040755 0000000 0000000 00000000000 13077405420 016324 5ustar000000000 0000000 opengl/tests/testViewport/src/com/android/0040755 0000000 0000000 00000000000 13077405420 017744 5ustar000000000 0000000 opengl/tests/testViewport/src/com/android/test/0040755 0000000 0000000 00000000000 13077405420 020723 5ustar000000000 0000000 opengl/tests/testViewport/src/com/android/test/TestActivity.java0100644 0000000 0000000 00000002371 13077405420 024222 0ustar000000000 0000000 /* * Copyright (C) 2007 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 com.android.test; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class TestActivity extends Activity { private final static String TAG = "TestActivity"; TestView mView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mView = new TestView(getApplication()); mView.setFocusableInTouchMode(true); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } } opengl/tests/testViewport/src/com/android/test/TestView.java0100644 0000000 0000000 00000020744 13077405420 023344 0ustar000000000 0000000 /* * Copyright (C) 2009 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 com.android.test; /* * Copyright (C) 2008 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. */ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.FloatBuffer; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; /** * An implementation of SurfaceView that uses the dedicated surface for * displaying an OpenGL animation. This allows the animation to run in a * separate thread, without requiring that it be driven by the update mechanism * of the view hierarchy. * * The application-specific rendering code is delegated to a GLView.Renderer * instance. */ class TestView extends GLSurfaceView { TestView(Context context) { super(context); init(); } public TestView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setRenderer(new Renderer()); setRenderMode(RENDERMODE_WHEN_DIRTY); } /** A grid is a topologically rectangular array of vertices. * * The vertex and index data are held in VBO objects because on most * GPUs VBO objects are the fastest way of rendering static vertex * and index data. * */ private static class Grid { // Size of vertex data elements in bytes: final static int FLOAT_SIZE = 4; final static int CHAR_SIZE = 2; // Vertex structure: // float x, y, z; final static int VERTEX_SIZE = 3 * FLOAT_SIZE; private int mVertexBufferObjectId; private int mElementBufferObjectId; // These buffers are used to hold the vertex and index data while // constructing the grid. Once createBufferObjects() is called // the buffers are nulled out to save memory. private ByteBuffer mVertexByteBuffer; private FloatBuffer mVertexBuffer; private CharBuffer mIndexBuffer; private int mW; private int mH; private int mIndexCount; public Grid(int w, int h) { if (w < 0 || w >= 65536) { throw new IllegalArgumentException("w"); } if (h < 0 || h >= 65536) { throw new IllegalArgumentException("h"); } if (w * h >= 65536) { throw new IllegalArgumentException("w * h >= 65536"); } mW = w; mH = h; int size = w * h; mVertexByteBuffer = ByteBuffer.allocateDirect(VERTEX_SIZE * size) .order(ByteOrder.nativeOrder()); mVertexBuffer = mVertexByteBuffer.asFloatBuffer(); int quadW = mW - 1; int quadH = mH - 1; int quadCount = quadW * quadH; int indexCount = quadCount * 6; mIndexCount = indexCount; mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount) .order(ByteOrder.nativeOrder()).asCharBuffer(); /* * Initialize triangle list mesh. * * [0]-----[ 1] ... * | / | * | / | * | / | * [w]-----[w+1] ... * | | * */ { int i = 0; for (int y = 0; y < quadH; y++) { for (int x = 0; x < quadW; x++) { char a = (char) (y * mW + x); char b = (char) (y * mW + x + 1); char c = (char) ((y + 1) * mW + x); char d = (char) ((y + 1) * mW + x + 1); mIndexBuffer.put(i++, a); mIndexBuffer.put(i++, c); mIndexBuffer.put(i++, b); mIndexBuffer.put(i++, b); mIndexBuffer.put(i++, c); mIndexBuffer.put(i++, d); } } } } public void set(int i, int j, float x, float y, float z) { if (i < 0 || i >= mW) { throw new IllegalArgumentException("i"); } if (j < 0 || j >= mH) { throw new IllegalArgumentException("j"); } int index = mW * j + i; mVertexBuffer.position(index * VERTEX_SIZE / FLOAT_SIZE); mVertexBuffer.put(x); mVertexBuffer.put(y); mVertexBuffer.put(z); } public void createBufferObjects(GL gl) { // Generate a the vertex and element buffer IDs int[] vboIds = new int[2]; GL11 gl11 = (GL11) gl; gl11.glGenBuffers(2, vboIds, 0); mVertexBufferObjectId = vboIds[0]; mElementBufferObjectId = vboIds[1]; // Upload the vertex data gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId); mVertexByteBuffer.position(0); gl11.glBufferData(GL11.GL_ARRAY_BUFFER, mVertexByteBuffer.capacity(), mVertexByteBuffer, GL11.GL_STATIC_DRAW); gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId); mIndexBuffer.position(0); gl11.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.capacity() * CHAR_SIZE, mIndexBuffer, GL11.GL_STATIC_DRAW); // We don't need the in-memory data any more mVertexBuffer = null; mVertexByteBuffer = null; mIndexBuffer = null; } public void draw(GL10 gl) { GL11 gl11 = (GL11) gl; gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertexBufferObjectId); gl11.glVertexPointer(3, GL10.GL_FLOAT, VERTEX_SIZE, 0); gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mElementBufferObjectId); gl11.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, 0); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0); gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0); } } private class Renderer implements GLSurfaceView.Renderer { private static final String TAG = "Renderer"; private Grid mGrid; public void onDrawFrame(GL10 gl) { gl.glClearColor(0,0,1,1); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); mGrid.draw(gl); } public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL11.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrthof(0, width, height, 0, -1, 1); gl.glMatrixMode(GL11.GL_MODELVIEW); createGrid(gl, width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { } private void createGrid(GL10 gl, float w, float h) { mGrid = new Grid(2, 2); for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { float x = w * i; float y = h * j; float z = 0.0f; mGrid.set(i,j, x, y, z); } } mGrid.createBufferObjects(gl); } } } opengl/tests/textures/0040755 0000000 0000000 00000000000 13077405420 014123 5ustar000000000 0000000 opengl/tests/textures/Android.mk0100644 0000000 0000000 00000000667 13077405420 016042 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ textures.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libEGL \ libGLESv1_CM \ libui \ libgui \ libutils LOCAL_STATIC_LIBRARIES += libglTest LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes) LOCAL_MODULE:= test-opengl-textures LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES include $(BUILD_EXECUTABLE) opengl/tests/textures/textures.cpp0100644 0000000 0000000 00000007717 13077405420 016523 0ustar000000000 0000000 /* ** ** Copyright 2006, 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 #include #include #include #include #include #include using namespace android; int main(int argc, char** argv) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 0, EGL_NONE }; EGLint majorVersion; EGLint minorVersion; EGLContext context; EGLConfig config; EGLSurface surface; EGLint w, h; EGLDisplay dpy; WindowSurface windowSurface; EGLNativeWindowType window = windowSurface.getSurface(); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, &majorVersion, &minorVersion); status_t err = EGLUtils::selectConfigForNativeWindow( dpy, configAttribs, window, &config); if (err) { fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); return 0; } surface = eglCreateWindowSurface(dpy, config, window, NULL); context = eglCreateContext(dpy, config, NULL, NULL); eglMakeCurrent(dpy, surface, surface, context); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); GLint dim = w #include #include #include #include #include #include #include using namespace android; EGLDisplay eglDisplay; EGLSurface eglSurface; EGLContext eglContext; GLuint texture; #define FIXED_ONE 0x10000 #define ITERATIONS 50 int init_gl_surface(const WindowSurface&); void free_gl_surface(void); void init_scene(void); void render(int quads); void create_texture(void); int readTimer(void); static void gluLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { // See the OpenGL GLUT documentation for gluLookAt for a description // of the algorithm. We implement it in a straightforward way: float fx = centerX - eyeX; float fy = centerY - eyeY; float fz = centerZ - eyeZ; // Normalize f float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz); fx *= rlf; fy *= rlf; fz *= rlf; // Normalize up float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ); upX *= rlup; upY *= rlup; upZ *= rlup; // compute s = f x up (x means "cross product") float sx = fy * upZ - fz * upY; float sy = fz * upX - fx * upZ; float sz = fx * upY - fy * upX; // compute u = s x f float ux = sy * fz - sz * fy; float uy = sz * fx - sx * fz; float uz = sx * fy - sy * fx; float m[16] ; m[0] = sx; m[1] = ux; m[2] = -fx; m[3] = 0.0f; m[4] = sy; m[5] = uy; m[6] = -fy; m[7] = 0.0f; m[8] = sz; m[9] = uz; m[10] = -fz; m[11] = 0.0f; m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f; glMultMatrixf(m); glTranslatef(-eyeX, -eyeY, -eyeZ); } int main(int argc, char **argv) { int q; int start, end; printf("Initializing EGL...\n"); WindowSurface windowSurface; if(!init_gl_surface(windowSurface)) { printf("GL initialisation failed - exiting\n"); return 0; } init_scene(); create_texture(); printf("Start test...\n"); render(argc==2 ? atoi(argv[1]) : ITERATIONS); free_gl_surface(); return 0; } int init_gl_surface(const WindowSurface& windowSurface) { EGLint numConfigs = 1; EGLConfig myConfig = {0}; EGLint attrib[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_DEPTH_SIZE, 16, EGL_NONE }; if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY ) { printf("eglGetDisplay failed\n"); return 0; } if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE ) { printf("eglInitialize failed\n"); return 0; } EGLNativeWindowType window = windowSurface.getSurface(); EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig); if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig, window, 0)) == EGL_NO_SURFACE ) { printf("eglCreateWindowSurface failed\n"); return 0; } if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT ) { printf("eglCreateContext failed\n"); return 0; } if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE ) { printf("eglMakeCurrent failed\n"); return 0; } return 1; } void free_gl_surface(void) { if (eglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); eglDestroyContext( eglDisplay, eglContext ); eglDestroySurface( eglDisplay, eglSurface ); eglTerminate( eglDisplay ); eglDisplay = EGL_NO_DISPLAY; } } void init_scene(void) { glDisable(GL_DITHER); glEnable(GL_CULL_FACE); float ratio = 320.0f / 480.0f; glViewport(0, 0, 320, 480); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustumf(-ratio, ratio, -1, 1, 1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( 0, 0, 3, // eye 0, 0, 0, // center 0, 1, 0); // up glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } void create_texture(void) { const unsigned int on = 0xff0000ff; const unsigned int off = 0xffffffff; const unsigned int pixels[] = { on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, on, off, on, off, on, off, on, off, off, on, off, on, off, on, off, on, }; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } void render(int quads) { int i, j; const GLfloat vertices[] = { -1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0 }; const GLfixed texCoords[] = { 0, 0, FIXED_ONE, 0, FIXED_ONE, FIXED_ONE, 0, FIXED_ONE }; const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 }; GLushort* indices = (GLushort*)malloc(quads*sizeof(quadIndices)); for (i=0 ; i out/android/graphics/Canvas.java echo "public interface Canvas {}" >> out/android/graphics/Canvas.java echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;}; }" > out/android/os/Build.java echo "package android.os; public class UserHandle {public static String myUserId() { return \"\"; } }" > out/android/os/UserHandle.java echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java echo "package android.view;" > out/android/view/SurfaceView.java echo "public interface SurfaceView { SurfaceHolder getHolder(); }" >> out/android/view/SurfaceView.java echo "package android.view;" > out/android/view/Surface.java echo "public interface Surface {}" >> out/android/view/Surface.java echo "package android.view;" > out/android/view/SurfaceHolder.java echo "public interface SurfaceHolder { Surface getSurface(); }" >> out/android/view/SurfaceHolder.java cp static/egl/*.java out/android/opengl/ GLFILE=out/javax/microedition/khronos/opengles/GL.java cp stubs/jsr239/GLHeader.java-if $GLFILE GLGEN_FILES="CFunc.java CType.java CodeEmitter.java EGLCodeEmitter.java GenerateEGL.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java" pushd src > /dev/null javac ${GLGEN_FILES} JAVAC_RESULT=$? if [ $JAVAC_RESULT -ne 0 ]; then echo "Could not compile glgen." exit $JAVAC_RESULT fi popd > /dev/null echo "Generating JSR239-like APIs" java -classpath src GenerateGL -c specs/jsr239/glspec-1.0 \ specs/jsr239/glspec-1.0ext \ specs/jsr239/glspec-1.1 \ specs/jsr239/glspec-1.1ext \ specs/jsr239/glspec-1.1extpack \ specs/jsr239/glspec-checks JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then echo "Could not run GenerateGL." exit $JAVA_RESULT fi echo "Generating static OpenGLES bindings" java -classpath src GenerateGLES JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then echo "Could not run GenerateGLES." exit $JAVA_RESULT fi echo "Generating static EGL bindings" java -classpath src GenerateEGL JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then echo "Could not run GenerateEGL." exit $JAVA_RESULT fi rm src/*.class pushd out > /dev/null mkdir classes javac -d classes android/opengl/EGL14.java \ android/opengl/EGLExt.java \ com/google/android/gles_jni/GLImpl.java \ javax/microedition/khronos/opengles/GL10.java \ javax/microedition/khronos/opengles/GL10Ext.java \ javax/microedition/khronos/opengles/GL11.java \ javax/microedition/khronos/opengles/GL11Ext.java \ javax/microedition/khronos/opengles/GL11ExtensionPack.java \ android/opengl/GLES10.java \ android/opengl/GLES10Ext.java \ android/opengl/GLES11.java \ android/opengl/GLES11Ext.java \ android/opengl/GLES20.java \ android/opengl/GLES30.java \ android/opengl/GLES31.java \ android/opengl/GLES31Ext.java \ android/opengl/GLES32.java popd > /dev/null JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then echo "Could not compile generated classes." exit $JAVA_RESULT fi rm -rf generated mkdir -p generated/C cp out/com_google_android_gles_jni_GLImpl.cpp generated/C cp -r out/com generated cp -r out/javax generated cp out/android_opengl_*.cpp generated/C mkdir -p generated/android/opengl cp -r out/android/opengl generated/android rm -rf out KEEP_GENERATED=0 SAID_PLEASE=0 # compareGenerated destDir generatedDir file compareGenerated() { if cmp -s $1/$3 $2/$3 ; then echo "# " $3 unchanged else echo "# " $3 changed if [ $SAID_PLEASE == "0" ] ; then echo Please evaluate the following commands: echo SAID_PLEASE=1 fi echo " cp $2/$3 $1" echo " (cd $1; git add $3)" KEEP_GENERATED=1 fi } compareGenerated ../../../../base/core/jni generated/C com_google_android_gles_jni_GLImpl.cpp compareGenerated ../../../../base/opengl/java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java for x in GL.java GL10.java GL10Ext.java GL11.java GL11Ext.java GL11ExtensionPack.java do compareGenerated ../../../../base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x done for x in EGL14 EGLExt GLES10 GLES10Ext GLES11 GLES11Ext GLES20 GLES30 GLES31 GLES31Ext GLES32 do compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp done for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface do compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java done if [ $KEEP_GENERATED == "0" ] ; then rm -rf generated fi opengl/tools/glgen/specs/0040755 0000000 0000000 00000000000 13077405420 014447 5ustar000000000 0000000 opengl/tools/glgen/specs/egl/0040755 0000000 0000000 00000000000 13077405420 015216 5ustar000000000 0000000 opengl/tools/glgen/specs/egl/EGL14.spec0100644 0000000 0000000 00000004645 13077405420 016654 0ustar000000000 0000000 EGLint eglGetError ( void ) EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) EGLBoolean eglInitialize ( EGLDisplay dpy, EGLint *major, EGLint *minor ) EGLBoolean eglTerminate ( EGLDisplay dpy ) const char * eglQueryString ( EGLDisplay dpy, EGLint name ) EGLBoolean eglGetConfigs ( EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config ) EGLBoolean eglChooseConfig ( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config ) EGLBoolean eglGetConfigAttrib ( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value ) EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) EGLSurface eglCreatePbufferSurface ( EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list ) EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list ) EGLBoolean eglDestroySurface ( EGLDisplay dpy, EGLSurface surface ) EGLBoolean eglQuerySurface ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value ) EGLBoolean eglBindAPI ( EGLenum api ) EGLenum eglQueryAPI ( void ) EGLBoolean eglWaitClient ( void ) EGLBoolean eglReleaseThread ( void ) EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) EGLBoolean eglSurfaceAttrib ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value ) EGLBoolean eglBindTexImage ( EGLDisplay dpy, EGLSurface surface, EGLint buffer ) EGLBoolean eglReleaseTexImage ( EGLDisplay dpy, EGLSurface surface, EGLint buffer ) EGLBoolean eglSwapInterval ( EGLDisplay dpy, EGLint interval ) EGLContext eglCreateContext ( EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list ) EGLBoolean eglDestroyContext ( EGLDisplay dpy, EGLContext ctx ) EGLBoolean eglMakeCurrent ( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx ) EGLContext eglGetCurrentContext ( void ) EGLSurface eglGetCurrentSurface ( EGLint readdraw ) EGLDisplay eglGetCurrentDisplay ( void ) EGLBoolean eglQueryContext ( EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value ) EGLBoolean eglWaitGL ( void ) EGLBoolean eglWaitNative ( EGLint engine ) EGLBoolean eglSwapBuffers ( EGLDisplay dpy, EGLSurface surface ) EGLBoolean eglCopyBuffers ( EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target ) opengl/tools/glgen/specs/egl/EGLExt.spec0100644 0000000 0000000 00000000137 13077405420 017160 0ustar000000000 0000000 EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time ) opengl/tools/glgen/specs/egl/checks.spec0100644 0000000 0000000 00000001465 13077405420 017335 0ustar000000000 0000000 eglInitialize nullAllowed major nullAllowed minor check major 1 check minor 1 eglGetConfigs nullAllowed configs check configs config_size eglChooseConfig nullAllowed configs check configs config_size check num_config 1 sentinel attrib_list EGL_NONE eglGetConfigAttrib check value 1 //STUB function: //eglCreateWindowSurface nullAllowed attrib_list sentinel attrib_list EGL_NONE eglCreatePbufferSurface nullAllowed attrib_list sentinel attrib_list EGL_NONE //unsupported: eglCreatePixmapSurface nullAllowed attrib_list sentinel attrib_list EGL_NONE eglCreatePixmapSurface unsupported eglCopyBuffers unsupported eglQuerySurface check value 1 //STUB function: eglCreatePbufferFromClientBuffer nullAllowed attrib_list sentinel attrib_list EGL_NONE eglCreateContext sentinel attrib_list EGL_NONE eglQueryContext check value 1 opengl/tools/glgen/specs/gles11/0040755 0000000 0000000 00000000000 13077405420 015543 5ustar000000000 0000000 opengl/tools/glgen/specs/gles11/GLES10.spec0100644 0000000 0000000 00000014564 13077405420 017321 0ustar000000000 0000000 void glActiveTexture ( GLenum texture ) void glAlphaFunc ( GLenum func, GLclampf ref ) void glAlphaFuncx ( GLenum func, GLclampx ref ) void glBindTexture ( GLenum target, GLuint texture ) void glBlendFunc ( GLenum sfactor, GLenum dfactor ) void glClear ( GLbitfield mask ) void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) void glClearDepthf ( GLclampf depth ) void glClearDepthx ( GLclampx depth ) void glClearStencil ( GLint s ) void glClientActiveTexture ( GLenum texture ) void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) void glCullFace ( GLenum mode ) void glDeleteTextures ( GLsizei n, const GLuint *textures ) void glDepthFunc ( GLenum func ) void glDepthMask ( GLboolean flag ) void glDepthRangef ( GLclampf zNear, GLclampf zFar ) void glDepthRangex ( GLclampx zNear, GLclampx zFar ) void glDisable ( GLenum cap ) void glDisableClientState ( GLenum array ) void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) void glEnable ( GLenum cap ) void glEnableClientState ( GLenum array ) void glFinish ( void ) void glFlush ( void ) void glFogf ( GLenum pname, GLfloat param ) void glFogfv ( GLenum pname, const GLfloat *params ) void glFogx ( GLenum pname, GLfixed param ) void glFogxv ( GLenum pname, const GLfixed *params ) void glFrontFace ( GLenum mode ) void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glGenTextures ( GLsizei n, GLuint *textures ) GLenum glGetError ( void ) void glGetIntegerv ( GLenum pname, GLint *params ) const GLubyte * glGetString ( GLenum name ) void glHint ( GLenum target, GLenum mode ) void glLightModelf ( GLenum pname, GLfloat param ) void glLightModelfv ( GLenum pname, const GLfloat *params ) void glLightModelx ( GLenum pname, GLfixed param ) void glLightModelxv ( GLenum pname, const GLfixed *params ) void glLightf ( GLenum light, GLenum pname, GLfloat param ) void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) void glLightx ( GLenum light, GLenum pname, GLfixed param ) void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) void glLineWidth ( GLfloat width ) void glLineWidthx ( GLfixed width ) void glLoadIdentity ( void ) void glLoadMatrixf ( const GLfloat *m ) void glLoadMatrixx ( const GLfixed *m ) void glLogicOp ( GLenum opcode ) void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) void glMatrixMode ( GLenum mode ) void glMultMatrixf ( const GLfloat *m ) void glMultMatrixx ( const GLfixed *m ) void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glPixelStorei ( GLenum pname, GLint param ) void glPointSize ( GLfloat size ) void glPointSizex ( GLfixed size ) void glPolygonOffset ( GLfloat factor, GLfloat units ) void glPolygonOffsetx ( GLfixed factor, GLfixed units ) void glPopMatrix ( void ) void glPushMatrix ( void ) void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) void glSampleCoverage ( GLclampf value, GLboolean invert ) void glSampleCoveragex ( GLclampx value, GLboolean invert ) void glScalef ( GLfloat x, GLfloat y, GLfloat z ) void glScalex ( GLfixed x, GLfixed y, GLfixed z ) void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) void glShadeModel ( GLenum mode ) void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) void glStencilMask ( GLuint mask ) void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) opengl/tools/glgen/specs/gles11/GLES10Ext.spec0100644 0000000 0000000 00000000104 13077405420 017763 0ustar000000000 0000000 GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) opengl/tools/glgen/specs/gles11/GLES11.spec0100644 0000000 0000000 00000005441 13077405420 017314 0ustar000000000 0000000 void glBindBuffer ( GLenum target, GLuint buffer ) void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) void glClipPlanef ( GLenum plane, const GLfloat *equation ) void glClipPlanex ( GLenum plane, const GLfixed *equation ) void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) void glGenBuffers ( GLsizei n, GLuint *buffers ) void glGetBooleanv ( GLenum pname, GLboolean *params ) void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) void glGetFixedv ( GLenum pname, GLfixed *params ) void glGetFloatv ( GLenum pname, GLfloat *params ) void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) // void glGetPointerv ( GLenum pname, void **params ) void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *params ) void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) GLboolean glIsBuffer ( GLuint buffer ) GLboolean glIsEnabled ( GLenum cap ) GLboolean glIsTexture ( GLuint texture ) void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) void glPointParameterf ( GLenum pname, GLfloat param ) void glPointParameterfv ( GLenum pname, const GLfloat *params ) void glPointParameterx ( GLenum pname, GLfixed param ) void glPointParameterxv ( GLenum pname, const GLfixed *params ) void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) void glTexEnvi ( GLenum target, GLenum pname, GLint param ) void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) void glTexParameteri ( GLenum target, GLenum pname, GLint param ) void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) opengl/tools/glgen/specs/gles11/GLES11Ext.spec0100644 0000000 0000000 00000013664 13077405420 020003 0ustar000000000 0000000 void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) void glBlendFuncSeparateOES ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) void glBlendEquationOES ( GLenum mode ) void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) void glDrawTexsvOES ( const GLshort *coords ) void glDrawTexivOES ( const GLint *coords ) void glDrawTexxvOES ( const GLfixed *coords ) void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) void glDrawTexfvOES ( const GLfloat *coords ) void glEGLImageTargetTexture2DOES ( GLenum target, GLeglImageOES image ) void glEGLImageTargetRenderbufferStorageOES ( GLenum target, GLeglImageOES image ) void glAlphaFuncxOES ( GLenum func, GLclampx ref ) void glClearColorxOES ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) void glClearDepthxOES ( GLclampx depth ) void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) void glColor4xOES ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) void glDepthRangexOES ( GLclampx zNear, GLclampx zFar ) void glFogxOES ( GLenum pname, GLfixed param ) void glFogxvOES ( GLenum pname, const GLfixed *params ) void glFrustumxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) void glGetFixedvOES ( GLenum pname, GLfixed *params ) void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) void glLightModelxOES ( GLenum pname, GLfixed param ) void glLightModelxvOES ( GLenum pname, const GLfixed *params ) void glLightxOES ( GLenum light, GLenum pname, GLfixed param ) void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) void glLineWidthxOES ( GLfixed width ) void glLoadMatrixxOES ( const GLfixed *m ) void glMaterialxOES ( GLenum face, GLenum pname, GLfixed param ) void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) void glMultMatrixxOES ( const GLfixed *m ) void glMultiTexCoord4xOES ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) void glNormal3xOES ( GLfixed nx, GLfixed ny, GLfixed nz ) void glOrthoxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glPointParameterxOES ( GLenum pname, GLfixed param ) void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) void glPointSizexOES ( GLfixed size ) void glPolygonOffsetxOES ( GLfixed factor, GLfixed units ) void glRotatexOES ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) void glSampleCoveragexOES ( GLclampx value, GLboolean invert ) void glScalexOES ( GLfixed x, GLfixed y, GLfixed z ) void glTexEnvxOES ( GLenum target, GLenum pname, GLfixed param ) void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) void glTexParameterxOES ( GLenum target, GLenum pname, GLfixed param ) void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) void glTranslatexOES ( GLfixed x, GLfixed y, GLfixed z ) GLboolean glIsRenderbufferOES ( GLuint renderbuffer ) void glBindRenderbufferOES ( GLenum target, GLuint renderbuffer ) void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) void glRenderbufferStorageOES ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) GLboolean glIsFramebufferOES ( GLuint framebuffer ) void glBindFramebufferOES ( GLenum target, GLuint framebuffer ) void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) GLenum glCheckFramebufferStatusOES ( GLenum target ) void glFramebufferRenderbufferOES ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) void glFramebufferTexture2DOES ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) void glGenerateMipmapOES ( GLenum target ) // Hard to export to Java: // void *glMapBufferOES ( GLenum target, GLenum access ) // GLboolean glUnmapBufferOES ( GLenum target ) // void glGetBufferPointervOES ( GLenum target, GLenum pname, void **params ) void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) void glLoadPaletteFromModelViewMatrixOES ( void ) void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glDepthRangefOES ( GLclampf zNear, GLclampf zFar ) void glFrustumfOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glOrthofOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) void glClearDepthfOES ( GLclampf depth ) void glTexGenfOES ( GLenum coord, GLenum pname, GLfloat param ) void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) void glTexGeniOES ( GLenum coord, GLenum pname, GLint param ) void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) void glTexGenxOES ( GLenum coord, GLenum pname, GLfixed param ) void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) opengl/tools/glgen/specs/gles11/GLES20.spec0100644 0000000 0000000 00000023001 13077405420 017304 0ustar000000000 0000000 void glActiveTexture ( GLenum texture ) void glAttachShader ( GLuint program, GLuint shader ) void glBindAttribLocation ( GLuint program, GLuint index, const char *name ) void glBindBuffer ( GLenum target, GLuint buffer ) void glBindFramebuffer ( GLenum target, GLuint framebuffer ) void glBindRenderbuffer ( GLenum target, GLuint renderbuffer ) void glBindTexture ( GLenum target, GLuint texture ) void glBlendColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) void glBlendEquation ( GLenum mode ) void glBlendEquationSeparate ( GLenum modeRGB, GLenum modeAlpha ) void glBlendFunc ( GLenum sfactor, GLenum dfactor ) void glBlendFuncSeparate ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) GLenum glCheckFramebufferStatus ( GLenum target ) void glClear ( GLbitfield mask ) void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) void glClearDepthf ( GLclampf depth ) void glClearStencil ( GLint s ) void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) void glCompileShader ( GLuint shader ) void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) GLuint glCreateProgram ( void ) GLuint glCreateShader ( GLenum type ) void glCullFace ( GLenum mode ) void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) void glDeleteFramebuffers ( GLsizei n, const GLuint *framebuffers ) void glDeleteProgram ( GLuint program ) void glDeleteRenderbuffers ( GLsizei n, const GLuint *renderbuffers ) void glDeleteShader ( GLuint shader ) void glDeleteTextures ( GLsizei n, const GLuint *textures ) void glDepthFunc ( GLenum func ) void glDepthMask ( GLboolean flag ) void glDepthRangef ( GLclampf zNear, GLclampf zFar ) void glDetachShader ( GLuint program, GLuint shader ) void glDisable ( GLenum cap ) void glDisableVertexAttribArray ( GLuint index ) void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) void glEnable ( GLenum cap ) void glEnableVertexAttribArray ( GLuint index ) void glFinish ( void ) void glFlush ( void ) void glFramebufferRenderbuffer ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) void glFramebufferTexture2D ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) void glFrontFace ( GLenum mode ) void glGenBuffers ( GLsizei n, GLuint *buffers ) void glGenerateMipmap ( GLenum target ) void glGenFramebuffers ( GLsizei n, GLuint *framebuffers ) void glGenRenderbuffers ( GLsizei n, GLuint *renderbuffers ) void glGenTextures ( GLsizei n, GLuint *textures ) void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) void glGetAttachedShaders ( GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders ) GLint glGetAttribLocation ( GLuint program, const char *name ) void glGetBooleanv ( GLenum pname, GLboolean *params ) void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) GLenum glGetError ( void ) void glGetFloatv ( GLenum pname, GLfloat *params ) void glGetFramebufferAttachmentParameteriv ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) void glGetIntegerv ( GLenum pname, GLint *params ) void glGetProgramiv ( GLuint program, GLenum pname, GLint *params ) void glGetProgramInfoLog ( GLuint program, GLsizei bufsize, GLsizei *length, char *infolog ) void glGetRenderbufferParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetShaderiv ( GLuint shader, GLenum pname, GLint *params ) void glGetShaderInfoLog ( GLuint shader, GLsizei bufsize, GLsizei *length, char *infolog ) void glGetShaderPrecisionFormat ( GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision ) void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) const GLubyte * glGetString ( GLenum name ) void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetUniformfv ( GLuint program, GLint location, GLfloat *params ) void glGetUniformiv ( GLuint program, GLint location, GLint *params ) GLint glGetUniformLocation ( GLuint program, const char *name ) void glGetVertexAttribfv ( GLuint index, GLenum pname, GLfloat *params ) void glGetVertexAttribiv ( GLuint index, GLenum pname, GLint *params ) // void glGetVertexAttribPointerv ( GLuint index, GLenum pname, void **pointer ) void glHint ( GLenum target, GLenum mode ) GLboolean glIsBuffer ( GLuint buffer ) GLboolean glIsEnabled ( GLenum cap ) GLboolean glIsFramebuffer ( GLuint framebuffer ) GLboolean glIsProgram ( GLuint program ) GLboolean glIsRenderbuffer ( GLuint renderbuffer ) GLboolean glIsShader ( GLuint shader ) GLboolean glIsTexture ( GLuint texture ) void glLineWidth ( GLfloat width ) void glLinkProgram ( GLuint program ) void glPixelStorei ( GLenum pname, GLint param ) void glPolygonOffset ( GLfloat factor, GLfloat units ) void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) void glReleaseShaderCompiler ( void ) void glRenderbufferStorage ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) void glSampleCoverage ( GLclampf value, GLboolean invert ) void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) void glShaderBinary ( GLsizei n, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length ) void glShaderSource ( GLuint shader ) void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) void glStencilFuncSeparate ( GLenum face, GLenum func, GLint ref, GLuint mask ) void glStencilMask ( GLuint mask ) void glStencilMaskSeparate ( GLenum face, GLuint mask ) void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) void glStencilOpSeparate ( GLenum face, GLenum fail, GLenum zfail, GLenum zpass ) void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) void glTexParameteri ( GLenum target, GLenum pname, GLint param ) void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) void glUniform1f ( GLint location, GLfloat x ) void glUniform1fv ( GLint location, GLsizei count, const GLfloat *v ) void glUniform1i ( GLint location, GLint x ) void glUniform1iv ( GLint location, GLsizei count, const GLint *v ) void glUniform2f ( GLint location, GLfloat x, GLfloat y ) void glUniform2fv ( GLint location, GLsizei count, const GLfloat *v ) void glUniform2i ( GLint location, GLint x, GLint y ) void glUniform2iv ( GLint location, GLsizei count, const GLint *v ) void glUniform3f ( GLint location, GLfloat x, GLfloat y, GLfloat z ) void glUniform3fv ( GLint location, GLsizei count, const GLfloat *v ) void glUniform3i ( GLint location, GLint x, GLint y, GLint z ) void glUniform3iv ( GLint location, GLsizei count, const GLint *v ) void glUniform4f ( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) void glUniform4fv ( GLint location, GLsizei count, const GLfloat *v ) void glUniform4i ( GLint location, GLint x, GLint y, GLint z, GLint w ) void glUniform4iv ( GLint location, GLsizei count, const GLint *v ) void glUniformMatrix2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUseProgram ( GLuint program ) void glValidateProgram ( GLuint program ) void glVertexAttrib1f ( GLuint indx, GLfloat x ) void glVertexAttrib1fv ( GLuint indx, const GLfloat *values ) void glVertexAttrib2f ( GLuint indx, GLfloat x, GLfloat y ) void glVertexAttrib2fv ( GLuint indx, const GLfloat *values ) void glVertexAttrib3f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z ) void glVertexAttrib3fv ( GLuint indx, const GLfloat *values ) void glVertexAttrib4f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) void glVertexAttrib4fv ( GLuint indx, const GLfloat *values ) void glVertexAttribPointer ( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLint offset ) void glVertexAttribPointer ( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr ) void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) opengl/tools/glgen/specs/gles11/GLES30.spec0100644 0000000 0000000 00000023006 13077405420 017312 0ustar000000000 0000000 void glReadBuffer ( GLenum mode ) void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices ) void glDrawRangeElements ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLsizei offset ) void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) void glTexImage3D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei offset ) void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels ) void glTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei offset ) void glCopyTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data ) void glCompressedTexImage3D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei offset ) void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data ) void glCompressedTexSubImage3D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei offset ) void glGenQueries ( GLsizei n, GLuint *ids ) void glDeleteQueries ( GLsizei n, const GLuint *ids ) GLboolean glIsQuery ( GLuint id ) void glBeginQuery ( GLenum target, GLuint id ) void glEndQuery ( GLenum target ) void glGetQueryiv ( GLenum target, GLenum pname, GLint *params ) void glGetQueryObjectuiv ( GLuint id, GLenum pname, GLuint *params ) GLboolean glUnmapBuffer ( GLenum target ) void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid **params ) void glDrawBuffers ( GLsizei n, const GLenum *bufs ) void glUniformMatrix2x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix3x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix2x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix4x2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix3x4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glUniformMatrix4x3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glBlitFramebuffer ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) void glRenderbufferStorageMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ) void glFramebufferTextureLayer ( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer ) GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) void glFlushMappedBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length ) void glBindVertexArray ( GLuint array ) void glDeleteVertexArrays ( GLsizei n, const GLuint *arrays ) void glGenVertexArrays ( GLsizei n, GLuint *arrays ) GLboolean glIsVertexArray ( GLuint array ) void glGetIntegeri_v ( GLenum target, GLuint index, GLint *data ) void glBeginTransformFeedback ( GLenum primitiveMode ) void glEndTransformFeedback ( void ) void glBindBufferRange ( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) void glBindBufferBase ( GLenum target, GLuint index, GLuint buffer ) void glTransformFeedbackVaryings ( GLuint program, GLsizei count, const GLchar *varyings, GLenum bufferMode ) void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name ) void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glVertexAttribIPointer ( GLuint index, GLint size, GLenum type, GLsizei stride, GLsizei offset ) void glGetVertexAttribIiv ( GLuint index, GLenum pname, GLint *params ) void glGetVertexAttribIuiv ( GLuint index, GLenum pname, GLuint *params ) void glVertexAttribI4i ( GLuint index, GLint x, GLint y, GLint z, GLint w ) void glVertexAttribI4ui ( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) void glVertexAttribI4iv ( GLuint index, const GLint *v ) void glVertexAttribI4uiv ( GLuint index, const GLuint *v ) void glGetUniformuiv ( GLuint program, GLint location, GLuint *params ) GLint glGetFragDataLocation ( GLuint program, const GLchar *name ) void glUniform1ui ( GLint location, GLuint v0 ) void glUniform2ui ( GLint location, GLuint v0, GLuint v1 ) void glUniform3ui ( GLint location, GLuint v0, GLuint v1, GLuint v2 ) void glUniform4ui ( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) void glUniform1uiv ( GLint location, GLsizei count, const GLuint *value ) void glUniform2uiv ( GLint location, GLsizei count, const GLuint *value ) void glUniform3uiv ( GLint location, GLsizei count, const GLuint *value ) void glUniform4uiv ( GLint location, GLsizei count, const GLuint *value ) void glClearBufferiv ( GLenum buffer, GLint drawbuffer, const GLint *value ) void glClearBufferuiv ( GLenum buffer, GLint drawbuffer, const GLuint *value ) void glClearBufferfv ( GLenum buffer, GLint drawbuffer, const GLfloat *value ) void glClearBufferfi ( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) const GLubyte * glGetStringi ( GLenum name, GLuint index ) void glCopyBufferSubData ( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size ) void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) void glGetActiveUniformsiv ( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params ) GLuint glGetUniformBlockIndex ( GLuint program, const GLchar *uniformBlockName ) void glGetActiveUniformBlockiv ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params ) void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) void glUniformBlockBinding ( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) void glDrawArraysInstanced ( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount ) void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) GLsync glFenceSync ( GLenum condition, GLbitfield flags ) GLboolean glIsSync ( GLsync sync ) void glDeleteSync ( GLsync sync ) GLenum glClientWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout ) void glWaitSync ( GLsync sync, GLbitfield flags, GLuint64 timeout ) void glGetInteger64v ( GLenum pname, GLint64 *params ) void glGetSynciv ( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values ) void glGetInteger64i_v ( GLenum target, GLuint index, GLint64 *data ) void glGetBufferParameteri64v ( GLenum target, GLenum pname, GLint64 *params ) void glGenSamplers ( GLsizei count, GLuint *samplers ) void glDeleteSamplers ( GLsizei count, const GLuint *samplers ) GLboolean glIsSampler ( GLuint sampler ) void glBindSampler ( GLuint unit, GLuint sampler ) void glSamplerParameteri ( GLuint sampler, GLenum pname, GLint param ) void glSamplerParameteriv ( GLuint sampler, GLenum pname, const GLint *param ) void glSamplerParameterf ( GLuint sampler, GLenum pname, GLfloat param ) void glSamplerParameterfv ( GLuint sampler, GLenum pname, const GLfloat *param ) void glGetSamplerParameteriv ( GLuint sampler, GLenum pname, GLint *params ) void glGetSamplerParameterfv ( GLuint sampler, GLenum pname, GLfloat *params ) void glVertexAttribDivisor ( GLuint index, GLuint divisor ) void glBindTransformFeedback ( GLenum target, GLuint id ) void glDeleteTransformFeedbacks ( GLsizei n, const GLuint *ids ) void glGenTransformFeedbacks ( GLsizei n, GLuint *ids ) GLboolean glIsTransformFeedback ( GLuint id ) void glPauseTransformFeedback ( void ) void glResumeTransformFeedback ( void ) void glGetProgramBinary ( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary ) void glProgramBinary ( GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length ) void glProgramParameteri ( GLuint program, GLenum pname, GLint value ) void glInvalidateFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments ) void glInvalidateSubFramebuffer ( GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height ) void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) void glTexStorage3D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth ) void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params ) void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset ) opengl/tools/glgen/specs/gles11/GLES31.spec0100644 0000000 0000000 00000014205 13077405420 017314 0ustar000000000 0000000 void glDispatchCompute ( GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z ) void glDispatchComputeIndirect ( GLintptr indirect ) void glDrawArraysIndirect ( GLenum mode, const void *indirect ) void glDrawElementsIndirect ( GLenum mode, GLenum type, const void *indirect ) void glFramebufferParameteri ( GLenum target, GLenum pname, GLint param ) void glGetFramebufferParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetProgramInterfaceiv ( GLuint program, GLenum programInterface, GLenum pname, GLint *params ) GLuint glGetProgramResourceIndex ( GLuint program, GLenum programInterface, const GLchar *name ) void glGetProgramResourceName ( GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name ) void glGetProgramResourceiv ( GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params ) GLint glGetProgramResourceLocation ( GLuint program, GLenum programInterface, const GLchar *name ) void glUseProgramStages ( GLuint pipeline, GLbitfield stages, GLuint program ) void glActiveShaderProgram ( GLuint pipeline, GLuint program ) GLuint glCreateShaderProgramv ( GLenum type, GLsizei count, const GLchar *const *strings ) void glBindProgramPipeline ( GLuint pipeline ) void glDeleteProgramPipelines ( GLsizei n, const GLuint *pipelines ) void glGenProgramPipelines ( GLsizei n, GLuint *pipelines ) GLboolean glIsProgramPipeline ( GLuint pipeline ) void glGetProgramPipelineiv ( GLuint pipeline, GLenum pname, GLint *params ) void glProgramUniform1i ( GLuint program, GLint location, GLint v0 ) void glProgramUniform2i ( GLuint program, GLint location, GLint v0, GLint v1 ) void glProgramUniform3i ( GLuint program, GLint location, GLint v0, GLint v1, GLint v2 ) void glProgramUniform4i ( GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3 ) void glProgramUniform1ui ( GLuint program, GLint location, GLuint v0 ) void glProgramUniform2ui ( GLuint program, GLint location, GLuint v0, GLuint v1 ) void glProgramUniform3ui ( GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2 ) void glProgramUniform4ui ( GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) void glProgramUniform1f ( GLuint program, GLint location, GLfloat v0 ) void glProgramUniform2f ( GLuint program, GLint location, GLfloat v0, GLfloat v1 ) void glProgramUniform3f ( GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2 ) void glProgramUniform4f ( GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3 ) void glProgramUniform1iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) void glProgramUniform2iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) void glProgramUniform3iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) void glProgramUniform4iv ( GLuint program, GLint location, GLsizei count, const GLint *value ) void glProgramUniform1uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) void glProgramUniform2uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) void glProgramUniform3uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) void glProgramUniform4uiv ( GLuint program, GLint location, GLsizei count, const GLuint *value ) void glProgramUniform1fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) void glProgramUniform2fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) void glProgramUniform3fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) void glProgramUniform4fv ( GLuint program, GLint location, GLsizei count, const GLfloat *value ) void glProgramUniformMatrix2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix2x3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix3x2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix2x4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix4x2fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix3x4fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glProgramUniformMatrix4x3fv ( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value ) void glValidateProgramPipeline ( GLuint pipeline ) void glGetProgramPipelineInfoLog ( GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog ) void glBindImageTexture ( GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format ) void glGetBooleani_v ( GLenum target, GLuint index, GLboolean *data ) void glMemoryBarrier ( GLbitfield barriers ) void glMemoryBarrierByRegion ( GLbitfield barriers ) void glTexStorage2DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations ) void glGetMultisamplefv ( GLenum pname, GLuint index, GLfloat *val ) void glSampleMaski ( GLuint maskNumber, GLbitfield mask ) void glGetTexLevelParameteriv ( GLenum target, GLint level, GLenum pname, GLint *params ) void glGetTexLevelParameterfv ( GLenum target, GLint level, GLenum pname, GLfloat *params ) void glBindVertexBuffer ( GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride ) void glVertexAttribFormat ( GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset ) void glVertexAttribIFormat ( GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset ) void glVertexAttribBinding ( GLuint attribindex, GLuint bindingindex ) void glVertexBindingDivisor ( GLuint bindingindex, GLuint divisor ) opengl/tools/glgen/specs/gles11/GLES31Ext.spec0100644 0000000 0000000 00000006270 13077405420 020000 0ustar000000000 0000000 void glBlendBarrierKHR ( void ) void glDebugMessageControlKHR ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) void glDebugMessageInsertKHR ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) void glDebugMessageCallbackKHR ( GLDEBUGPROCKHR callback, const void *userParam ) GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) void glPushDebugGroupKHR ( GLenum source, GLuint id, GLsizei length, const GLchar *message ) void glPopDebugGroupKHR ( void ) void glObjectLabelKHR ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label ) void glGetObjectLabelKHR ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) void glObjectPtrLabelKHR ( const void *ptr, GLsizei length, const GLchar *label ) void glGetObjectPtrLabelKHR ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) void glGetPointervKHR ( GLenum pname, void **params ) void glMinSampleShadingOES ( GLfloat value ) void glTexStorage3DMultisampleOES ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations ) void glCopyImageSubDataEXT ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth ) void glEnableiEXT ( GLenum target, GLuint index ) void glDisableiEXT ( GLenum target, GLuint index ) void glBlendEquationiEXT ( GLuint buf, GLenum mode ) void glBlendEquationSeparateiEXT ( GLuint buf, GLenum modeRGB, GLenum modeAlpha ) void glBlendFunciEXT ( GLuint buf, GLenum src, GLenum dst ) void glBlendFuncSeparateiEXT ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) void glColorMaskiEXT ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) GLboolean glIsEnablediEXT ( GLenum target, GLuint index ) void glFramebufferTextureEXT ( GLenum target, GLenum attachment, GLuint texture, GLint level ) void glPrimitiveBoundingBoxEXT ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW ) void glPatchParameteriEXT ( GLenum pname, GLint value ) void glTexParameterIivEXT ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterIuivEXT ( GLenum target, GLenum pname, const GLuint *params ) void glGetTexParameterIivEXT ( GLenum target, GLenum pname, GLint *params ) void glGetTexParameterIuivEXT ( GLenum target, GLenum pname, GLuint *params ) void glSamplerParameterIivEXT ( GLuint sampler, GLenum pname, const GLint *param ) void glSamplerParameterIuivEXT ( GLuint sampler, GLenum pname, const GLuint *param ) void glGetSamplerParameterIivEXT ( GLuint sampler, GLenum pname, GLint *params ) void glGetSamplerParameterIuivEXT ( GLuint sampler, GLenum pname, GLuint *params ) void glTexBufferEXT ( GLenum target, GLenum internalformat, GLuint buffer ) void glTexBufferRangeEXT ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size ) opengl/tools/glgen/specs/gles11/GLES32.spec0100644 0000000 0000000 00000007620 13077405420 017320 0ustar000000000 0000000 void glBlendBarrier ( void ) void glCopyImageSubData ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth ) void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) void glDebugMessageInsert ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam ) GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) void glPushDebugGroup ( GLenum source, GLuint id, GLsizei length, const GLchar *message ) void glPopDebugGroup ( void ) void glObjectLabel ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label ) void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label ) void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) void glGetPointerv ( GLenum pname, void **params ) void glEnablei ( GLenum target, GLuint index ) void glDisablei ( GLenum target, GLuint index ) void glBlendEquationi ( GLuint buf, GLenum mode ) void glBlendEquationSeparatei ( GLuint buf, GLenum modeRGB, GLenum modeAlpha ) void glBlendFunci ( GLuint buf, GLenum src, GLenum dst ) void glBlendFuncSeparatei ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) void glColorMaski ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) GLboolean glIsEnabledi ( GLenum target, GLuint index ) void glDrawElementsBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex ) void glDrawRangeElementsBaseVertex ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex ) void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex ) void glFramebufferTexture ( GLenum target, GLenum attachment, GLuint texture, GLint level ) void glPrimitiveBoundingBox ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW ) GLenum glGetGraphicsResetStatus ( void ) void glReadnPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data ) void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params ) void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params ) void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params ) void glMinSampleShading ( GLfloat value ) void glPatchParameteri ( GLenum pname, GLint value ) void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params ) void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param ) void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params ) void glTexBuffer ( GLenum target, GLenum internalformat, GLuint buffer ) void glTexBufferRange ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size ) void glTexStorage3DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations ) opengl/tools/glgen/specs/gles11/checks.spec0100644 0000000 0000000 00000010507 13077405420 017657 0ustar000000000 0000000 # Copyright (C) 2013 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. # # # ifcheck defaults to 1 so we don't explicitly list pnames requiring # a single value. unknown pnames will be validated against one value, which # is not perfect but better than nothing. # glBufferData nullAllowed data check data size glBufferSubData check data size # glCompressedTexImage2D # glCompressedTexSubImage2D glClipPlanef check eqn 4 glClipPlanex check eqn 4 glDebugMessageControl check ids count glDebugMessageInsert check message length glDeleteBuffers check buffers n glDeleteFramebuffers check framebuffers n glDeleteFramebuffersOES check framebuffers n glDeleteRenderbuffers check renderbuffers n glDeleteRenderbuffersOES check renderbuffers n glDeleteTextures check textures n glDrawElements check_AIOOBE indices count glDrawElementsBaseVertex check_AIOOBE indices count-basevertex glDrawRangeElementsBaseVertex check_AIOOBE indices count-basevertex glDrawTexfvOES check coords 5 glDrawTexivOES check coords 5 glDrawTexsvOES check coords 5 glDrawTexxvOES check coords 5 glFog ifcheck params 4 pname GL_FOG_COLOR glGenBuffers check buffers n glGenFramebuffersOES check framebuffers n glGenFramebuffers check framebuffers n glGenRenderbuffersOES check renderbuffers n glGenRenderbuffers check renderbuffers n glGenTextures check textures n // glGetActiveAttrib // glGetActiveUniform glGetAttachedShaders nullAllowed count check count 1 check shaders maxcount // glGetBooleanv glGetBufferParameter check params 1 glGetClipPlanef check eqn 4 glGetClipPlanex check eqn 4 glGetClipPlanefOES check eqn 4 glGetClipPlanexOES check eqn 4 // glGetFloatv glGetFramebufferAttachmentParameterivOES check params 1 // glGetIntegerv glGetLight ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION glGetMaterial ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE glGetProgramBinary nullAllowed length // glGetProgramInfoLog glGetProgramiv check params 1 glGetProgramResourceiv nullAllowed length glGetRenderbufferParameteriv check params 1 glGetRenderbufferParameterivOES check params 1 // glGetShaderInfoLog glGetShaderiv check params 1 glGetShaderPrecisionFormat check range 1 check precision 1 // glGetShaderSource // glGetString glGetSynciv nullAllowed length glGetTexEnv ifcheck params 4 pname GL_TEXTURE_ENV_COLOR glGetTexGen ifcheck params 4 pname GL_OBJECT_PLANE,GL_EYE_PLANE glGetTexParameter check params 1 glGetnUniformfv check params bufSize glGetnUniformiv check params bufSize glGetnUniformuiv check params bufSize glGetUniform check params 1 glGetVertexAttrib ifcheck params 4 pname GL_CURRENT_VERTEX_ATTRIB glLight ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION glLightModel ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT glLoadMatrix check m 16 glMaterial ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE glMultMatrix check m 16 glObjectLabelKHR nullAllowed label glObjectLabel nullAllowed label check label length glPointParameter check params 1 glPushDebugGroup check message length glQueryMatrixxOES check mantissa 16 check exponent 16 return -1 # glReadPixels glReadnPixels check data bufSize glShaderBinary check binary length // glShaderSource glTexEnv ifcheck params 4 pname GL_TEXTURE_ENV_COLOR glTexImage2D nullAllowed pixels glTexImage3D nullAllowed pixels glTexParameter check params 1 glTexSubImage2D nullAllowed pixels glUniform1 check v count glUniform2 check v count*2 glUniform3 check v count*3 glUniform4 check v count*4 glUniformMatrix2 check value count*4 glUniformMatrix3 check value count*9 glUniformMatrix4 check value count*16 glVertexAttrib1 check values 1 glVertexAttrib2 check values 2 glVertexAttrib3 check values 3 glVertexAttrib4 check values 4 # glVertexAttribPointer opengl/tools/glgen/specs/jsr239/0040755 0000000 0000000 00000000000 13077405420 015503 5ustar000000000 0000000 opengl/tools/glgen/specs/jsr239/glspec-1.00100644 0000000 0000000 00000014736 13077405420 017207 0ustar000000000 0000000 void glActiveTexture ( GLenum texture ) void glAlphaFunc ( GLenum func, GLclampf ref ) void glAlphaFuncx ( GLenum func, GLclampx ref ) void glBindTexture ( GLenum target, GLuint texture ) void glBlendFunc ( GLenum sfactor, GLenum dfactor ) void glClear ( GLbitfield mask ) void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) void glClearDepthf ( GLclampf depth ) void glClearDepthx ( GLclampx depth ) void glClearStencil ( GLint s ) void glClientActiveTexture ( GLenum texture ) void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) void glCullFace ( GLenum mode ) void glDeleteTextures ( GLsizei n, const GLuint *textures ) void glDepthFunc ( GLenum func ) void glDepthMask ( GLboolean flag ) void glDepthRangef ( GLclampf zNear, GLclampf zFar ) void glDepthRangex ( GLclampx zNear, GLclampx zFar ) void glDisable ( GLenum cap ) void glDisableClientState ( GLenum array ) void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) void glEnable ( GLenum cap ) void glEnableClientState ( GLenum array ) void glFinish ( void ) void glFlush ( void ) void glFogf ( GLenum pname, GLfloat param ) void glFogfv ( GLenum pname, const GLfloat *params ) void glFogx ( GLenum pname, GLfixed param ) void glFogxv ( GLenum pname, const GLfixed *params ) void glFrontFace ( GLenum mode ) void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glGenTextures ( GLsizei n, GLuint *textures ) GLenum glGetError ( void ) void glGetIntegerv ( GLenum pname, GLint *params ) const GLubyte * glGetString ( GLenum name ) void glHint ( GLenum target, GLenum mode ) void glLightModelf ( GLenum pname, GLfloat param ) void glLightModelfv ( GLenum pname, const GLfloat *params ) void glLightModelx ( GLenum pname, GLfixed param ) void glLightModelxv ( GLenum pname, const GLfixed *params ) void glLightf ( GLenum light, GLenum pname, GLfloat param ) void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) void glLightx ( GLenum light, GLenum pname, GLfixed param ) void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) void glLineWidth ( GLfloat width ) void glLineWidthx ( GLfixed width ) void glLoadIdentity ( void ) void glLoadMatrixf ( const GLfloat *m ) void glLoadMatrixx ( const GLfixed *m ) void glLogicOp ( GLenum opcode ) void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) void glMatrixMode ( GLenum mode ) void glMultMatrixf ( const GLfloat *m ) void glMultMatrixx ( const GLfixed *m ) void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) void glPixelStorei ( GLenum pname, GLint param ) void glPointSize ( GLfloat size ) void glPointSizex ( GLfixed size ) void glPolygonOffset ( GLfloat factor, GLfloat units ) void glPolygonOffsetx ( GLfixed factor, GLfixed units ) void glPopMatrix ( void ) void glPushMatrix ( void ) void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) void glSampleCoverage ( GLclampf value, GLboolean invert ) void glSampleCoveragex ( GLclampx value, GLboolean invert ) void glScalef ( GLfloat x, GLfloat y, GLfloat z ) void glScalex ( GLfixed x, GLfixed y, GLfixed z ) void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) void glShadeModel ( GLenum mode ) void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) void glStencilMask ( GLuint mask ) void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) opengl/tools/glgen/specs/jsr239/glspec-1.0ext0100644 0000000 0000000 00000000105 13077405420 017711 0ustar000000000 0000000 GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) opengl/tools/glgen/specs/jsr239/glspec-1.10100644 0000000 0000000 00000005324 13077405420 017201 0ustar000000000 0000000 void glBindBuffer ( GLenum target, GLuint buffer ) void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) void glClipPlanef ( GLenum plane, const GLfloat *equation ) void glClipPlanex ( GLenum plane, const GLfixed *equation ) void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) void glGenBuffers ( GLsizei n, GLuint *buffers ) void glGetBooleanv ( GLenum pname, GLboolean *params ) void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) void glGetFixedv ( GLenum pname, GLfixed *params ) void glGetFloatv ( GLenum pname, GLfloat *params ) void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) GLboolean glIsBuffer ( GLuint buffer ) GLboolean glIsEnabled ( GLenum cap ) GLboolean glIsTexture ( GLuint texture ) void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) void glPointParameterf ( GLenum pname, GLfloat param ) void glPointParameterfv ( GLenum pname, const GLfloat *params ) void glPointParameterx ( GLenum pname, GLfixed param ) void glPointParameterxv ( GLenum pname, const GLfixed *params ) void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) void glTexEnvi ( GLenum target, GLenum pname, GLint param ) void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) void glTexParameteri ( GLenum target, GLenum pname, GLint param ) void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) opengl/tools/glgen/specs/jsr239/glspec-1.1ext0100644 0000000 0000000 00000002056 13077405420 017721 0ustar000000000 0000000 void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) void glDrawTexfvOES ( const GLfloat *coords ) void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) void glDrawTexivOES ( const GLint *coords ) void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) void glDrawTexsvOES ( const GLshort *coords ) void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) void glDrawTexxvOES ( const GLfixed *coords ) void glEnable ( GLenum cap ) void glEnableClientState ( GLenum array ) void glLoadPaletteFromModelViewMatrixOES ( void ) void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) opengl/tools/glgen/specs/jsr239/glspec-1.1extpack0100644 0000000 0000000 00000005066 13077405420 020564 0ustar000000000 0000000 void glBindFramebufferOES ( GLint target, GLint framebuffer ) void glBindRenderbufferOES ( GLint target, GLint renderbuffer ) void glBindTexture ( GLint target, GLint texture ) void glBlendEquation ( GLint mode ) void glBlendEquationSeparate ( GLint modeRGB, GLint modeAlpha ) void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dstAlpha ) GLint glCheckFramebufferStatusOES ( GLint target ) void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) void glCopyTexImage2D ( GLint target, GLint level, GLint internalformat, GLint x, GLint y, GLint width, GLint height, GLint border ) void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) void glEnable ( GLint cap ) void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer ) void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level ) void glGenerateMipmapOES ( GLint target ) void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) void glGetIntegerv ( GLint pname, GLint *params ) void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) GLboolean glIsFramebufferOES ( GLint framebuffer ) GLboolean glIsRenderbufferOES ( GLint renderbuffer ) void glRenderbufferStorageOES ( GLint target, GLint internalformat, GLint width, GLint height ) void glStencilOp ( GLint fail, GLint zfail, GLint zpass ) void glTexEnvf ( GLint target, GLint pname, GLfloat param ) void glTexEnvfv ( GLint target, GLint pname, GLfloat *params ) void glTexEnvx ( GLint target, GLint pname, GLint param ) void glTexEnvxv ( GLint target, GLint pname, GLint *params ) void glTexGenf ( GLint coord, GLint pname, GLfloat param ) void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) void glTexGeni ( GLint coord, GLint pname, GLint param ) void glTexGeniv ( GLint coord, GLint pname, GLint *params ) void glTexGenx ( GLint coord, GLint pname, GLint param ) void glTexGenxv ( GLint coord, GLint pname, GLint *params ) void glTexParameterf ( GLint target, GLint pname, GLfloat param ) opengl/tools/glgen/specs/jsr239/glspec-checks0100644 0000000 0000000 00000013567 13077405420 020152 0ustar000000000 0000000 glClipPlanef check equation 4 glClipPlanex check equation 4 glDeleteBuffers check buffers n glDeleteTextures check textures n glDrawElements check_AIOOBE indices count glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR glGenBuffers check buffers n glGenTextures check textures n glGetClipPlane check eqn 4 glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR glGetTexParameter check params 1 glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION glLoadMatrix check m 16 glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE glMultMatrix check m 16 glPointParameter check params 1 glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR glTexImage2D nullAllowed pixels glTexSubImage2D nullAllowed pixels glBufferData nullAllowed data check data size glBufferSubData check data size glTexParameter check params 1 glQueryMatrixxOES check mantissa 16 check exponent 16 return -1 glDrawTexfvOES check coords 5 glDrawTexivOES check coords 5 glDrawTexsvOES check coords 5 glDrawTexxvOES check coords 5 glBindFramebufferOES requires OES_framebuffer_object glBindRenderbufferOES requires OES_framebuffer_object glBlendEquation requires OES_blend_subtract glBlendEquationSeparate requires OES_blend_equation_separate glBlendFuncSeparate requires OES_blend_equation_separate glCheckFramebufferStatusOES requires OES_framebuffer_object return 0 glDeleteFramebuffersOES requires OES_framebuffer_object check framebuffers n glDeleteRenderbuffersOES requires OES_framebuffer_object check renderbuffers n glFramebufferRenderbufferOES requires OES_framebuffer_object glFramebufferStorageOES requires OES_framebuffer_object glFramebufferTexture2DOES requires OES_framebuffer_object glGenFramebuffersOES requires OES_framebuffer_object check framebuffers n glGenRenderbuffersOES requires OES_framebuffer_object check renderbuffers n glGenerateMipmapOES requires OES_framebuffer_object glGetFramebufferAttachmentParameterivOES requires OES_framebuffer_object glGetRenderbufferParameterivOES requires OES_framebuffer_object glIsFramebufferOES requires OES_framebuffer_object return JNI_FALSE glIsRenderbufferOES requires OES_framebuffer_object return JNI_FALSE glRenderbufferStorageOES requires OES_framebuffer_object glGetTexGen requires OES_texture_cube_map glTexGen requires OES_texture_cube_map glTexGenf requires OES_texture_cube_map glTexGeni requires OES_texture_cube_map glTexGenx requires OES_texture_cube_map glGetBufferParameter unsupported opengl/tools/glgen/src/0040755 0000000 0000000 00000000000 13077405420 014121 5ustar000000000 0000000 opengl/tools/glgen/src/.gitignore0100644 0000000 0000000 00000000010 13077405420 016075 0ustar000000000 0000000 *.class opengl/tools/glgen/src/CFunc.java0100644 0000000 0000000 00000010473 13077405420 015764 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.util.*; public class CFunc { String original; CType ftype; String fname; List argNames = new ArrayList(); List argTypes = new ArrayList(); boolean hasPointerArg = false; boolean hasTypedPointerArg = false; boolean hasEGLHandleArg = false; public CFunc(String original) { this.original = original; } public String getOriginal() { return original; } public void setName(String fname) { this.fname = fname; } public String getName() { return fname; } public void setType(CType ftype) { this.ftype = ftype; } public CType getType() { return ftype; } public void addArgument(String argName, CType argType) { argNames.add(argName); argTypes.add(argType); if (argType.isPointer()) { hasPointerArg = true; } if (argType.isTypedPointer()) { hasTypedPointerArg = true; } if (argType.isEGLHandle()) { hasEGLHandleArg = true; } } public int getNumArgs() { return argNames.size(); } public int getArgIndex(String name) { int len = argNames.size(); for (int i = 0; i < len; i++) { if (name.equals(argNames.get(i))) { return i; } } return -1; } public String getArgName(int index) { return argNames.get(index); } public CType getArgType(int index) { return argTypes.get(index); } public boolean hasPointerArg() { return hasPointerArg; } public boolean hasTypedPointerArg() { return hasTypedPointerArg; } public boolean hasEGLHandleArg() { return hasEGLHandleArg; } @Override public String toString() { String s = "Function " + fname + " returns " + ftype + ": "; for (int i = 0; i < argNames.size(); i++) { if (i > 0) { s += ", "; } s += argTypes.get(i) + " " + argNames.get(i); } return s; } public static CFunc parseCFunc(String s) { CFunc cfunc = new CFunc(s); String[] tokens = s.split("\\s"); int i = 0; CType ftype = new CType(); String ftypeName = tokens[i++]; if (ftypeName.equals("const")) { ftype.setIsConst(true); ftypeName = tokens[i++]; } ftype.setBaseType(ftypeName); String fname = tokens[i++]; if (fname.equals("*")) { ftype.setIsPointer(true); fname = tokens[i++]; } cfunc.setName(fname); cfunc.setType(ftype); while (i < tokens.length) { String tok = tokens[i++]; if (tok.equals("(")) { tok = tokens[i++]; if (tok.equals("void")) { break; } } if (tok.equals(")")) { break; } CType argType = new CType(); String argTypeName = tok; String argName = ""; if (argTypeName.equals("const")) { argType.setIsConst(true); argTypeName = tokens[i++]; } argType.setBaseType(argTypeName); argName = tokens[i++]; if (argName.startsWith("*")) { argType.setIsPointer(true); argName = argName.substring(1, argName.length()); } if (argName.endsWith(",")) { argName = argName.substring(0, argName.length() - 1); } cfunc.addArgument(argName, argType); } return cfunc; } } opengl/tools/glgen/src/CType.java0100644 0000000 0000000 00000005326 13077405420 016013 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ public class CType { String baseType; boolean isConst; boolean isPointer; public CType() { } public CType(String baseType) { setBaseType(baseType); } public CType(String baseType, boolean isConst, boolean isPointer) { setBaseType(baseType); setIsConst(isConst); setIsPointer(isPointer); } public String getDeclaration() { return baseType + (isPointer ? " *" : ""); } public void setIsConst(boolean isConst) { this.isConst = isConst; } public boolean isConst() { return isConst; } public void setIsPointer(boolean isPointer) { this.isPointer = isPointer; } public boolean isPointer() { return isPointer; } public boolean isEGLHandle() { if(baseType.equals("EGLContext") || baseType.equals("EGLConfig") || baseType.equals("EGLSurface") || baseType.equals("EGLDisplay")) { return true; } return false; } boolean isVoid() { String baseType = getBaseType(); return baseType.equals("GLvoid") || baseType.equals("void"); } public boolean isConstCharPointer() { return isConst && isPointer && (baseType.equals("char") || baseType.equals("GLchar")); } public boolean isTypedPointer() { return isPointer() && !isVoid() && !isConstCharPointer(); } public void setBaseType(String baseType) { this.baseType = baseType; } public String getBaseType() { return baseType; } @Override public String toString() { String s = ""; if (isConst()) { s += "const "; } s += baseType; if (isPointer()) { s += "*"; } return s; } @Override public int hashCode() { return baseType.hashCode() ^ (isPointer ? 2 : 0) ^ (isConst ? 1 : 0); } @Override public boolean equals(Object o) { if (o != null && o instanceof CType) { CType c = (CType)o; return baseType.equals(c.baseType) && isPointer() == c.isPointer() && isConst() == c.isConst(); } return false; } } opengl/tools/glgen/src/CodeEmitter.java0100644 0000000 0000000 00000001516 13077405420 017170 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ public interface CodeEmitter { void setVersion(int version, boolean ext, boolean pack); void emitCode(CFunc cfunc, String original); void addNativeRegistration(String fname); void emitNativeRegistration(); } opengl/tools/glgen/src/EGLCodeEmitter.java0100644 0000000 0000000 00000003604 13077405420 017520 0ustar000000000 0000000 /* * Copyright 2012 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. */ import java.io.PrintStream; /** * Emits a Java interface and Java & C implementation for a C function. * *

The Java interface will have Buffer and array variants for functions that * have a typed pointer argument. The array variant will convert a single " *data" * argument to a pair of arguments "[] data, int offset". */ public class EGLCodeEmitter extends JniCodeEmitter { PrintStream mJavaImplStream; PrintStream mCStream; PrintStream mJavaInterfaceStream; /** */ public EGLCodeEmitter(String classPathName, ParameterChecker checker, PrintStream javaImplStream, PrintStream cStream) { mClassPathName = classPathName; mChecker = checker; mJavaImplStream = javaImplStream; mCStream = cStream; mUseContextPointer = false; mUseStaticMethods = true; mUseSimpleMethodNames = true; mUseHideCommentForAPI = false; } public void emitCode(CFunc cfunc, String original) { emitCode(cfunc, original, null, mJavaImplStream, mCStream); } public void emitNativeRegistration(String nativeRegistrationName) { emitNativeRegistration(nativeRegistrationName, mCStream); } } opengl/tools/glgen/src/GLESCodeEmitter.java0100644 0000000 0000000 00000003475 13077405420 017651 0ustar000000000 0000000 /* * Copyright (C) 2009 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. */ import java.io.PrintStream; /** * Emits a Java interface and Java & C implementation for a C function. * *

The Java interface will have Buffer and array variants for functions that * have a typed pointer argument. The array variant will convert a single " *data" * argument to a pair of arguments "[] data, int offset". */ public class GLESCodeEmitter extends JniCodeEmitter { PrintStream mJavaImplStream; PrintStream mCStream; PrintStream mJavaInterfaceStream; /** */ public GLESCodeEmitter(String classPathName, ParameterChecker checker, PrintStream javaImplStream, PrintStream cStream) { mClassPathName = classPathName; mChecker = checker; mJavaImplStream = javaImplStream; mCStream = cStream; mUseContextPointer = false; mUseStaticMethods = true; } public void emitCode(CFunc cfunc, String original) { emitCode(cfunc, original, null, mJavaImplStream, mCStream); } public void emitNativeRegistration(String nativeRegistrationName) { emitNativeRegistration(nativeRegistrationName, mCStream); } } opengl/tools/glgen/src/GenerateEGL.java0100644 0000000 0000000 00000010073 13077405420 017044 0ustar000000000 0000000 /* * Copyright 2012 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. */ import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; public class GenerateEGL { private static void copy(String filename, PrintStream out) throws IOException { BufferedReader br = new BufferedReader(new FileReader(filename)); String s; while ((s = br.readLine()) != null) { out.println(s); } } private static void emit(EGLCodeEmitter emitter, BufferedReader specReader, PrintStream glStream, PrintStream cStream) throws Exception { String s = null; while ((s = specReader.readLine()) != null) { if (s.trim().startsWith("//")) { continue; } CFunc cfunc = CFunc.parseCFunc(s); String fname = cfunc.getName(); String stubRoot = "stubs/egl/" + fname; String javaPath = stubRoot + ".java"; File f = new File(javaPath); if (f.exists()) { System.out.println("Special-casing function " + fname); copy(javaPath, glStream); copy(stubRoot + ".cpp", cStream); // Register native function names // This should be improved to require fewer discrete files String filename = stubRoot + ".nativeReg"; BufferedReader br = new BufferedReader(new FileReader(filename)); String nfunc; while ((nfunc = br.readLine()) != null) { emitter.addNativeRegistration(nfunc); } } else { emitter.emitCode(cfunc, s); } } } public static void main(String[] args) throws Exception { int aidx = 0; while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) { switch (args[aidx].charAt(1)) { default: System.err.println("Unknown flag: " + args[aidx]); System.exit(1); } aidx++; } BufferedReader checksReader = new BufferedReader(new FileReader("specs/egl/checks.spec")); ParameterChecker checker = new ParameterChecker(checksReader); for(String suffix: new String[] {"EGL14", "EGLExt"}) { BufferedReader specReader = new BufferedReader(new FileReader( "specs/egl/" + suffix + ".spec")); String egljFilename = "android/opengl/" + suffix + ".java"; String eglcFilename = "android_opengl_" + suffix + ".cpp"; PrintStream egljStream = new PrintStream(new FileOutputStream("out/" + egljFilename)); PrintStream eglcStream = new PrintStream(new FileOutputStream("out/" + eglcFilename)); copy("stubs/egl/" + suffix + "Header.java-if", egljStream); copy("stubs/egl/" + suffix + "cHeader.cpp", eglcStream); EGLCodeEmitter emitter = new EGLCodeEmitter( "android/opengl/" + suffix, checker, egljStream, eglcStream); emit(emitter, specReader, egljStream, eglcStream); emitter.emitNativeRegistration( "register_android_opengl_jni_" + suffix); egljStream.println("}"); egljStream.close(); eglcStream.close(); } } } opengl/tools/glgen/src/GenerateGL.java0100644 0000000 0000000 00000016713 13077405420 016746 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; public class GenerateGL { static void copy(String filename, PrintStream out) throws IOException { BufferedReader br = new BufferedReader(new FileReader(filename)); String s; while ((s = br.readLine()) != null) { out.println(s); } } private static void emit(int version, boolean ext, boolean pack, CodeEmitter emitter, BufferedReader specReader, PrintStream glStream, PrintStream glImplStream, PrintStream cStream) throws Exception { String s = null; while ((s = specReader.readLine()) != null) { if (s.trim().startsWith("//")) { continue; } CFunc cfunc = CFunc.parseCFunc(s); String fname = cfunc.getName(); File f = new File("stubs/jsr239/" + fname + ".java-1" + version + "-if"); if (f.exists()) { System.out.println("Special-casing function " + fname); copy("stubs/jsr239/" + fname + ".java-1" + version + "-if", glStream); copy("stubs/jsr239/" + fname + ".java-impl", glImplStream); copy("stubs/jsr239/" + fname + ".cpp", cStream); // Register native function names // This should be improved to require fewer discrete files String filename = "stubs/jsr239/" + fname + ".nativeReg"; BufferedReader br = new BufferedReader(new FileReader(filename)); String nfunc; while ((nfunc = br.readLine()) != null) { emitter.addNativeRegistration(nfunc); } } else { emitter.setVersion(version, ext, pack); emitter.emitCode(cfunc, s); } } } public static void main(String[] args) throws Exception { String classPathName = "com/google/android/gles_jni/GLImpl"; boolean useContextPointer = true; int aidx = 0; while (args[aidx].charAt(0) == '-') { switch (args[aidx].charAt(1)) { case 'c': useContextPointer = false; break; default: System.err.println("Unknown flag: " + args[aidx]); System.exit(1); } aidx++; } System.out.println("useContextPointer = " + useContextPointer); BufferedReader spec10Reader = new BufferedReader(new FileReader(args[aidx++])); BufferedReader spec10ExtReader = new BufferedReader(new FileReader(args[aidx++])); BufferedReader spec11Reader = new BufferedReader(new FileReader(args[aidx++])); BufferedReader spec11ExtReader = new BufferedReader(new FileReader(args[aidx++])); BufferedReader spec11ExtPackReader = new BufferedReader(new FileReader(args[aidx++])); BufferedReader checksReader = new BufferedReader(new FileReader(args[aidx++])); String gl10Filename = "javax/microedition/khronos/opengles/GL10.java"; String gl10ExtFilename = "javax/microedition/khronos/opengles/GL10Ext.java"; String gl11Filename = "javax/microedition/khronos/opengles/GL11.java"; String gl11ExtFilename = "javax/microedition/khronos/opengles/GL11Ext.java"; String gl11ExtPackFilename = "javax/microedition/khronos/opengles/GL11ExtensionPack.java"; String glImplFilename = "com/google/android/gles_jni/GLImpl.java"; String cFilename = "com_google_android_gles_jni_GLImpl.cpp"; PrintStream gl10Stream = new PrintStream(new FileOutputStream("out/" + gl10Filename)); PrintStream gl10ExtStream = new PrintStream(new FileOutputStream("out/" + gl10ExtFilename)); PrintStream gl11Stream = new PrintStream(new FileOutputStream("out/" + gl11Filename)); PrintStream gl11ExtStream = new PrintStream(new FileOutputStream("out/" + gl11ExtFilename)); PrintStream gl11ExtPackStream = new PrintStream(new FileOutputStream("out/" + gl11ExtPackFilename)); PrintStream glImplStream = new PrintStream(new FileOutputStream("out/" + glImplFilename)); PrintStream cStream = new PrintStream(new FileOutputStream("out/" + cFilename)); ParameterChecker checker = new ParameterChecker(checksReader); CodeEmitter emitter = new Jsr239CodeEmitter(classPathName, checker, gl10Stream, gl10ExtStream, gl11Stream, gl11ExtStream, gl11ExtPackStream, glImplStream, cStream, useContextPointer); gl10Stream.println("/* //device/java/android/" + gl10Filename); gl10ExtStream.println("/* //device/java/android/" + gl10ExtFilename); gl11Stream.println("/* //device/java/android/" + gl11Filename); gl11ExtStream.println("/* //device/java/android/" + gl11ExtFilename); gl11ExtPackStream.println("/* //device/java/android/" + gl11ExtPackFilename); glImplStream.println("/* //device/java/android/" + glImplFilename); cStream.println("/* //device/libs/android_runtime/" + cFilename); copy("stubs/jsr239/GL10Header.java-if", gl10Stream); copy("stubs/jsr239/GL10ExtHeader.java-if", gl10ExtStream); copy("stubs/jsr239/GL11Header.java-if", gl11Stream); copy("stubs/jsr239/GL11ExtHeader.java-if", gl11ExtStream); copy("stubs/jsr239/GL11ExtensionPackHeader.java-if", gl11ExtPackStream); copy("stubs/jsr239/GLImplHeader.java-impl", glImplStream); copy("stubs/jsr239/GLCHeader.cpp", cStream); emit(0, false, false, emitter, spec10Reader, gl10Stream, glImplStream, cStream); emit(0, true, false, emitter, spec10ExtReader, gl10ExtStream, glImplStream, cStream); emit(1, false, false, emitter, spec11Reader, gl11Stream, glImplStream, cStream); emit(1, true, false, emitter, spec11ExtReader, gl11ExtStream, glImplStream, cStream); emit(1, true, true, emitter, spec11ExtPackReader, gl11ExtPackStream, glImplStream, cStream); emitter.emitNativeRegistration(); gl10Stream.println("}"); gl10ExtStream.println("}"); gl11Stream.println("}"); gl11ExtStream.println("}"); gl11ExtPackStream.println("}"); glImplStream.println("}"); } } opengl/tools/glgen/src/GenerateGLES.java0100644 0000000 0000000 00000010461 13077405420 017170 0ustar000000000 0000000 /* * Copyright (C) 2009 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. */ import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; public class GenerateGLES { static void copy(String filename, PrintStream out) throws IOException { BufferedReader br = new BufferedReader(new FileReader(filename)); String s; while ((s = br.readLine()) != null) { out.println(s); } } private static void emit(GLESCodeEmitter emitter, BufferedReader specReader, PrintStream glStream, PrintStream cStream) throws Exception { String s = null; while ((s = specReader.readLine()) != null) { if (s.trim().startsWith("//")) { continue; } CFunc cfunc = CFunc.parseCFunc(s); String fname = cfunc.getName(); String stubRoot = "stubs/gles11/" + fname; String javaPath = stubRoot + ".java"; File f = new File(javaPath); if (f.exists()) { System.out.println("Special-casing function " + fname); copy(javaPath, glStream); copy(stubRoot + ".cpp", cStream); // Register native function names // This should be improved to require fewer discrete files String filename = stubRoot + ".nativeReg"; BufferedReader br = new BufferedReader(new FileReader(filename)); String nfunc; while ((nfunc = br.readLine()) != null) { emitter.addNativeRegistration(nfunc); } } else { emitter.emitCode(cfunc, s); } } } public static void main(String[] args) throws Exception { int aidx = 0; while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) { switch (args[aidx].charAt(1)) { default: System.err.println("Unknown flag: " + args[aidx]); System.exit(1); } aidx++; } BufferedReader checksReader = new BufferedReader(new FileReader("specs/gles11/checks.spec")); ParameterChecker checker = new ParameterChecker(checksReader); // Generate files for(String suffix: new String[] {"GLES10", "GLES10Ext", "GLES11", "GLES11Ext", "GLES20", "GLES30", "GLES31", "GLES31Ext", "GLES32"}) { BufferedReader spec11Reader = new BufferedReader(new FileReader("specs/gles11/" + suffix + ".spec")); String gl11Filename = "android/opengl/" + suffix + ".java"; String gl11cFilename = "android_opengl_" + suffix + ".cpp"; PrintStream gl11Stream = new PrintStream(new FileOutputStream("out/" + gl11Filename)); PrintStream gl11cStream = new PrintStream(new FileOutputStream("out/" + gl11cFilename)); copy("stubs/gles11/" + suffix + "Header.java-if", gl11Stream); copy("stubs/gles11/" + suffix + "cHeader.cpp", gl11cStream); copy("stubs/gles11/common.cpp", gl11cStream); GLESCodeEmitter emitter = new GLESCodeEmitter( "android/opengl/" + suffix, checker, gl11Stream, gl11cStream); emit(emitter, spec11Reader, gl11Stream, gl11cStream); emitter.emitNativeRegistration("register_android_opengl_jni_" + suffix); gl11Stream.println("}"); gl11Stream.close(); gl11cStream.close(); } } } opengl/tools/glgen/src/JFunc.java0100644 0000000 0000000 00000010717 13077405420 015774 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.util.ArrayList; import java.util.List; public class JFunc { String className = "com.google.android.gles_jni.GL11Impl"; CFunc cfunc; JType ftype; String fname; List argNames = new ArrayList(); List argTypes = new ArrayList(); List argCIndices = new ArrayList(); boolean hasBufferArg = false; boolean hasTypedBufferArg = false; ArrayList bufferArgNames = new ArrayList(); public JFunc(CFunc cfunc) { this.cfunc = cfunc; } public CFunc getCFunc() { return cfunc; } public void setName(String fname) { this.fname = fname; } public String getName() { return fname; } public void setType(JType ftype) { this.ftype = ftype; } public JType getType() { return ftype; } public void setClassName(String className) { this.className = className; } public String getClassName() { return className; } public boolean hasBufferArg() { return hasBufferArg; } public boolean hasTypedBufferArg() { return hasTypedBufferArg; } public String getBufferArgName(int index) { return bufferArgNames.get(index); } public void addArgument(String argName, JType argType, int cindex) { argNames.add(argName); argTypes.add(argType); argCIndices.add(new Integer(cindex)); if (argType.isBuffer()) { hasBufferArg = true; bufferArgNames.add(argName); } if (argType.isTypedBuffer()) { hasTypedBufferArg = true; bufferArgNames.add(argName); } } public int getNumArgs() { return argNames.size(); } public int getArgIndex(String name) { int len = argNames.size(); for (int i = 0; i < len; i++) { if (name.equals(argNames.get(i))) { return i; } } return -1; } public String getArgName(int index) { return argNames.get(index); } public JType getArgType(int index) { return argTypes.get(index); } public int getArgCIndex(int index) { return argCIndices.get(index).intValue(); } public static JFunc convert(CFunc cfunc, boolean useArray) { try { JFunc jfunc = new JFunc(cfunc); jfunc.setName(cfunc.getName()); jfunc.setType(JType.convert(cfunc.getType(), false)); int numArgs = cfunc.getNumArgs(); int numOffsets = 0; for (int i = 0; i < numArgs; i++) { CType cArgType = cfunc.getArgType(i); if (cArgType.isTypedPointer() && useArray) { ++numOffsets; } } for (int i = 0; i < numArgs; i++) { String cArgName = cfunc.getArgName(i); CType cArgType = cfunc.getArgType(i); jfunc.addArgument(cArgName, JType.convert(cArgType, useArray), i); if (cArgType.isTypedPointer() && useArray) { if (numOffsets > 1) { jfunc.addArgument(cArgName + "Offset", new JType("int"), i); } else { jfunc.addArgument("offset", new JType("int"), i); } } } return jfunc; } catch (RuntimeException e) { System.err.println("Failed to convert function " + cfunc); throw e; } } @Override public String toString() { String s = "Function " + fname + " returns " + ftype + ": "; for (int i = 0; i < argNames.size(); i++) { if (i > 0) { s += ", "; } s += argTypes.get(i) + " " + argNames.get(i); } return s; } } opengl/tools/glgen/src/JType.java0100644 0000000 0000000 00000027325 13077405420 016025 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.util.HashMap; public class JType { String baseType; boolean isArray; boolean isClass; boolean isString; static HashMap typeMapping = new HashMap(); static HashMap arrayTypeMapping = new HashMap(); static { // Primitive types typeMapping.put(new CType("GLbitfield"), new JType("int")); typeMapping.put(new CType("GLboolean"), new JType("boolean")); typeMapping.put(new CType("GLclampf"), new JType("float")); typeMapping.put(new CType("GLclampx"), new JType("int")); typeMapping.put(new CType("GLenum"), new JType("int")); typeMapping.put(new CType("GLfloat"), new JType("float")); typeMapping.put(new CType("GLfixed"), new JType("int")); typeMapping.put(new CType("GLint"), new JType("int")); typeMapping.put(new CType("GLintptr"), new JType("int")); typeMapping.put(new CType("GLshort"), new JType("short")); typeMapping.put(new CType("GLsizei"), new JType("int")); typeMapping.put(new CType("GLsizeiptr"), new JType("int")); typeMapping.put(new CType("GLubyte"), new JType("byte")); typeMapping.put(new CType("GLuint"), new JType("int")); typeMapping.put(new CType("void"), new JType("void")); typeMapping.put(new CType("GLubyte", true, true), new JType("String", false, false)); typeMapping.put(new CType("char"), new JType("byte")); typeMapping.put(new CType("char", true, true), new JType("String", false, false)); typeMapping.put(new CType("GLchar", true, true), new JType("String", false, false)); typeMapping.put(new CType("int"), new JType("int")); typeMapping.put(new CType("GLuint64"), new JType("long")); typeMapping.put(new CType("GLsync"), new JType("long")); // EGL primitive types typeMapping.put(new CType("EGLint"), new JType("int")); typeMapping.put(new CType("EGLBoolean"), new JType("boolean")); typeMapping.put(new CType("EGLenum"), new JType("int")); typeMapping.put(new CType("EGLNativePixmapType"), new JType("int")); typeMapping.put(new CType("EGLNativeWindowType"), new JType("int")); typeMapping.put(new CType("EGLNativeDisplayType"), new JType("long")); typeMapping.put(new CType("EGLClientBuffer"), new JType("long")); typeMapping.put(new CType("EGLnsecsANDROID"), new JType("long")); // EGL nonprimitive types typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false)); typeMapping.put(new CType("EGLContext"), new JType("EGLContext", true, false)); typeMapping.put(new CType("EGLDisplay"), new JType("EGLDisplay", true, false)); typeMapping.put(new CType("EGLSurface"), new JType("EGLSurface", true, false)); // Untyped pointers map to untyped Buffers typeMapping.put(new CType("GLvoid", true, true), new JType("java.nio.Buffer", true, false)); typeMapping.put(new CType("GLvoid", false, true), new JType("java.nio.Buffer", true, false)); typeMapping.put(new CType("void", false, true), new JType("java.nio.Buffer", true, false)); typeMapping.put(new CType("void", true, true), new JType("java.nio.Buffer", true, false)); typeMapping.put(new CType("GLeglImageOES", false, false), new JType("java.nio.Buffer", true, false)); // Typed pointers map to typed Buffers typeMapping.put(new CType("GLboolean", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLenum", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLenum", true, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLfixed", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLfixed", true, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLfloat", false, true), new JType("java.nio.FloatBuffer", true, false)); typeMapping.put(new CType("GLfloat", true, true), new JType("java.nio.FloatBuffer", true, false)); typeMapping.put(new CType("GLint", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLint", true, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLsizei", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLuint", false, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLuint", true, true), new JType("java.nio.IntBuffer", true, false)); typeMapping.put(new CType("GLshort", true, true), new JType("java.nio.ShortBuffer", true, false)); typeMapping.put(new CType("GLint64", false, true), new JType("java.nio.LongBuffer", true, false)); // Typed pointers map to arrays + offsets arrayTypeMapping.put(new CType("char", false, true), new JType("byte", false, true)); arrayTypeMapping.put(new CType("GLchar", false, true), new JType("byte", false, true)); arrayTypeMapping.put(new CType("GLboolean", false, true), new JType("boolean", false, true)); arrayTypeMapping.put(new CType("GLenum", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLenum", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true)); arrayTypeMapping.put(new CType("GLfloat", true, true), new JType("float", false, true)); arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true)); arrayTypeMapping.put(new CType("GLsizei", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLsizei", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLint64", false, true), new JType("long", false, true)); //EGL typed pointers map to arrays + offsets arrayTypeMapping.put(new CType("EGLint", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("EGLint", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("EGLConfig", false, true), new JType("EGLConfig", true, true)); arrayTypeMapping.put(new CType("EGLConfig", true, true), new JType("EGLConfig", true, true)); } public JType() { } public JType(String primitiveTypeName) { this.baseType = primitiveTypeName; this.isClass = false; this.isArray = false; } public JType(String primitiveTypeName, boolean isClass, boolean isArray) { this.baseType = primitiveTypeName; this.isClass = isClass; this.isArray = isArray; } public String getBaseType() { return baseType; } @Override public String toString() { return baseType + (isArray ? "[]" : ""); } public boolean isArray() { return isArray; } public boolean isClass() { return isClass; } public boolean isString() { return baseType.equals("String"); } public boolean isPrimitive() { return !isClass() && !isArray(); } public boolean isVoid() { return baseType.equals("void"); } public boolean isBuffer() { return baseType.indexOf("Buffer") != -1; } public boolean isTypedBuffer() { return !baseType.equals("java.nio.Buffer") && (baseType.indexOf("Buffer") != -1); } public JType getArrayTypeForTypedBuffer() { if (!isTypedBuffer()) { throw new RuntimeException("Not typed buffer type " + this); } switch (baseType) { case "java.nio.ByteBuffer": return new JType("byte", false, true); case "java.nio.BooleanBuffer": return new JType("boolean", false, true); case "java.nio.ShortBuffer": return new JType("short", false, true); case "java.nio.CharBuffer": return new JType("char", false, true); case "java.nio.IntBuffer": return new JType("int", false, true); case "java.nio.LongBuffer": return new JType("long", false, true); case "java.nio.FloatBuffer": return new JType("float", false, true); case "java.nio.DoubleBuffer": return new JType("double", false, true); default: throw new RuntimeException("Unknown typed buffer type " + this); } } public String getArrayGetterForPrimitiveArray() { if (!isArray() || isClass()) { throw new RuntimeException("Not array type " + this); } switch (baseType) { case "byte": return "GetByteArrayElements"; case "boolean": return "GetBooleanArrayElements"; case "short": return "GetShortArrayElements"; case "char": return "GetCharArrayElements"; case "int": return "GetIntArrayElements"; case "long": return "GetLongArrayElements"; case "float": return "GetFloatArrayElements"; case "double": return "GetDoubleArrayElements"; default: throw new RuntimeException("Unknown array type " + this); } } public String getArrayReleaserForPrimitiveArray() { if (!isArray() || isClass()) { throw new RuntimeException("Not array type " + this); } switch (baseType) { case "byte": return "ReleaseByteArrayElements"; case "boolean": return "ReleaseBooleanArrayElements"; case "short": return "ReleaseShortArrayElements"; case "char": return "ReleaseCharArrayElements"; case "int": return "ReleaseIntArrayElements"; case "long": return "ReleaseLongArrayElements"; case "float": return "ReleaseFloatArrayElements"; case "double": return "ReleaseDoubleArrayElements"; default: throw new RuntimeException("Unknown array type " + this); } } public boolean isEGLHandle() { return !isPrimitive() && (baseType.startsWith("EGL")); } public static JType convert(CType ctype, boolean useArray) { JType javaType = null; if (useArray) { javaType = arrayTypeMapping.get(ctype); } if (javaType == null) { javaType = typeMapping.get(ctype); } if (javaType == null) { throw new RuntimeException("Unsupported C type: " + ctype); } return javaType; } } opengl/tools/glgen/src/JniCodeEmitter.java0100644 0000000 0000000 00000200317 13077405420 017631 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.io.PrintStream; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; public class JniCodeEmitter { static final boolean mUseCPlusPlus = true; protected boolean mUseContextPointer = true; protected boolean mUseStaticMethods = false; protected boolean mUseSimpleMethodNames = false; protected boolean mUseHideCommentForAPI = false; protected String mClassPathName; protected ParameterChecker mChecker; protected List nativeRegistrations = new ArrayList(); boolean needsExit; protected static String indent = " "; HashSet mFunctionsEmitted = new HashSet(); public static String getJniName(JType jType) { String jniName = ""; if (jType.isEGLHandle()) { return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";"; } else if (jType.isClass()) { return "L" + jType.getBaseType() + ";"; } else if (jType.isArray()) { jniName = "["; } String baseType = jType.getBaseType(); if (baseType.equals("int")) { jniName += "I"; } else if (baseType.equals("float")) { jniName += "F"; } else if (baseType.equals("boolean")) { jniName += "Z"; } else if (baseType.equals("short")) { jniName += "S"; } else if (baseType.equals("long")) { jniName += "J"; } else if (baseType.equals("byte")) { jniName += "B"; } else if (baseType.equals("String")) { jniName += "Ljava/lang/String;"; } else if (baseType.equals("void")) { // nothing. } else { throw new RuntimeException("Unknown primitive basetype " + baseType); } return jniName; } public void emitCode(CFunc cfunc, String original, PrintStream javaInterfaceStream, PrintStream javaImplStream, PrintStream cStream) { JFunc jfunc; String signature; boolean duplicate; if (cfunc.hasTypedPointerArg()) { jfunc = JFunc.convert(cfunc, true); // Don't emit duplicate functions // These may appear because they are defined in multiple // Java interfaces (e.g., GL11/GL11ExtensionPack) signature = jfunc.toString(); duplicate = false; if (mFunctionsEmitted.contains(signature)) { duplicate = true; } else { mFunctionsEmitted.add(signature); } if (!duplicate) { emitNativeDeclaration(jfunc, javaImplStream); emitJavaCode(jfunc, javaImplStream); } if (javaInterfaceStream != null) { emitJavaInterfaceCode(jfunc, javaInterfaceStream); } if (!duplicate) { emitJniCode(jfunc, cStream); } // Don't create IOBuffer versions of the EGL functions if (cfunc.hasEGLHandleArg()) { return; } } jfunc = JFunc.convert(cfunc, false); signature = jfunc.toString(); duplicate = false; if (mFunctionsEmitted.contains(signature)) { duplicate = true; } else { mFunctionsEmitted.add(signature); } if (!duplicate) { emitNativeDeclaration(jfunc, javaImplStream); } if (javaInterfaceStream != null) { emitJavaInterfaceCode(jfunc, javaInterfaceStream); } if (!duplicate) { emitJavaCode(jfunc, javaImplStream); emitJniCode(jfunc, cStream); } } public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { if (mUseHideCommentForAPI) { out.println(" /* @hide C function " + jfunc.getCFunc().getOriginal() + " */"); out.println(); } else { out.println(" // C function " + jfunc.getCFunc().getOriginal()); out.println(); } emitFunction(jfunc, out, true, false); } public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { emitFunction(jfunc, out, false, true); } public void emitJavaCode(JFunc jfunc, PrintStream out) { emitFunction(jfunc, out, false, false); } boolean isPointerFunc(JFunc jfunc) { String name = jfunc.getName(); return (name.endsWith("Pointer") || name.endsWith("PointerOES")) && jfunc.getCFunc().hasPointerArg(); } void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { boolean isVoid = jfunc.getType().isVoid(); boolean isPointerFunc = isPointerFunc(jfunc); if (!isVoid) { out.println(iii + jfunc.getType() + " _returnValue;"); } out.println(iii + (isVoid ? "" : "_returnValue = ") + jfunc.getName() + (isPointerFunc ? "Bounds" : "" ) + "("); int numArgs = jfunc.getNumArgs(); for (int i = 0; i < numArgs; i++) { String argName = jfunc.getArgName(i); JType argType = jfunc.getArgType(i); if (grabArray && argType.isTypedBuffer()) { String typeName = argType.getBaseType(); typeName = typeName.substring(9, typeName.length() - 6); out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); out.print(iii + indent + "getOffset(" + argName + ")"); } else { out.print(iii + indent + argName); } if (i == numArgs - 1) { if (isPointerFunc) { out.println(","); out.println(iii + indent + argName + ".remaining()"); } else { out.println(); } } else { out.println(","); } } out.println(iii + ");"); } void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String iii) { printIfcheckPostamble(out, isBuffer, emitExceptionCheck, "offset", "_remaining", iii); } void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { out.println(iii + " default:"); out.println(iii + " _needed = 1;"); out.println(iii + " break;"); out.println(iii + "}"); out.println(iii + "if (" + remaining + " < _needed) {"); out.println(iii + indent + "_exception = 1;"); out.println(iii + indent + "_exceptionType = \"java/lang/IllegalArgumentException\";"); out.println(iii + indent + "_exceptionMessage = \"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\";"); out.println(iii + indent + "goto exit;"); out.println(iii + "}"); needsExit = true; } boolean isNullAllowed(CFunc cfunc, String cname) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].equals("nullAllowed") && checks[index + 1].equals(cname)) { return true; } else { index = skipOneCheck(checks, index); } } } return false; } boolean hasCheckTest(CFunc cfunc) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("check")) { return true; } else { index = skipOneCheck(checks, index); } } } return false; } boolean hasCheckTest(CFunc cfunc, String cname) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("check") && cname != null && cname.equals(checks[index + 1])) { return true; } else { index = skipOneCheck(checks, index); } } } return false; } boolean hasIfTest(CFunc cfunc) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("ifcheck")) { return true; } else { index = skipOneCheck(checks, index); } } } return false; } int skipOneCheck(String[] checks, int index) { if (checks[index].equals("return")) { index += 2; } else if (checks[index].startsWith("check")) { index += 3; } else if (checks[index].startsWith("sentinel")) { index += 3; } else if (checks[index].equals("ifcheck")) { index += 5; } else if (checks[index].equals("unsupported")) { index += 1; } else if (checks[index].equals("requires")) { index += 2; } else if (checks[index].equals("nullAllowed")) { index += 2; } else { System.out.println("Error: unknown keyword \"" + checks[index] + "\""); System.exit(0); } return index; } String getErrorReturnValue(CFunc cfunc) { CType returnType = cfunc.getType(); boolean isVoid = returnType.isVoid(); if (isVoid) { return null; } if (returnType.getBaseType().startsWith("EGL")) { return "(" + returnType.getDeclaration() + ") 0"; } String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].equals("return")) { return checks[index + 1]; } else { index = skipOneCheck(checks, index); } } } return null; } boolean isUnsupportedFunc(CFunc cfunc) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].equals("unsupported")) { return true; } else { index = skipOneCheck(checks, index); } } } return false; } String isRequiresFunc(CFunc cfunc) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].equals("requires")) { return checks[index+1]; } else { index = skipOneCheck(checks, index); } } } return null; } void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { String[] checks = mChecker.getChecks(cfunc.getName()); boolean lastWasIfcheck = false; int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("check")) { if (lastWasIfcheck) { printIfcheckPostamble(out, isBuffer, emitExceptionCheck, offset, remaining, iii); } lastWasIfcheck = false; if (cname != null && !cname.equals(checks[index + 1])) { index += 3; continue; } out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); out.println(iii + indent + "_exception = 1;"); String exceptionClassName = "java/lang/IllegalArgumentException"; // If the "check" keyword was of the form // "check_", use the class name in the // exception to be thrown int underscore = checks[index].indexOf('_'); if (underscore >= 0) { String abbr = checks[index].substring(underscore + 1); if (abbr.equals("AIOOBE")) { exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException"; } else { throw new RuntimeException("unknown exception abbreviation: " + abbr); } } out.println(iii + indent + "_exceptionType = \""+exceptionClassName+"\";"); out.println(iii + indent + "_exceptionMessage = \"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + " < needed\";"); out.println(iii + indent + "goto exit;"); out.println(iii + "}"); needsExit = true; index += 3; } else if (checks[index].equals("ifcheck")) { String[] matches = checks[index + 4].split(","); if (!lastWasIfcheck) { out.println(iii + "int _needed;"); out.println(iii + "switch (" + checks[index + 3] + ") {"); } for (int i = 0; i < matches.length; i++) { out.println("#if defined(" + matches[i] + ")"); out.println(iii + " case " + matches[i] + ":"); out.println("#endif // defined(" + matches[i] + ")"); } out.println(iii + " _needed = " + checks[index + 2] + ";"); out.println(iii + " break;"); lastWasIfcheck = true; index += 5; } else { index = skipOneCheck(checks, index); } } } if (lastWasIfcheck) { printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); } } void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("sentinel")) { if (cname != null && !cname.equals(checks[index + 1])) { index += 3; continue; } out.println(iii + cname + "_sentinel = false;"); out.println(iii + "for (int i = " + remaining + " - 1; i >= 0; i--) {"); out.println(iii + indent + "if (" + cname + "[i] == " + checks[index + 2] + "){"); out.println(iii + indent + indent + cname + "_sentinel = true;"); out.println(iii + indent + indent + "break;"); out.println(iii + indent + "}"); out.println(iii + "}"); out.println(iii + "if (" + cname + "_sentinel == false) {"); out.println(iii + indent + "_exception = 1;"); out.println(iii + indent + "_exceptionType = \"java/lang/IllegalArgumentException\";"); out.println(iii + indent + "_exceptionMessage = \"" + cname + " must contain " + checks[index + 2] + "!\";"); out.println(iii + indent + "goto exit;"); out.println(iii + "}"); needsExit = true; index += 3; } else { index = skipOneCheck(checks, index); } } } } void emitStringCheck(CFunc cfunc, String cname, PrintStream out, String iii) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("check")) { if (cname != null && !cname.equals(checks[index + 1])) { index += 3; continue; } out.println(iii + "_stringlen = _env->GetStringUTFLength(" + cname + ");"); out.println(iii + "if (" + checks[index + 2] + " > _stringlen) {"); out.println(iii + indent + "_exception = 1;"); out.println(iii + indent + "_exceptionType = \"java/lang/ArrayIndexOutOfBoundsException\";"); out.println(iii + indent + "_exceptionMessage = \"length of " + cname + " is shorter than " + checks[index + 2] + " argument\";"); out.println(iii + indent + "goto exit;"); out.println(iii + "}"); index += 3; needsExit = true; } else { index = skipOneCheck(checks, index); } } } } void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; if (checks != null) { while (index < checks.length) { if (checks[index].startsWith("sentinel")) { String cname = checks[index + 1]; out.println(indent + "bool " + cname + "_sentinel = false;"); index += 3; } else { index = skipOneCheck(checks, index); } } } } boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List nonPrimitiveArgs) { if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); if (jfunc.getArgType(idx).isArray()) { if (!cfunc.getArgType(cIndex).isConst()) { return true; } } else if (jfunc.getArgType(idx).isBuffer()) { if (!cfunc.getArgType(cIndex).isConst()) { return true; } } } } return false; } /** * Emit a function in several variants: * * if nativeDecl: public native func(args); * * if !nativeDecl: * if interfaceDecl: public func(args); * if !interfaceDecl: public func(args) { body } */ void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { boolean isPointerFunc = isPointerFunc(jfunc); if (!nativeDecl && !interfaceDecl && !isPointerFunc) { // If it's not a pointer function, we've already emitted it // with nativeDecl == true return; } String maybeStatic = mUseStaticMethods ? "static " : ""; if (isPointerFunc) { out.println(indent + (nativeDecl ? "private " + maybeStatic +"native " : (interfaceDecl ? "" : "public ") + maybeStatic) + jfunc.getType() + " " + jfunc.getName() + (nativeDecl ? "Bounds" : "") + "("); } else { out.println(indent + (nativeDecl ? "public " + maybeStatic +"native " : (interfaceDecl ? "" : "public ") + maybeStatic) + jfunc.getType() + " " + jfunc.getName() + "("); } int numArgs = jfunc.getNumArgs(); for (int i = 0; i < numArgs; i++) { String argName = jfunc.getArgName(i); JType argType = jfunc.getArgType(i); out.print(indent + indent + argType + " " + argName); if (i == numArgs - 1) { if (isPointerFunc && nativeDecl) { out.println(","); out.println(indent + indent + "int remaining"); } else { out.println(); } } else { out.println(","); } } if (nativeDecl || interfaceDecl) { out.println(indent + ");"); } else { out.println(indent + ") {"); String iii = indent + indent; // emitBoundsChecks(jfunc, out, iii); emitFunctionCall(jfunc, out, iii, false); // Set the pointer after we call the native code, so that if // the native code throws an exception we don't modify the // pointer. We assume that the native code is written so that // if an exception is thrown, then the underlying glXXXPointer // function will not have been called. String fname = jfunc.getName(); if (isPointerFunc) { // TODO - deal with VBO variants if (fname.equals("glColorPointer")) { out.println(iii + "if ((size == 4) &&"); out.println(iii + " ((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_colorPointer = pointer;"); out.println(iii + "}"); } else if (fname.equals("glNormalPointer")) { out.println(iii + "if (((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_BYTE) ||"); out.println(iii + " (type == GL_SHORT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_normalPointer = pointer;"); out.println(iii + "}"); } else if (fname.equals("glTexCoordPointer")) { out.println(iii + "if (((size == 2) ||"); out.println(iii + " (size == 3) ||"); out.println(iii + " (size == 4)) &&"); out.println(iii + " ((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_BYTE) ||"); out.println(iii + " (type == GL_SHORT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_texCoordPointer = pointer;"); out.println(iii + "}"); } else if (fname.equals("glVertexPointer")) { out.println(iii + "if (((size == 2) ||"); out.println(iii + " (size == 3) ||"); out.println(iii + " (size == 4)) &&"); out.println(iii + " ((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_BYTE) ||"); out.println(iii + " (type == GL_SHORT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_vertexPointer = pointer;"); out.println(iii + "}"); } else if (fname.equals("glPointSizePointerOES")) { out.println(iii + "if (((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_pointSizePointerOES = pointer;"); out.println(iii + "}"); } else if (fname.equals("glMatrixIndexPointerOES")) { out.println(iii + "if (((size == 2) ||"); out.println(iii + " (size == 3) ||"); out.println(iii + " (size == 4)) &&"); out.println(iii + " ((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_BYTE) ||"); out.println(iii + " (type == GL_SHORT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_matrixIndexPointerOES = pointer;"); out.println(iii + "}"); } else if (fname.equals("glWeightPointer")) { out.println(iii + "if (((size == 2) ||"); out.println(iii + " (size == 3) ||"); out.println(iii + " (size == 4)) &&"); out.println(iii + " ((type == GL_FLOAT) ||"); out.println(iii + " (type == GL_BYTE) ||"); out.println(iii + " (type == GL_SHORT) ||"); out.println(iii + " (type == GL_FIXED)) &&"); out.println(iii + " (stride >= 0)) {"); out.println(iii + indent + "_weightPointerOES = pointer;"); out.println(iii + "}"); } } boolean isVoid = jfunc.getType().isVoid(); if (!isVoid) { out.println(indent + indent + "return _returnValue;"); } out.println(indent + "}"); } out.println(); } public void addNativeRegistration(String s) { nativeRegistrations.add(s); } public void emitNativeRegistration(String registrationFunctionName, PrintStream cStream) { cStream.println("static const char *classPathName = \"" + mClassPathName + "\";"); cStream.println(); cStream.println("static const JNINativeMethod methods[] = {"); cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); Iterator i = nativeRegistrations.iterator(); while (i.hasNext()) { cStream.println(i.next()); } cStream.println("};"); cStream.println(); cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); cStream.println("{"); cStream.println(indent + "int err;"); cStream.println(indent + "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); cStream.println(indent + "return err;"); cStream.println("}"); } public JniCodeEmitter() { super(); } String getJniType(JType jType) { if (jType.isVoid()) { return "void"; } String baseType = jType.getBaseType(); if (jType.isPrimitive()) { if (baseType.equals("String")) { return "jstring"; } else { return "j" + baseType; } } else if (jType.isArray()) { return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; } else { return "jobject"; } } String getJniMangledName(String name) { name = name.replaceAll("_", "_1"); name = name.replaceAll(";", "_2"); name = name.replaceAll("\\[", "_3"); return name; } public void emitJniCode(JFunc jfunc, PrintStream out) { CFunc cfunc = jfunc.getCFunc(); // Emit comment identifying original C function // // Example: // // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ // out.println("/* " + cfunc.getOriginal() + " */"); // Emit JNI signature (name) // // Example: // // void // android_glClipPlanef__I_3FI // String outName = "android_" + jfunc.getName(); boolean isPointerFunc = isPointerFunc(jfunc); boolean isPointerOffsetFunc = (outName.endsWith("Pointer") || outName.endsWith("PointerOES") || outName.endsWith("glDrawElements") || outName.endsWith("glDrawRangeElements") || outName.endsWith("glTexImage2D") || outName.endsWith("glTexSubImage2D") || outName.endsWith("glCompressedTexImage2D") || outName.endsWith("glCompressedTexSubImage2D") || outName.endsWith("glTexImage3D") || outName.endsWith("glTexSubImage3D") || outName.endsWith("glCompressedTexImage3D") || outName.endsWith("glCompressedTexSubImage3D") || outName.endsWith("glReadPixels")) && !jfunc.getCFunc().hasPointerArg(); if (isPointerFunc) { outName += "Bounds"; } out.print("static "); out.println(getJniType(jfunc.getType())); out.print(outName); String rsignature = getJniName(jfunc.getType()); String signature = ""; int numArgs = jfunc.getNumArgs(); for (int i = 0; i < numArgs; i++) { JType argType = jfunc.getArgType(i); signature += getJniName(argType); } if (isPointerFunc) { signature += "I"; } // Append signature to function name String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); if (!mUseSimpleMethodNames) { out.print("__" + sig); outName += "__" + sig; } signature = signature.replace('.', '/'); rsignature = rsignature.replace('.', '/'); out.println(); if (rsignature.length() == 0) { rsignature = "V"; } String s = "{\"" + jfunc.getName() + (isPointerFunc ? "Bounds" : "") + "\", \"(" + signature +")" + rsignature + "\", (void *) " + outName + " },"; nativeRegistrations.add(s); List nonPrimitiveArgs = new ArrayList(); List stringArgs = new ArrayList(); int numBufferArgs = 0; List bufferArgNames = new ArrayList(); List bufferArgTypes = new ArrayList(); // Emit JNI signature (arguments) // // Example: // // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { // out.print(" (JNIEnv *_env, jobject _this"); for (int i = 0; i < numArgs; i++) { out.print(", "); JType argType = jfunc.getArgType(i); String suffix = ""; if (!argType.isPrimitive()) { if (argType.isArray()) { suffix = "_ref"; } else if (argType.isBuffer()) { suffix = "_buf"; } nonPrimitiveArgs.add(new Integer(i)); if (jfunc.getArgType(i).isBuffer()) { int cIndex = jfunc.getArgCIndex(i); String cname = cfunc.getArgName(cIndex); bufferArgNames.add(cname); bufferArgTypes.add(jfunc.getArgType(i)); numBufferArgs++; } } if (argType.isString()) { stringArgs.add(new Integer(i)); } out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); } if (isPointerFunc) { out.print(", jint remaining"); } out.println(") {"); int numArrays = 0; int numBuffers = 0; int numStrings = 0; for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); JType argType = jfunc.getArgType(idx); if (argType.isArray()) { ++numArrays; } if (argType.isBuffer()) { ++numBuffers; } if (argType.isString()) { ++numStrings; } } // Emit method body // Emit local variable declarations for _exception and _returnValue // // Example: // // android::gl::ogles_context_t *ctx; // // jint _exception; // GLenum _returnValue; // CType returnType = cfunc.getType(); boolean isVoid = returnType.isVoid(); boolean isUnsupported = isUnsupportedFunc(cfunc); if (isUnsupported) { out.println(indent + "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); out.println(indent + " \"" + cfunc.getName() + "\");"); if (!isVoid) { String retval = getErrorReturnValue(cfunc); if (cfunc.getType().isEGLHandle()) { String baseType = cfunc.getType().getBaseType().toLowerCase(); out.println(indent + "return toEGLHandle(_env, " + baseType + "Class, " + baseType + "Constructor, " + retval + ");"); } else { out.println(indent + "return " + retval + ";"); } } out.println("}"); out.println(); return; } String requiresExtension = isRequiresFunc(cfunc); if (requiresExtension != null) { out.println(indent + "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); out.println(indent + indent + "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); out.println(indent + indent + " \"" + cfunc.getName() + "\");"); if (isVoid) { out.println(indent + indent + " return;"); } else { String retval = getErrorReturnValue(cfunc); if (cfunc.getType().isEGLHandle()) { String baseType = cfunc.getType().getBaseType().toLowerCase(); out.println(indent + "return toEGLHandle(_env, " + baseType + "Class, " + baseType + "Constructor, " + retval + ");"); } else { out.println(indent + "return " + retval + ";"); } } out.println(indent + "}"); } if (mUseContextPointer) { out.println(indent + "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); } boolean initializeReturnValue = stringArgs.size() > 0; boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) || (cfunc.hasPointerArg() && numArrays > 0)) || hasCheckTest(cfunc) || hasIfTest(cfunc)) || (stringArgs.size() > 0); // mChecker.getChecks(cfunc.getName()) != null // Emit an _exeption variable if there will be error checks if (emitExceptionCheck) { out.println(indent + "jint _exception = 0;"); out.println(indent + "const char * _exceptionType = NULL;"); out.println(indent + "const char * _exceptionMessage = NULL;"); } // Emit a single _array or multiple _XXXArray variables if (numBufferArgs == 1) { JType bufferType = bufferArgTypes.get(0); if (bufferType.isTypedBuffer()) { String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;"); } else { out.println(indent + "jarray _array = (jarray) 0;"); } out.println(indent + "jint _bufferOffset = (jint) 0;"); } else { for (int i = 0; i < numBufferArgs; i++) { JType bufferType = bufferArgTypes.get(0); if (bufferType.isTypedBuffer()) { String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) + "Array = (" + typedArrayType + ") 0;"); } else { out.println(indent + "jarray _" + bufferArgNames.get(i) + "Array = (jarray) 0;"); } out.println(indent + "jint _" + bufferArgNames.get(i) + "BufferOffset = (jint) 0;"); } } if (!isVoid) { String retval = getErrorReturnValue(cfunc); if (retval != null) { out.println(indent + returnType.getDeclaration() + " _returnValue = " + retval + ";"); } else if (initializeReturnValue) { out.println(indent + returnType.getDeclaration() + " _returnValue = 0;"); } else { out.println(indent + returnType.getDeclaration() + " _returnValue;"); } } // Emit local variable declarations for EGL Handles // // Example: // // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); // if (nonPrimitiveArgs.size() > 0) { for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); if (jfunc.getArgType(idx).isBuffer() || jfunc.getArgType(idx).isArray() || !jfunc.getArgType(idx).isEGLHandle()) continue; CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); out.println(indent + decl + " " + cname + "_native = (" + decl + ") fromEGLHandle(_env, " + type.getBaseType().toLowerCase() + "GetHandleID, " + jfunc.getArgName(idx) + ");"); } } // Emit local variable declarations for element/sentinel checks // // Example: // // bool attrib_list_sentinel_found = false; // emitLocalVariablesForSentinel(cfunc, out); // Emit local variable declarations for pointer arguments // // Example: // // GLfixed *eqn_base; // GLfixed *eqn; // String offset = "offset"; String remaining = "_remaining"; if (nonPrimitiveArgs.size() > 0) { for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) continue; CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { out.println(indent + decl + (decl.endsWith("*") ? "" : " ") + jfunc.getArgName(idx) + "_base = (" + decl + ") 0;"); } remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : "_" + cname + "Remaining"; out.println(indent + "jint " + remaining + ";"); out.println(indent + decl + (decl.endsWith("*") ? "" : " ") + jfunc.getArgName(idx) + " = (" + decl + ") 0;"); } out.println(); } // Emit local variable declaration for strings if (stringArgs.size() > 0) { boolean requiresStringLengthCheck = false; for (int i = 0; i < stringArgs.size(); i++) { int idx = stringArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); out.println(indent + "const char* _native" + cname + " = 0;"); if (hasCheckTest(cfunc, cname)) { requiresStringLengthCheck = true; } } if (requiresStringLengthCheck) { out.println(indent + "jsize _stringlen = 0;"); } out.println(); } // Null pointer checks and GetStringUTFChars if (stringArgs.size() > 0) { for (int i = 0; i < stringArgs.size(); i++) { int idx = stringArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); boolean nullAllowed = isNullAllowed(cfunc, cname); String nullAllowedIndent = nullAllowed ? indent : ""; CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); if (nullAllowed) { out.println(indent + "if (" + cname + ") {"); } else { needsExit = true; out.println(indent + "if (!" + cname + ") {"); out.println(indent + indent + "_exception = 1;"); out.println(indent + indent + "_exceptionType = \"java/lang/IllegalArgumentException\";"); out.println(indent + indent + "_exceptionMessage = \"" + cname + " == null\";"); out.println(indent + indent + "goto exit;"); out.println(indent + "}"); } out.println(nullAllowedIndent + indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); emitStringCheck(cfunc, cname, out, nullAllowedIndent + indent); if (nullAllowed) { out.println(indent + "}"); } } out.println(); } // Emit 'GetPrimitiveArrayCritical' for non-object arrays // Emit 'GetPointer' calls for Buffer pointers if (nonPrimitiveArgs.size() > 0) { for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); offset = numArrays <= 1 ? "offset" : cname + "Offset"; remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : "_" + cname + "Remaining"; boolean nullAllowed = isNullAllowed(cfunc, cname); String nullAllowedIndent = nullAllowed ? indent : ""; if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isEGLHandle()) { needsExit = true; if (nullAllowed) { out.println(indent + "if (" + cname + "_ref) {"); } else { out.println(indent + "if (!" + cname + "_ref) {"); out.println(indent + indent + "_exception = 1;"); out.println(indent + indent + "_exceptionType = " + "\"java/lang/IllegalArgumentException\";"); out.println(indent + indent + "_exceptionMessage = \"" + cname + " == null\";"); out.println(indent + indent + "goto exit;"); out.println(indent + "}"); } out.println(nullAllowedIndent + indent + "if (" + offset + " < 0) {"); out.println(nullAllowedIndent + indent + indent + "_exception = 1;"); out.println(nullAllowedIndent + indent + indent + "_exceptionType = " + "\"java/lang/IllegalArgumentException\";"); out.println(nullAllowedIndent + indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); out.println(nullAllowedIndent + indent + indent + "goto exit;"); out.println(nullAllowedIndent + indent + "}"); out.println(nullAllowedIndent + indent + remaining + " = " + (mUseCPlusPlus ? "_env" : "(*_env)") + "->GetArrayLength(" + (mUseCPlusPlus ? "" : "_env, ") + cname + "_ref) - " + offset + ";"); emitNativeBoundsChecks(cfunc, cname, out, false, emitExceptionCheck, offset, remaining, nullAllowedIndent + indent); out.println(nullAllowedIndent + indent + cname + "_base = (" + cfunc.getArgType(cIndex).getDeclaration() + ")"); String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray(); out.println(nullAllowedIndent + indent + " " + (mUseCPlusPlus ? "_env" : "(*_env)") + "->" + arrayGetter + "(" + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, (jboolean *)0);"); out.println(nullAllowedIndent + indent + cname + " = " + cname + "_base + " + offset + ";"); emitSentinelCheck(cfunc, cname, out, false, emitExceptionCheck, offset, remaining, nullAllowedIndent + indent); if (nullAllowed) { out.println(indent + "}"); } out.println(); } else if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isEGLHandle()) { needsExit = true; if (nullAllowed) { out.println(indent + "if (" + cname + "_ref) {"); } else { out.println(indent + "if (!" + cname + "_ref) {"); out.println(indent + indent + "_exception = 1;"); out.println(indent + indent + "_exceptionType = " + "\"java/lang/IllegalArgumentException\";"); out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); out.println(indent + indent + "goto exit;"); out.println(indent + "}"); } out.println(nullAllowedIndent + indent + "if (" + offset + " < 0) {"); out.println(nullAllowedIndent + indent + indent + "_exception = 1;"); out.println(nullAllowedIndent + indent + indent + "_exceptionType = " + "\"java/lang/IllegalArgumentException\";"); out.println(nullAllowedIndent + indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); out.println(nullAllowedIndent + indent + indent + "goto exit;"); out.println(nullAllowedIndent + indent + "}"); out.println(nullAllowedIndent + indent + remaining + " = " + (mUseCPlusPlus ? "_env" : "(*_env)") + "->GetArrayLength(" + (mUseCPlusPlus ? "" : "_env, ") + cname + "_ref) - " + offset + ";"); emitNativeBoundsChecks(cfunc, cname, out, false, emitExceptionCheck, offset, remaining, nullAllowedIndent + indent); out.println(nullAllowedIndent + indent + jfunc.getArgName(idx) + " = new " + cfunc.getArgType(cIndex).getBaseType() + "["+ remaining + "];"); if (nullAllowed) { out.println(indent + "}"); } out.println(); } else if (jfunc.getArgType(idx).isBuffer()) { String array = numBufferArgs <= 1 ? "_array" : "_" + cfunc.getArgName(cIndex) + "Array"; String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : "_" + cfunc.getArgName(cIndex) + "BufferOffset"; nullAllowed = nullAllowed || isPointerFunc; if (nullAllowed) { out.println(indent + "if (" + cname + "_buf) {"); out.print(indent); } if (isPointerFunc) { out.println(indent + cname + " = (" + cfunc.getArgType(cIndex).getDeclaration() + ") getDirectBufferPointer(_env, " + cname + "_buf);"); String iii = " "; out.println(iii + indent + "if ( ! " + cname + " ) {"); out.println(iii + indent + indent + "return;"); out.println(iii + indent + "}"); } else { out.println(indent + cname + " = (" + cfunc.getArgType(cIndex).getDeclaration() + ")getPointer(_env, " + cname + "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset + ");"); } emitNativeBoundsChecks(cfunc, cname, out, true, emitExceptionCheck, offset, remaining, nullAllowed ? " " : " "); if (nullAllowed) { out.println(indent + "}"); } } } } // Emit 'GetPrimitiveArrayCritical' for pointers if needed if (nonPrimitiveArgs.size() > 0) { for (int i = 0; i < nonPrimitiveArgs.size(); i++) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; String cname = cfunc.getArgName(cIndex); String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : "_" + cname + "BufferOffset"; String array = numBufferArgs <= 1 ? "_array" : "_" + cfunc.getArgName(cIndex) + "Array"; boolean nullAllowed = isNullAllowed(cfunc, cname) || isPointerFunc; if (nullAllowed) { out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); } else { out.println(indent + "if (" + cname +" == NULL) {"); } JType argType = jfunc.getArgType(idx); if (argType.isTypedBuffer()) { String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray(); out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);"); out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); out.println(indent + "}"); } else { out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); out.println(indent + "}"); } } } if (!isVoid) { out.print(indent + "_returnValue = "); } else { out.print(indent); } String name = cfunc.getName(); if (mUseContextPointer) { name = name.substring(2, name.length()); // Strip off 'gl' prefix name = name.substring(0, 1).toLowerCase() + name.substring(1, name.length()); out.print("ctx->procs."); } out.print(name + (isPointerFunc ? "Bounds" : "") + "("); numArgs = cfunc.getNumArgs(); if (numArgs == 0) { if (mUseContextPointer) { out.println("ctx);"); } else { out.println(");"); } } else { if (mUseContextPointer) { out.println("ctx,"); } else { out.println(); } for (int i = 0; i < numArgs; i++) { String typecast; if (i == numArgs - 1 && isPointerOffsetFunc) { typecast = "reinterpret_cast"; } else { typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; } out.print(indent + indent + typecast); if (cfunc.getArgType(i).isConstCharPointer()) { out.print("_native"); } if (cfunc.getArgType(i).isEGLHandle() && !cfunc.getArgType(i).isPointer()){ out.print(cfunc.getArgName(i)+"_native"); } else if (i == numArgs - 1 && isPointerOffsetFunc){ out.print("("+cfunc.getArgName(i)+")"); } else { out.print(cfunc.getArgName(i)); } if (i == numArgs - 1) { if (isPointerFunc) { out.println(","); out.println(indent + indent + "(GLsizei)remaining"); } else { out.println(); } } else { out.println(","); } } out.println(indent + ");"); } if (needsExit) { out.println(); out.println("exit:"); needsExit = false; } if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { // If the argument is 'const', GL will not write to it. // In this case, we can use the 'JNI_ABORT' flag to avoid // the need to write back to the Java array out.println(indent + "if (" + jfunc.getArgName(idx) + "_base) {"); String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray(); out.println(indent + indent + (mUseCPlusPlus ? "_env" : "(*_env)") + "->" + arrayReleaser + "(" + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, " + "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) + "_base,"); out.println(indent + indent + indent + (cfunc.getArgType(cIndex).isConst() ? "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + ");"); out.println(indent + "}"); } else if (jfunc.getArgType(idx).isBuffer()) { if (! isPointerFunc) { JType argType = jfunc.getArgType(idx); String array = numBufferArgs <= 1 ? "_array" : "_" + cfunc.getArgName(cIndex) + "Array"; out.println(indent + "if (" + array + ") {"); if (argType.isTypedBuffer()) { String arrayReleaser = argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray(); out.println(indent + indent + "_env->" + arrayReleaser + "(" + array + ", " + "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" + cfunc.getArgName(cIndex) + ", " + (cfunc.getArgType(cIndex).isConst() ? "JNI_ABORT" : (emitExceptionCheck ? "_exception ? JNI_ABORT : 0" : "0")) + ");"); } else { out.println(indent + indent + "releasePointer(_env, " + array + ", " + cfunc.getArgName(cIndex) + ", " + (cfunc.getArgType(cIndex).isConst() ? "JNI_FALSE" : (emitExceptionCheck ? "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + ");"); } out.println(indent + "}"); } } } } // Emit local variable declaration for strings if (stringArgs.size() > 0) { for (int i = 0; i < stringArgs.size(); i++) { int idx = stringArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); out.println(indent + "if (_native" + cname + ") {"); out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); out.println(indent + "}"); } out.println(); } // Copy results back to java arrays if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : "_" + cfunc.getArgName(cIndex) + "Remaining"; offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; out.println(indent + "if (" + jfunc.getArgName(idx) + ") {"); out.println(indent + indent + "for (int i = 0; i < " + remaining + "; i++) {"); out.println(indent + indent + indent + "jobject " + cfunc.getArgName(cIndex) + "_new = toEGLHandle(_env, " + baseType + "Class, " + baseType + "Constructor, " + cfunc.getArgName(cIndex) + "[i]);"); out.println(indent + indent + indent + (mUseCPlusPlus ? "_env" : "(*_env)") + "->SetObjectArrayElement(" + (mUseCPlusPlus ? "" : "_env, ") + cfunc.getArgName(cIndex) + "_ref, i + " + offset + ", " + cfunc.getArgName(cIndex) + "_new);"); out.println(indent + indent + "}"); out.println(indent + indent + "delete[] " + jfunc.getArgName(idx) + ";"); out.println(indent + "}"); } } } // Throw exception if there is one if (emitExceptionCheck) { out.println(indent + "if (_exception) {"); out.println(indent + indent + "jniThrowException(_env, _exceptionType, _exceptionMessage);"); out.println(indent + "}"); } if (!isVoid) { if (cfunc.getType().isEGLHandle()) { String baseType = cfunc.getType().getBaseType().toLowerCase(); out.println(indent + "return toEGLHandle(_env, " + baseType + "Class, " + baseType + "Constructor, _returnValue);"); } else { out.println(indent + "return (" + getJniType(jfunc.getType()) + ")_returnValue;"); } } out.println("}"); out.println(); } } opengl/tools/glgen/src/Jsr239CodeEmitter.java0100644 0000000 0000000 00000007664 13077405420 020117 0ustar000000000 0000000 /* * Copyright (C) 2009 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. */ import java.io.PrintStream; /** * Emits a Java interface and Java & C implementation for a C function. * *

The Java interface will have Buffer and array variants for functions that * have a typed pointer argument. The array variant will convert a single " *data" * argument to a pair of arguments "[] data, int offset". */ public class Jsr239CodeEmitter extends JniCodeEmitter implements CodeEmitter { PrintStream mJava10InterfaceStream; PrintStream mJava10ExtInterfaceStream; PrintStream mJava11InterfaceStream; PrintStream mJava11ExtInterfaceStream; PrintStream mJava11ExtPackInterfaceStream; PrintStream mJavaImplStream; PrintStream mCStream; PrintStream mJavaInterfaceStream; /** * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions * @param javaImplStream the PrintStream to which to emit the Java implementation * @param cStream the PrintStream to which to emit the C implementation */ public Jsr239CodeEmitter(String classPathName, ParameterChecker checker, PrintStream java10InterfaceStream, PrintStream java10ExtInterfaceStream, PrintStream java11InterfaceStream, PrintStream java11ExtInterfaceStream, PrintStream java11ExtPackInterfaceStream, PrintStream javaImplStream, PrintStream cStream, boolean useContextPointer) { mClassPathName = classPathName; mChecker = checker; mJava10InterfaceStream = java10InterfaceStream; mJava10ExtInterfaceStream = java10ExtInterfaceStream; mJava11InterfaceStream = java11InterfaceStream; mJava11ExtInterfaceStream = java11ExtInterfaceStream; mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream; mJavaImplStream = javaImplStream; mCStream = cStream; mUseContextPointer = useContextPointer; } public void setVersion(int version, boolean ext, boolean pack) { if (version == 0) { mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream : mJava10InterfaceStream; } else if (version == 1) { mJavaInterfaceStream = ext ? (pack ? mJava11ExtPackInterfaceStream : mJava11ExtInterfaceStream) : mJava11InterfaceStream; } else { throw new RuntimeException("Bad version: " + version); } } public void emitCode(CFunc cfunc, String original) { emitCode(cfunc, original, mJavaInterfaceStream, mJavaImplStream, mCStream); } public void emitNativeRegistration() { emitNativeRegistration("register_com_google_android_gles_jni_GLImpl", mCStream); } } opengl/tools/glgen/src/ParameterChecker.java0100644 0000000 0000000 00000003334 13077405420 020171 0ustar000000000 0000000 /* * Copyright (C) 2006 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. */ import java.io.BufferedReader; import java.util.HashMap; public class ParameterChecker { HashMap map = new HashMap(); public ParameterChecker(BufferedReader reader) throws Exception { String line; while ((line = reader.readLine()) != null) { String s = line.trim(); // skip empty lines if (s.isEmpty()) { continue; } // skip single-line comments if (s.startsWith("//") || s.startsWith("#")) { continue; } String[] tokens = s.split("\\s"); map.put(tokens[0], tokens); } } public String[] getChecks(String functionName) { String[] checks = map.get(functionName); if (checks == null && (functionName.endsWith("fv") || functionName.endsWith("xv") || functionName.endsWith("iv"))) { functionName = functionName.substring(0, functionName.length() - 2); checks = map.get(functionName); } return checks; } } opengl/tools/glgen/static/0040755 0000000 0000000 00000000000 13077405420 014621 5ustar000000000 0000000 opengl/tools/glgen/static/egl/0040755 0000000 0000000 00000000000 13077405420 015370 5ustar000000000 0000000 opengl/tools/glgen/static/egl/EGLConfig.java0100644 0000000 0000000 00000002054 13077405420 017766 0ustar000000000 0000000 /* ** ** Copyright 2012, 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.opengl; /** * Wrapper class for native EGLConfig objects. * */ public class EGLConfig extends EGLObjectHandle { private EGLConfig(long handle) { super(handle); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EGLConfig)) return false; EGLConfig that = (EGLConfig) o; return getNativeHandle() == that.getNativeHandle(); } } opengl/tools/glgen/static/egl/EGLContext.java0100644 0000000 0000000 00000002062 13077405420 020204 0ustar000000000 0000000 /* ** ** Copyright 2012, 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.opengl; /** * Wrapper class for native EGLContext objects. * */ public class EGLContext extends EGLObjectHandle { private EGLContext(long handle) { super(handle); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EGLContext)) return false; EGLContext that = (EGLContext) o; return getNativeHandle() == that.getNativeHandle(); } } opengl/tools/glgen/static/egl/EGLDisplay.java0100644 0000000 0000000 00000002062 13077405420 020165 0ustar000000000 0000000 /* ** ** Copyright 2012, 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.opengl; /** * Wrapper class for native EGLDisplay objects. * */ public class EGLDisplay extends EGLObjectHandle { private EGLDisplay(long handle) { super(handle); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EGLDisplay)) return false; EGLDisplay that = (EGLDisplay) o; return getNativeHandle() == that.getNativeHandle(); } } opengl/tools/glgen/static/egl/EGLObjectHandle.java0100644 0000000 0000000 00000004047 13077405420 021107 0ustar000000000 0000000 /* ** ** Copyright 2012, 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.opengl; /** * Base class for wrapped EGL objects. * */ public abstract class EGLObjectHandle { private final long mHandle; /** * @deprecated Use {@link #EGLObjectHandle(long)} instead. Handles * on 64 bit platforms will be wider than java ints. */ @Deprecated protected EGLObjectHandle(int handle) { mHandle = handle; } protected EGLObjectHandle(long handle) { mHandle = handle; } /** * @deprecated Use {@link #getNativeHandle()} instead. Handles on * 64 bit platforms will be wider than java ints. */ @Deprecated public int getHandle() { if ((mHandle & 0xffffffffL) != mHandle) { throw new UnsupportedOperationException(); } return (int)mHandle; } /** * Returns the native handle of the wrapped EGL object. This handle can be * cast to the corresponding native type on the native side. * * For example, EGLDisplay dpy = (EGLDisplay)handle; * * @return the native handle of the wrapped EGL object. */ public long getNativeHandle() { return mHandle; } @Override public int hashCode() { /* * Based on the algorithm suggested in * http://developer.android.com/reference/java/lang/Object.html */ int result = 17; result = 31 * result + (int) (mHandle ^ (mHandle >>> 32)); return result; } } opengl/tools/glgen/static/egl/EGLSurface.java0100644 0000000 0000000 00000002062 13077405420 020150 0ustar000000000 0000000 /* ** ** Copyright 2012, 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.opengl; /** * Wrapper class for native EGLSurface objects. * */ public class EGLSurface extends EGLObjectHandle { private EGLSurface(long handle) { super(handle); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EGLSurface)) return false; EGLSurface that = (EGLSurface) o; return getNativeHandle() == that.getNativeHandle(); } } opengl/tools/glgen/stubs/0040755 0000000 0000000 00000000000 13077405420 014472 5ustar000000000 0000000 opengl/tools/glgen/stubs/egl/0040755 0000000 0000000 00000000000 13077405420 015241 5ustar000000000 0000000 opengl/tools/glgen/stubs/egl/EGL14Header.java-if0100644 0000000 0000000 00000021137 13077405420 020366 0ustar000000000 0000000 /* ** Copyright 2012, 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. */ // This source file is automatically generated package android.opengl; import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceView; import android.view.SurfaceHolder; /** * EGL 1.4 * */ public class EGL14 { public static final int EGL_DEFAULT_DISPLAY = 0; public static EGLContext EGL_NO_CONTEXT = null; public static EGLDisplay EGL_NO_DISPLAY = null; public static EGLSurface EGL_NO_SURFACE = null; public static final int EGL_FALSE = 0; public static final int EGL_TRUE = 1; public static final int EGL_SUCCESS = 0x3000; public static final int EGL_NOT_INITIALIZED = 0x3001; public static final int EGL_BAD_ACCESS = 0x3002; public static final int EGL_BAD_ALLOC = 0x3003; public static final int EGL_BAD_ATTRIBUTE = 0x3004; public static final int EGL_BAD_CONFIG = 0x3005; public static final int EGL_BAD_CONTEXT = 0x3006; public static final int EGL_BAD_CURRENT_SURFACE = 0x3007; public static final int EGL_BAD_DISPLAY = 0x3008; public static final int EGL_BAD_MATCH = 0x3009; public static final int EGL_BAD_NATIVE_PIXMAP = 0x300A; public static final int EGL_BAD_NATIVE_WINDOW = 0x300B; public static final int EGL_BAD_PARAMETER = 0x300C; public static final int EGL_BAD_SURFACE = 0x300D; public static final int EGL_CONTEXT_LOST = 0x300E; public static final int EGL_BUFFER_SIZE = 0x3020; public static final int EGL_ALPHA_SIZE = 0x3021; public static final int EGL_BLUE_SIZE = 0x3022; public static final int EGL_GREEN_SIZE = 0x3023; public static final int EGL_RED_SIZE = 0x3024; public static final int EGL_DEPTH_SIZE = 0x3025; public static final int EGL_STENCIL_SIZE = 0x3026; public static final int EGL_CONFIG_CAVEAT = 0x3027; public static final int EGL_CONFIG_ID = 0x3028; public static final int EGL_LEVEL = 0x3029; public static final int EGL_MAX_PBUFFER_HEIGHT = 0x302A; public static final int EGL_MAX_PBUFFER_PIXELS = 0x302B; public static final int EGL_MAX_PBUFFER_WIDTH = 0x302C; public static final int EGL_NATIVE_RENDERABLE = 0x302D; public static final int EGL_NATIVE_VISUAL_ID = 0x302E; public static final int EGL_NATIVE_VISUAL_TYPE = 0x302F; public static final int EGL_SAMPLES = 0x3031; public static final int EGL_SAMPLE_BUFFERS = 0x3032; public static final int EGL_SURFACE_TYPE = 0x3033; public static final int EGL_TRANSPARENT_TYPE = 0x3034; public static final int EGL_TRANSPARENT_BLUE_VALUE = 0x3035; public static final int EGL_TRANSPARENT_GREEN_VALUE = 0x3036; public static final int EGL_TRANSPARENT_RED_VALUE = 0x3037; public static final int EGL_NONE = 0x3038; public static final int EGL_BIND_TO_TEXTURE_RGB = 0x3039; public static final int EGL_BIND_TO_TEXTURE_RGBA = 0x303A; public static final int EGL_MIN_SWAP_INTERVAL = 0x303B; public static final int EGL_MAX_SWAP_INTERVAL = 0x303C; public static final int EGL_LUMINANCE_SIZE = 0x303D; public static final int EGL_ALPHA_MASK_SIZE = 0x303E; public static final int EGL_COLOR_BUFFER_TYPE = 0x303F; public static final int EGL_RENDERABLE_TYPE = 0x3040; public static final int EGL_MATCH_NATIVE_PIXMAP = 0x3041; public static final int EGL_CONFORMANT = 0x3042; public static final int EGL_SLOW_CONFIG = 0x3050; public static final int EGL_NON_CONFORMANT_CONFIG = 0x3051; public static final int EGL_TRANSPARENT_RGB = 0x3052; public static final int EGL_RGB_BUFFER = 0x308E; public static final int EGL_LUMINANCE_BUFFER = 0x308F; public static final int EGL_NO_TEXTURE = 0x305C; public static final int EGL_TEXTURE_RGB = 0x305D; public static final int EGL_TEXTURE_RGBA = 0x305E; public static final int EGL_TEXTURE_2D = 0x305F; public static final int EGL_PBUFFER_BIT = 0x0001; public static final int EGL_PIXMAP_BIT = 0x0002; public static final int EGL_WINDOW_BIT = 0x0004; public static final int EGL_VG_COLORSPACE_LINEAR_BIT = 0x0020; public static final int EGL_VG_ALPHA_FORMAT_PRE_BIT = 0x0040; public static final int EGL_MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200; public static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; public static final int EGL_OPENGL_ES_BIT = 0x0001; public static final int EGL_OPENVG_BIT = 0x0002; public static final int EGL_OPENGL_ES2_BIT = 0x0004; public static final int EGL_OPENGL_BIT = 0x0008; public static final int EGL_VENDOR = 0x3053; public static final int EGL_VERSION = 0x3054; public static final int EGL_EXTENSIONS = 0x3055; public static final int EGL_CLIENT_APIS = 0x308D; public static final int EGL_HEIGHT = 0x3056; public static final int EGL_WIDTH = 0x3057; public static final int EGL_LARGEST_PBUFFER = 0x3058; public static final int EGL_TEXTURE_FORMAT = 0x3080; public static final int EGL_TEXTURE_TARGET = 0x3081; public static final int EGL_MIPMAP_TEXTURE = 0x3082; public static final int EGL_MIPMAP_LEVEL = 0x3083; public static final int EGL_RENDER_BUFFER = 0x3086; public static final int EGL_VG_COLORSPACE = 0x3087; public static final int EGL_VG_ALPHA_FORMAT = 0x3088; public static final int EGL_HORIZONTAL_RESOLUTION = 0x3090; public static final int EGL_VERTICAL_RESOLUTION = 0x3091; public static final int EGL_PIXEL_ASPECT_RATIO = 0x3092; public static final int EGL_SWAP_BEHAVIOR = 0x3093; public static final int EGL_MULTISAMPLE_RESOLVE = 0x3099; public static final int EGL_BACK_BUFFER = 0x3084; public static final int EGL_SINGLE_BUFFER = 0x3085; public static final int EGL_VG_COLORSPACE_sRGB = 0x3089; public static final int EGL_VG_COLORSPACE_LINEAR = 0x308A; public static final int EGL_VG_ALPHA_FORMAT_NONPRE = 0x308B; public static final int EGL_VG_ALPHA_FORMAT_PRE = 0x308C; public static final int EGL_DISPLAY_SCALING = 10000; public static final int EGL_BUFFER_PRESERVED = 0x3094; public static final int EGL_BUFFER_DESTROYED = 0x3095; public static final int EGL_OPENVG_IMAGE = 0x3096; public static final int EGL_CONTEXT_CLIENT_TYPE = 0x3097; public static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public static final int EGL_MULTISAMPLE_RESOLVE_DEFAULT = 0x309A; public static final int EGL_MULTISAMPLE_RESOLVE_BOX = 0x309B; public static final int EGL_OPENGL_ES_API = 0x30A0; public static final int EGL_OPENVG_API = 0x30A1; public static final int EGL_OPENGL_API = 0x30A2; public static final int EGL_DRAW = 0x3059; public static final int EGL_READ = 0x305A; public static final int EGL_CORE_NATIVE_ENGINE = 0x305B; native private static void _nativeClassInit(); static { _nativeClassInit(); } opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp0100644 0000000 0000000 00000012436 13077405420 020000 0ustar000000000 0000000 /* ** Copyright 2012, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" #include "JNIHelp.h" #include #include #include #include #include #include #include #include #include #include static int initialized = 0; static jclass egldisplayClass; static jclass eglcontextClass; static jclass eglsurfaceClass; static jclass eglconfigClass; static jmethodID egldisplayGetHandleID; static jmethodID eglcontextGetHandleID; static jmethodID eglsurfaceGetHandleID; static jmethodID eglconfigGetHandleID; static jmethodID egldisplayConstructor; static jmethodID eglcontextConstructor; static jmethodID eglsurfaceConstructor; static jmethodID eglconfigConstructor; static jobject eglNoContextObject; static jobject eglNoDisplayObject; static jobject eglNoSurfaceObject; /* Cache method IDs each time the class is loaded. */ static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay"); egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal); jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext"); eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal); jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface"); eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal); jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig"); eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal); egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J"); eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J"); eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J"); eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J"); egldisplayConstructor = _env->GetMethodID(egldisplayClass, "", "(J)V"); eglcontextConstructor = _env->GetMethodID(eglcontextClass, "", "(J)V"); eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "", "(J)V"); eglconfigConstructor = _env->GetMethodID(eglconfigClass, "", "(J)V"); jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast(EGL_NO_CONTEXT)); eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast(EGL_NO_DISPLAY)); eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast(EGL_NO_SURFACE)); eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); jclass eglClass = _env->FindClass("android/opengl/EGL14"); jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;"); _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject); jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;"); _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject); jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;"); _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject); } static void * fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { if (obj == NULL){ jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null."); } jlong handle = _env->CallLongMethod(obj, mid); return reinterpret_cast(handle); } static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) { if (cls == eglcontextClass && (EGLContext)handle == EGL_NO_CONTEXT) { return eglNoContextObject; } if (cls == egldisplayClass && (EGLDisplay)handle == EGL_NO_DISPLAY) { return eglNoDisplayObject; } if (cls == eglsurfaceClass && (EGLSurface)handle == EGL_NO_SURFACE) { return eglNoSurfaceObject; } return _env->NewObject(cls, con, reinterpret_cast(handle)); } // -------------------------------------------------------------------------- opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if0100644 0000000 0000000 00000002174 13077405420 020702 0ustar000000000 0000000 /* ** Copyright 2013, 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. */ // This source file is automatically generated package android.opengl; /** * EGL Extensions */ public class EGLExt { // EGL_KHR_create_context public static final int EGL_CONTEXT_MAJOR_VERSION_KHR = 0x3098; public static final int EGL_CONTEXT_MINOR_VERSION_KHR = 0x30FB; public static final int EGL_CONTEXT_FLAGS_KHR = 0x30FC; public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; native private static void _nativeClassInit(); static { _nativeClassInit(); } opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp0100644 0000000 0000000 00000011654 13077405420 020315 0ustar000000000 0000000 /* ** Copyright 2013, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" #include "JNIHelp.h" #include #include #include #include #include #include #include #include #include #include #include static int initialized = 0; static jclass egldisplayClass; static jclass eglcontextClass; static jclass eglsurfaceClass; static jclass eglconfigClass; static jmethodID egldisplayGetHandleID; static jmethodID eglcontextGetHandleID; static jmethodID eglsurfaceGetHandleID; static jmethodID eglconfigGetHandleID; static jmethodID egldisplayConstructor; static jmethodID eglcontextConstructor; static jmethodID eglsurfaceConstructor; static jmethodID eglconfigConstructor; static jobject eglNoContextObject; static jobject eglNoDisplayObject; static jobject eglNoSurfaceObject; /* Cache method IDs each time the class is loaded. */ static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay"); egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal); jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext"); eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal); jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface"); eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal); jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig"); eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal); egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J"); eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J"); eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J"); eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J"); egldisplayConstructor = _env->GetMethodID(egldisplayClass, "", "(J)V"); eglcontextConstructor = _env->GetMethodID(eglcontextClass, "", "(J)V"); eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "", "(J)V"); eglconfigConstructor = _env->GetMethodID(eglconfigClass, "", "(J)V"); jclass eglClass = _env->FindClass("android/opengl/EGL14"); jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;"); jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID); eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;"); jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID); eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;"); jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID); eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); } static void * fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { if (obj == NULL){ jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null."); } return reinterpret_cast(_env->CallLongMethod(obj, mid)); } static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) { if (cls == eglcontextClass && (EGLContext)handle == EGL_NO_CONTEXT) { return eglNoContextObject; } if (cls == egldisplayClass && (EGLDisplay)handle == EGL_NO_DISPLAY) { return eglNoDisplayObject; } if (cls == eglsurfaceClass && (EGLSurface)handle == EGL_NO_SURFACE) { return eglNoSurfaceObject; } return _env->NewObject(cls, con, reinterpret_cast(handle)); } // -------------------------------------------------------------------------- opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp0100755 0000000 0000000 00000005363 13077405420 024276 0ustar000000000 0000000 /* EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) */ static jobject android_eglCreatePbufferFromClientBuffer (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jlong buffer, jobject config, jintArray attrib_list_ref, jint offset) { jint _exception = 0; const char * _exceptionType = NULL; const char * _exceptionMessage = NULL; EGLSurface _returnValue = (EGLSurface) 0; EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config); bool attrib_list_sentinel = false; EGLint *attrib_list_base = (EGLint *) 0; jint _remaining; EGLint *attrib_list = (EGLint *) 0; if (attrib_list_ref) { if (offset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "offset < 0"; goto exit; } _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = false; for (int i = _remaining - 1; i >= 0; i--) { if (attrib_list[i] == EGL_NONE){ attrib_list_sentinel = true; break; } } if (attrib_list_sentinel == false) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "attrib_list must contain EGL_NONE!"; goto exit; } } _returnValue = eglCreatePbufferFromClientBuffer( (EGLDisplay)dpy_native, (EGLenum)buftype, reinterpret_cast(buffer), (EGLConfig)config_native, (EGLint *)attrib_list ); exit: if (attrib_list_base) { _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } static jobject android_eglCreatePbufferFromClientBufferInt (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jint buffer, jobject config, jintArray attrib_list_ref, jint offset) { if(sizeof(void*) != sizeof(uint32_t)) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePbufferFromClientBuffer"); return 0; } return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset); } opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.java0100755 0000000 0000000 00000001277 13077405420 024435 0ustar000000000 0000000 // C function EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) // TODO Deprecate the below method public static native EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, int buftype, int buffer, EGLConfig config, int[] attrib_list, int offset ); // TODO Unhide the below method /** * {@hide} */ public static native EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, int buftype, long buffer, EGLConfig config, int[] attrib_list, int offset ); opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.nativeReg0100755 0000000 0000000 00000000555 13077405420 025436 0ustar000000000 0000000 {"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IILandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBufferInt }, {"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IJLandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBuffer },opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp0100644 0000000 0000000 00000012607 13077405420 022344 0ustar000000000 0000000 /* EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) */ static jobject android_eglCreateWindowSurface (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) { jint _exception = 0; const char * _exceptionType = ""; const char * _exceptionMessage = ""; EGLSurface _returnValue = (EGLSurface) 0; EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config); int attrib_list_sentinel = 0; EGLint *attrib_list_base = (EGLint *) 0; jint _remaining; EGLint *attrib_list = (EGLint *) 0; android::sp window; if (attrib_list_ref) { if (offset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "offset < 0"; goto exit; } _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = 0; for (int i = _remaining - 1; i >= 0; i--) { if (*((EGLint*)(attrib_list + i)) == EGL_NONE){ attrib_list_sentinel = 1; break; } } if (attrib_list_sentinel == 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "attrib_list must contain EGL_NONE!"; goto exit; } } if (win == NULL) { not_valid_surface: _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface"; goto exit; } window = android::android_view_Surface_getNativeWindow(_env, win); if (window == NULL) goto not_valid_surface; _returnValue = eglCreateWindowSurface( (EGLDisplay)dpy_native, (EGLConfig)config_native, (EGLNativeWindowType)window.get(), (EGLint *)attrib_list ); exit: if (attrib_list_base) { _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } /* EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) */ static jobject android_eglCreateWindowSurfaceTexture (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) { jint _exception = 0; const char * _exceptionType = ""; const char * _exceptionMessage = ""; EGLSurface _returnValue = (EGLSurface) 0; EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config); int attrib_list_sentinel = 0; EGLint *attrib_list_base = (EGLint *) 0; jint _remaining; EGLint *attrib_list = (EGLint *) 0; android::sp window; android::sp producer; if (!attrib_list_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "attrib_list == null"; goto exit; } if (offset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "offset < 0"; goto exit; } if (win == NULL) { not_valid_surface: _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface"; goto exit; } producer = android::SurfaceTexture_getProducer(_env, win); if (producer == NULL) goto not_valid_surface; window = new android::Surface(producer, true); if (window == NULL) goto not_valid_surface; _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = 0; for (int i = _remaining - 1; i >= 0; i--) { if (*((EGLint*)(attrib_list + i)) == EGL_NONE){ attrib_list_sentinel = 1; break; } } if (attrib_list_sentinel == 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "attrib_list must contain EGL_NONE!"; goto exit; } _returnValue = eglCreateWindowSurface( (EGLDisplay)dpy_native, (EGLConfig)config_native, (EGLNativeWindowType)window.get(), (EGLint *)attrib_list ); exit: if (attrib_list_base) { _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue); } opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.java0100644 0000000 0000000 00000003330 13077405420 022474 0ustar000000000 0000000 // C function EGLSurface eglCreateWindowSurface ( EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list ) private static native EGLSurface _eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, Object win, int[] attrib_list, int offset ); private static native EGLSurface _eglCreateWindowSurfaceTexture( EGLDisplay dpy, EGLConfig config, Object win, int[] attrib_list, int offset ); public static EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, Object win, int[] attrib_list, int offset ){ Surface sur = null; if (win instanceof SurfaceView) { SurfaceView surfaceView = (SurfaceView)win; sur = surfaceView.getHolder().getSurface(); } else if (win instanceof SurfaceHolder) { SurfaceHolder holder = (SurfaceHolder)win; sur = holder.getSurface(); } else if (win instanceof Surface) { sur = (Surface) win; } EGLSurface surface; if (sur != null) { surface = _eglCreateWindowSurface(dpy, config, sur, attrib_list, offset); } else if (win instanceof SurfaceTexture) { surface = _eglCreateWindowSurfaceTexture(dpy, config, win, attrib_list, offset); } else { throw new java.lang.UnsupportedOperationException( "eglCreateWindowSurface() can only be called with an instance of " + "Surface, SurfaceView, SurfaceTexture or SurfaceHolder at the moment, " + "this will be fixed later."); } return surface; } opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.nativeReg0100644 0000000 0000000 00000000562 13077405420 023503 0ustar000000000 0000000 {"_eglCreateWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/lang/Object;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreateWindowSurface }, {"_eglCreateWindowSurfaceTexture", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/lang/Object;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreateWindowSurfaceTexture }, opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp0100755 0000000 0000000 00000001501 13077405420 020477 0ustar000000000 0000000 /* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */ static jobject android_eglGetDisplay (JNIEnv *_env, jobject _this, jlong display_id) { EGLDisplay _returnValue = (EGLDisplay) 0; _returnValue = eglGetDisplay( reinterpret_cast(display_id) ); return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue); } /* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */ static jobject android_eglGetDisplayInt (JNIEnv *_env, jobject _this, jint display_id) { if (static_cast(display_id) != reinterpret_cast(EGL_DEFAULT_DISPLAY)) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay"); return 0; } return android_eglGetDisplay(_env, _this, display_id); } opengl/tools/glgen/stubs/egl/eglGetDisplay.java0100755 0000000 0000000 00000000424 13077405420 020641 0ustar000000000 0000000 // C function EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) public static native EGLDisplay eglGetDisplay( int display_id ); /** * {@hide} */ public static native EGLDisplay eglGetDisplay( long display_id ); opengl/tools/glgen/stubs/egl/eglGetDisplay.nativeReg0100755 0000000 0000000 00000000256 13077405420 021647 0ustar000000000 0000000 {"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt }, {"eglGetDisplay", "(J)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplay },opengl/tools/glgen/stubs/egl/eglQueryString.cpp0100644 0000000 0000000 00000000601 13077405420 020723 0ustar000000000 0000000 /* const char * eglQueryString ( EGLDisplay dpy, EGLint name ) */ static jstring android_eglQueryString__Landroind_opengl_EGLDisplay_2I (JNIEnv *_env, jobject _this, jobject dpy, jint name) { const char* chars = (const char*) eglQueryString( (EGLDisplay)fromEGLHandle(_env, egldisplayGetHandleID, dpy), (EGLint)name ); return _env->NewStringUTF(chars); } opengl/tools/glgen/stubs/egl/eglQueryString.java0100644 0000000 0000000 00000000257 13077405420 021071 0ustar000000000 0000000 // C function const char * eglQueryString ( EGLDisplay dpy, EGLint name ) public static native String eglQueryString( EGLDisplay dpy, int name ); opengl/tools/glgen/stubs/egl/eglQueryString.nativeReg0100644 0000000 0000000 00000000213 13077405420 022064 0ustar000000000 0000000 {"eglQueryString", "(Landroid/opengl/EGLDisplay;I)Ljava/lang/String;", (void *) android_eglQueryString__Landroind_opengl_EGLDisplay_2I }, opengl/tools/glgen/stubs/gles11/0040755 0000000 0000000 00000000000 13077405420 015566 5ustar000000000 0000000 opengl/tools/glgen/stubs/gles11/GLES10ExtHeader.java-if0100644 0000000 0000000 00000001464 13077405420 021514 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated package android.opengl; public class GLES10Ext { native private static void _nativeClassInit(); static { _nativeClassInit(); } opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp0100644 0000000 0000000 00000001553 13077405420 021123 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES10Header.java-if0100644 0000000 0000000 00000046373 13077405420 021043 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated package android.opengl; import java.nio.Buffer; public class GLES10 { public static final int GL_ADD = 0x0104; public static final int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; public static final int GL_ALIASED_POINT_SIZE_RANGE = 0x846D; public static final int GL_ALPHA = 0x1906; public static final int GL_ALPHA_BITS = 0x0D55; public static final int GL_ALPHA_TEST = 0x0BC0; public static final int GL_ALWAYS = 0x0207; public static final int GL_AMBIENT = 0x1200; public static final int GL_AMBIENT_AND_DIFFUSE = 0x1602; public static final int GL_AND = 0x1501; public static final int GL_AND_INVERTED = 0x1504; public static final int GL_AND_REVERSE = 0x1502; public static final int GL_BACK = 0x0405; public static final int GL_BLEND = 0x0BE2; public static final int GL_BLUE_BITS = 0x0D54; public static final int GL_BYTE = 0x1400; public static final int GL_CCW = 0x0901; public static final int GL_CLAMP_TO_EDGE = 0x812F; public static final int GL_CLEAR = 0x1500; public static final int GL_COLOR_ARRAY = 0x8076; public static final int GL_COLOR_BUFFER_BIT = 0x4000; public static final int GL_COLOR_LOGIC_OP = 0x0BF2; public static final int GL_COLOR_MATERIAL = 0x0B57; public static final int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; public static final int GL_CONSTANT_ATTENUATION = 0x1207; public static final int GL_COPY = 0x1503; public static final int GL_COPY_INVERTED = 0x150C; public static final int GL_CULL_FACE = 0x0B44; public static final int GL_CW = 0x0900; public static final int GL_DECAL = 0x2101; public static final int GL_DECR = 0x1E03; public static final int GL_DEPTH_BITS = 0x0D56; public static final int GL_DEPTH_BUFFER_BIT = 0x0100; public static final int GL_DEPTH_TEST = 0x0B71; public static final int GL_DIFFUSE = 0x1201; public static final int GL_DITHER = 0x0BD0; public static final int GL_DONT_CARE = 0x1100; public static final int GL_DST_ALPHA = 0x0304; public static final int GL_DST_COLOR = 0x0306; public static final int GL_EMISSION = 0x1600; public static final int GL_EQUAL = 0x0202; public static final int GL_EQUIV = 0x1509; public static final int GL_EXP = 0x0800; public static final int GL_EXP2 = 0x0801; public static final int GL_EXTENSIONS = 0x1F03; public static final int GL_FALSE = 0; public static final int GL_FASTEST = 0x1101; public static final int GL_FIXED = 0x140C; public static final int GL_FLAT = 0x1D00; public static final int GL_FLOAT = 0x1406; public static final int GL_FOG = 0x0B60; public static final int GL_FOG_COLOR = 0x0B66; public static final int GL_FOG_DENSITY = 0x0B62; public static final int GL_FOG_END = 0x0B64; public static final int GL_FOG_HINT = 0x0C54; public static final int GL_FOG_MODE = 0x0B65; public static final int GL_FOG_START = 0x0B63; public static final int GL_FRONT = 0x0404; public static final int GL_FRONT_AND_BACK = 0x0408; public static final int GL_GEQUAL = 0x0206; public static final int GL_GREATER = 0x0204; public static final int GL_GREEN_BITS = 0x0D53; public static final int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x8B9B; public static final int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x8B9A; public static final int GL_INCR = 0x1E02; public static final int GL_INVALID_ENUM = 0x0500; public static final int GL_INVALID_OPERATION = 0x0502; public static final int GL_INVALID_VALUE = 0x0501; public static final int GL_INVERT = 0x150A; public static final int GL_KEEP = 0x1E00; public static final int GL_LEQUAL = 0x0203; public static final int GL_LESS = 0x0201; public static final int GL_LIGHT_MODEL_AMBIENT = 0x0B53; public static final int GL_LIGHT_MODEL_TWO_SIDE = 0x0B52; public static final int GL_LIGHT0 = 0x4000; public static final int GL_LIGHT1 = 0x4001; public static final int GL_LIGHT2 = 0x4002; public static final int GL_LIGHT3 = 0x4003; public static final int GL_LIGHT4 = 0x4004; public static final int GL_LIGHT5 = 0x4005; public static final int GL_LIGHT6 = 0x4006; public static final int GL_LIGHT7 = 0x4007; public static final int GL_LIGHTING = 0x0B50; public static final int GL_LINE_LOOP = 0x0002; public static final int GL_LINE_SMOOTH = 0x0B20; public static final int GL_LINE_SMOOTH_HINT = 0x0C52; public static final int GL_LINE_STRIP = 0x0003; public static final int GL_LINEAR = 0x2601; public static final int GL_LINEAR_ATTENUATION = 0x1208; public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; public static final int GL_LINES = 0x0001; public static final int GL_LUMINANCE = 0x1909; public static final int GL_LUMINANCE_ALPHA = 0x190A; public static final int GL_MAX_ELEMENTS_INDICES = 0x80E9; public static final int GL_MAX_ELEMENTS_VERTICES = 0x80E8; public static final int GL_MAX_LIGHTS = 0x0D31; public static final int GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36; public static final int GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38; public static final int GL_MAX_TEXTURE_SIZE = 0x0D33; public static final int GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39; public static final int GL_MAX_TEXTURE_UNITS = 0x84E2; public static final int GL_MAX_VIEWPORT_DIMS = 0x0D3A; public static final int GL_MODELVIEW = 0x1700; public static final int GL_MODULATE = 0x2100; public static final int GL_MULTISAMPLE = 0x809D; public static final int GL_NAND = 0x150E; public static final int GL_NEAREST = 0x2600; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; public static final int GL_NEVER = 0x0200; public static final int GL_NICEST = 0x1102; public static final int GL_NO_ERROR = 0; public static final int GL_NOOP = 0x1505; public static final int GL_NOR = 0x1508; public static final int GL_NORMAL_ARRAY = 0x8075; public static final int GL_NORMALIZE = 0x0BA1; public static final int GL_NOTEQUAL = 0x0205; public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; public static final int GL_ONE = 1; public static final int GL_ONE_MINUS_DST_ALPHA = 0x0305; public static final int GL_ONE_MINUS_DST_COLOR = 0x0307; public static final int GL_ONE_MINUS_SRC_ALPHA = 0x0303; public static final int GL_ONE_MINUS_SRC_COLOR = 0x0301; public static final int GL_OR = 0x1507; public static final int GL_OR_INVERTED = 0x150D; public static final int GL_OR_REVERSE = 0x150B; public static final int GL_OUT_OF_MEMORY = 0x0505; public static final int GL_PACK_ALIGNMENT = 0x0D05; public static final int GL_PALETTE4_R5_G6_B5_OES = 0x8B92; public static final int GL_PALETTE4_RGB5_A1_OES = 0x8B94; public static final int GL_PALETTE4_RGB8_OES = 0x8B90; public static final int GL_PALETTE4_RGBA4_OES = 0x8B93; public static final int GL_PALETTE4_RGBA8_OES = 0x8B91; public static final int GL_PALETTE8_R5_G6_B5_OES = 0x8B97; public static final int GL_PALETTE8_RGB5_A1_OES = 0x8B99; public static final int GL_PALETTE8_RGB8_OES = 0x8B95; public static final int GL_PALETTE8_RGBA4_OES = 0x8B98; public static final int GL_PALETTE8_RGBA8_OES = 0x8B96; public static final int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50; public static final int GL_POINT_SMOOTH = 0x0B10; public static final int GL_POINT_SMOOTH_HINT = 0x0C51; public static final int GL_POINTS = 0x0000; public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; public static final int GL_POINT_SIZE = 0x0B11; public static final int GL_POLYGON_OFFSET_FILL = 0x8037; public static final int GL_POLYGON_SMOOTH_HINT = 0x0C53; public static final int GL_POSITION = 0x1203; public static final int GL_PROJECTION = 0x1701; public static final int GL_QUADRATIC_ATTENUATION = 0x1209; public static final int GL_RED_BITS = 0x0D52; public static final int GL_RENDERER = 0x1F01; public static final int GL_REPEAT = 0x2901; public static final int GL_REPLACE = 0x1E01; public static final int GL_RESCALE_NORMAL = 0x803A; public static final int GL_RGB = 0x1907; public static final int GL_RGBA = 0x1908; public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; public static final int GL_SAMPLE_ALPHA_TO_ONE = 0x809F; public static final int GL_SAMPLE_COVERAGE = 0x80A0; public static final int GL_SCISSOR_TEST = 0x0C11; public static final int GL_SET = 0x150F; public static final int GL_SHININESS = 0x1601; public static final int GL_SHORT = 0x1402; public static final int GL_SMOOTH = 0x1D01; public static final int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22; public static final int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12; public static final int GL_SPECULAR = 0x1202; public static final int GL_SPOT_CUTOFF = 0x1206; public static final int GL_SPOT_DIRECTION = 0x1204; public static final int GL_SPOT_EXPONENT = 0x1205; public static final int GL_SRC_ALPHA = 0x0302; public static final int GL_SRC_ALPHA_SATURATE = 0x0308; public static final int GL_SRC_COLOR = 0x0300; public static final int GL_STACK_OVERFLOW = 0x0503; public static final int GL_STACK_UNDERFLOW = 0x0504; public static final int GL_STENCIL_BITS = 0x0D57; public static final int GL_STENCIL_BUFFER_BIT = 0x0400; public static final int GL_STENCIL_TEST = 0x0B90; public static final int GL_SUBPIXEL_BITS = 0x0D50; public static final int GL_TEXTURE = 0x1702; public static final int GL_TEXTURE_2D = 0x0DE1; public static final int GL_TEXTURE_COORD_ARRAY = 0x8078; public static final int GL_TEXTURE_ENV = 0x2300; public static final int GL_TEXTURE_ENV_COLOR = 0x2201; public static final int GL_TEXTURE_ENV_MODE = 0x2200; public static final int GL_TEXTURE_MAG_FILTER = 0x2800; public static final int GL_TEXTURE_MIN_FILTER = 0x2801; public static final int GL_TEXTURE_WRAP_S = 0x2802; public static final int GL_TEXTURE_WRAP_T = 0x2803; public static final int GL_TEXTURE0 = 0x84C0; public static final int GL_TEXTURE1 = 0x84C1; public static final int GL_TEXTURE2 = 0x84C2; public static final int GL_TEXTURE3 = 0x84C3; public static final int GL_TEXTURE4 = 0x84C4; public static final int GL_TEXTURE5 = 0x84C5; public static final int GL_TEXTURE6 = 0x84C6; public static final int GL_TEXTURE7 = 0x84C7; public static final int GL_TEXTURE8 = 0x84C8; public static final int GL_TEXTURE9 = 0x84C9; public static final int GL_TEXTURE10 = 0x84CA; public static final int GL_TEXTURE11 = 0x84CB; public static final int GL_TEXTURE12 = 0x84CC; public static final int GL_TEXTURE13 = 0x84CD; public static final int GL_TEXTURE14 = 0x84CE; public static final int GL_TEXTURE15 = 0x84CF; public static final int GL_TEXTURE16 = 0x84D0; public static final int GL_TEXTURE17 = 0x84D1; public static final int GL_TEXTURE18 = 0x84D2; public static final int GL_TEXTURE19 = 0x84D3; public static final int GL_TEXTURE20 = 0x84D4; public static final int GL_TEXTURE21 = 0x84D5; public static final int GL_TEXTURE22 = 0x84D6; public static final int GL_TEXTURE23 = 0x84D7; public static final int GL_TEXTURE24 = 0x84D8; public static final int GL_TEXTURE25 = 0x84D9; public static final int GL_TEXTURE26 = 0x84DA; public static final int GL_TEXTURE27 = 0x84DB; public static final int GL_TEXTURE28 = 0x84DC; public static final int GL_TEXTURE29 = 0x84DD; public static final int GL_TEXTURE30 = 0x84DE; public static final int GL_TEXTURE31 = 0x84DF; public static final int GL_TRIANGLE_FAN = 0x0006; public static final int GL_TRIANGLE_STRIP = 0x0005; public static final int GL_TRIANGLES = 0x0004; public static final int GL_TRUE = 1; public static final int GL_UNPACK_ALIGNMENT = 0x0CF5; public static final int GL_UNSIGNED_BYTE = 0x1401; public static final int GL_UNSIGNED_SHORT = 0x1403; public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; public static final int GL_VENDOR = 0x1F00; public static final int GL_VERSION = 0x1F02; public static final int GL_VERTEX_ARRAY = 0x8074; public static final int GL_XOR = 0x1506; public static final int GL_ZERO = 0; native private static void _nativeClassInit(); static { _nativeClassInit(); } private static Buffer _colorPointer; private static Buffer _normalPointer; private static Buffer _texCoordPointer; private static Buffer _vertexPointer; opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp0100644 0000000 0000000 00000001553 13077405420 020442 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if0100644 0000000 0000000 00000025655 13077405420 021525 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated package android.opengl; import java.nio.Buffer; public class GLES11Ext { public static final int GL_BLEND_EQUATION_RGB_OES = 0x8009; public static final int GL_BLEND_EQUATION_ALPHA_OES = 0x883D; public static final int GL_BLEND_DST_RGB_OES = 0x80C8; public static final int GL_BLEND_SRC_RGB_OES = 0x80C9; public static final int GL_BLEND_DST_ALPHA_OES = 0x80CA; public static final int GL_BLEND_SRC_ALPHA_OES = 0x80CB; public static final int GL_BLEND_EQUATION_OES = 0x8009; public static final int GL_FUNC_ADD_OES = 0x8006; public static final int GL_FUNC_SUBTRACT_OES = 0x800A; public static final int GL_FUNC_REVERSE_SUBTRACT_OES = 0x800B; public static final int GL_ETC1_RGB8_OES = 0x8D64; public static final int GL_DEPTH_COMPONENT24_OES = 0x81A6; public static final int GL_DEPTH_COMPONENT32_OES = 0x81A7; public static final int GL_TEXTURE_CROP_RECT_OES = 0x8B9D; public static final int GL_FIXED_OES = 0x140C; public static final int GL_NONE_OES = 0; public static final int GL_FRAMEBUFFER_OES = 0x8D40; public static final int GL_RENDERBUFFER_OES = 0x8D41; public static final int GL_RGBA4_OES = 0x8056; public static final int GL_RGB5_A1_OES = 0x8057; public static final int GL_RGB565_OES = 0x8D62; public static final int GL_DEPTH_COMPONENT16_OES = 0x81A5; public static final int GL_RENDERBUFFER_WIDTH_OES = 0x8D42; public static final int GL_RENDERBUFFER_HEIGHT_OES = 0x8D43; public static final int GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x8D44; public static final int GL_RENDERBUFFER_RED_SIZE_OES = 0x8D50; public static final int GL_RENDERBUFFER_GREEN_SIZE_OES = 0x8D51; public static final int GL_RENDERBUFFER_BLUE_SIZE_OES = 0x8D52; public static final int GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x8D53; public static final int GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x8D54; public static final int GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x8D55; public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x8CD0; public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x8CD1; public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x8CD2; public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3; public static final int GL_COLOR_ATTACHMENT0_OES = 0x8CE0; public static final int GL_DEPTH_ATTACHMENT_OES = 0x8D00; public static final int GL_STENCIL_ATTACHMENT_OES = 0x8D20; public static final int GL_FRAMEBUFFER_COMPLETE_OES = 0x8CD5; public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x8CD6; public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x8CD7; public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x8CD9; public static final int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x8CDA; public static final int GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x8CDD; public static final int GL_FRAMEBUFFER_BINDING_OES = 0x8CA6; public static final int GL_RENDERBUFFER_BINDING_OES = 0x8CA7; public static final int GL_MAX_RENDERBUFFER_SIZE_OES = 0x84E8; public static final int GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x0506; public static final int GL_WRITE_ONLY_OES = 0x88B9; public static final int GL_BUFFER_ACCESS_OES = 0x88BB; public static final int GL_BUFFER_MAPPED_OES = 0x88BC; public static final int GL_BUFFER_MAP_POINTER_OES = 0x88BD; public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; public static final int GL_MAX_VERTEX_UNITS_OES = 0x86A4; public static final int GL_MAX_PALETTE_MATRICES_OES = 0x8842; public static final int GL_MATRIX_PALETTE_OES = 0x8840; public static final int GL_MATRIX_INDEX_ARRAY_OES = 0x8844; public static final int GL_WEIGHT_ARRAY_OES = 0x86AD; public static final int GL_CURRENT_PALETTE_MATRIX_OES = 0x8843; public static final int GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x8846; public static final int GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x8847; public static final int GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x8848; public static final int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x8849; public static final int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E; public static final int GL_WEIGHT_ARRAY_SIZE_OES = 0x86AB; public static final int GL_WEIGHT_ARRAY_TYPE_OES = 0x86A9; public static final int GL_WEIGHT_ARRAY_STRIDE_OES = 0x86AA; public static final int GL_WEIGHT_ARRAY_POINTER_OES = 0x86AC; public static final int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x889E; public static final int GL_DEPTH_STENCIL_OES = 0x84F9; public static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; public static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; public static final int GL_RGB8_OES = 0x8051; public static final int GL_RGBA8_OES = 0x8058; public static final int GL_STENCIL_INDEX1_OES = 0x8D46; public static final int GL_STENCIL_INDEX4_OES = 0x8D47; public static final int GL_STENCIL_INDEX8_OES = 0x8D48; public static final int GL_INCR_WRAP_OES = 0x8507; public static final int GL_DECR_WRAP_OES = 0x8508; public static final int GL_NORMAL_MAP_OES = 0x8511; public static final int GL_REFLECTION_MAP_OES = 0x8512; public static final int GL_TEXTURE_CUBE_MAP_OES = 0x8513; public static final int GL_TEXTURE_BINDING_CUBE_MAP_OES = 0x8514; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 0x8515; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 0x8516; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 0x8517; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 0x8518; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 0x8519; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES = 0x851A; public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES = 0x851C; public static final int GL_TEXTURE_GEN_MODE_OES = 0x2500; public static final int GL_TEXTURE_GEN_STR_OES = 0x8D60; public static final int GL_MIRRORED_REPEAT_OES = 0x8370; public static final int GL_3DC_X_AMD = 0x87F9; public static final int GL_3DC_XY_AMD = 0x87FA; public static final int GL_ATC_RGB_AMD = 0x8C92; public static final int GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93; public static final int GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE; public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; public static final int GL_BGRA = 0x80E1; public static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; public static final int GL_SAMPLER_EXTERNAL_OES = 0x8D66; public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 0x8D67; public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 0x8D68; native private static void _nativeClassInit(); static { _nativeClassInit(); } private static final int GL_BYTE = GLES10.GL_BYTE; private static final int GL_FIXED = GLES10.GL_FIXED; private static final int GL_FLOAT = GLES10.GL_FLOAT; private static final int GL_SHORT = GLES10.GL_SHORT; private static Buffer _matrixIndexPointerOES; opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp0100644 0000000 0000000 00000001553 13077405420 021124 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES11Header.java-if0100644 0000000 0000000 00000025040 13077405420 021030 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated package android.opengl; import java.nio.Buffer; public class GLES11 extends GLES10 { public static final int GL_ACTIVE_TEXTURE = 0x84E0; public static final int GL_ADD_SIGNED = 0x8574; public static final int GL_ALPHA_SCALE = 0x0D1C; public static final int GL_ALPHA_TEST_FUNC = 0x0BC1; public static final int GL_ALPHA_TEST_REF = 0x0BC2; public static final int GL_ARRAY_BUFFER = 0x8892; public static final int GL_ARRAY_BUFFER_BINDING = 0x8894; public static final int GL_BLEND_DST = 0x0BE0; public static final int GL_BLEND_SRC = 0x0BE1; public static final int GL_BUFFER_ACCESS = 0x88BB; public static final int GL_BUFFER_SIZE = 0x8764; public static final int GL_BUFFER_USAGE = 0x8765; public static final int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1; public static final int GL_CLIP_PLANE0 = 0x3000; public static final int GL_CLIP_PLANE1 = 0x3001; public static final int GL_CLIP_PLANE2 = 0x3002; public static final int GL_CLIP_PLANE3 = 0x3003; public static final int GL_CLIP_PLANE4 = 0x3004; public static final int GL_CLIP_PLANE5 = 0x3005; public static final int GL_COLOR_ARRAY_BUFFER_BINDING = 0x8898; public static final int GL_COLOR_ARRAY_POINTER = 0x8090; public static final int GL_COLOR_ARRAY_SIZE = 0x8081; public static final int GL_COLOR_ARRAY_STRIDE = 0x8083; public static final int GL_COLOR_ARRAY_TYPE = 0x8082; public static final int GL_COLOR_CLEAR_VALUE = 0x0C22; public static final int GL_COLOR_WRITEMASK = 0x0C23; public static final int GL_COMBINE = 0x8570; public static final int GL_COMBINE_ALPHA = 0x8572; public static final int GL_COMBINE_RGB = 0x8571; public static final int GL_CONSTANT = 0x8576; public static final int GL_COORD_REPLACE_OES = 0x8862; public static final int GL_CULL_FACE_MODE = 0x0B45; public static final int GL_CURRENT_COLOR = 0x0B00; public static final int GL_CURRENT_NORMAL = 0x0B02; public static final int GL_CURRENT_TEXTURE_COORDS = 0x0B03; public static final int GL_DEPTH_CLEAR_VALUE = 0x0B73; public static final int GL_DEPTH_FUNC = 0x0B74; public static final int GL_DEPTH_RANGE = 0x0B70; public static final int GL_DEPTH_WRITEMASK = 0x0B72; public static final int GL_DOT3_RGB = 0x86AE; public static final int GL_DOT3_RGBA = 0x86AF; public static final int GL_DYNAMIC_DRAW = 0x88E8; public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; public static final int GL_FRONT_FACE = 0x0B46; public static final int GL_GENERATE_MIPMAP = 0x8191; public static final int GL_GENERATE_MIPMAP_HINT = 0x8192; public static final int GL_INTERPOLATE = 0x8575; public static final int GL_LINE_WIDTH = 0x0B21; public static final int GL_LOGIC_OP_MODE = 0x0BF0; public static final int GL_MATRIX_MODE = 0x0BA0; public static final int GL_MAX_CLIP_PLANES = 0x0D32; public static final int GL_MODELVIEW_MATRIX = 0x0BA6; public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; public static final int GL_MODELVIEW_STACK_DEPTH = 0x0BA3; public static final int GL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897; public static final int GL_NORMAL_ARRAY_POINTER = 0x808F; public static final int GL_NORMAL_ARRAY_STRIDE = 0x807F; public static final int GL_NORMAL_ARRAY_TYPE = 0x807E; public static final int GL_OPERAND0_ALPHA = 0x8598; public static final int GL_OPERAND0_RGB = 0x8590; public static final int GL_OPERAND1_ALPHA = 0x8599; public static final int GL_OPERAND1_RGB = 0x8591; public static final int GL_OPERAND2_ALPHA = 0x859A; public static final int GL_OPERAND2_RGB = 0x8592; public static final int GL_POINT_DISTANCE_ATTENUATION = 0x8129; public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; public static final int GL_POINT_SIZE = 0x0B11; public static final int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x8B9F; public static final int GL_POINT_SIZE_ARRAY_OES = 0x8B9C; public static final int GL_POINT_SIZE_ARRAY_POINTER_OES = 0x898C; public static final int GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x898B; public static final int GL_POINT_SIZE_ARRAY_TYPE_OES = 0x898A; public static final int GL_POINT_SIZE_MAX = 0x8127; public static final int GL_POINT_SIZE_MIN = 0x8126; public static final int GL_POINT_SPRITE_OES = 0x8861; public static final int GL_POLYGON_OFFSET_FACTOR = 0x8038; public static final int GL_POLYGON_OFFSET_UNITS = 0x2A00; public static final int GL_PREVIOUS = 0x8578; public static final int GL_PRIMARY_COLOR = 0x8577; public static final int GL_PROJECTION_MATRIX = 0x0BA7; public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; public static final int GL_PROJECTION_STACK_DEPTH = 0x0BA4; public static final int GL_RGB_SCALE = 0x8573; public static final int GL_SAMPLE_BUFFERS = 0x80A8; public static final int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; public static final int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; public static final int GL_SAMPLES = 0x80A9; public static final int GL_SCISSOR_BOX = 0x0C10; public static final int GL_SHADE_MODEL = 0x0B54; public static final int GL_SRC0_ALPHA = 0x8588; public static final int GL_SRC0_RGB = 0x8580; public static final int GL_SRC1_ALPHA = 0x8589; public static final int GL_SRC1_RGB = 0x8581; public static final int GL_SRC2_ALPHA = 0x858A; public static final int GL_SRC2_RGB = 0x8582; public static final int GL_STATIC_DRAW = 0x88E4; public static final int GL_STENCIL_CLEAR_VALUE = 0x0B91; public static final int GL_STENCIL_FAIL = 0x0B94; public static final int GL_STENCIL_FUNC = 0x0B92; public static final int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; public static final int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; public static final int GL_STENCIL_REF = 0x0B97; public static final int GL_STENCIL_VALUE_MASK = 0x0B93; public static final int GL_STENCIL_WRITEMASK = 0x0B98; public static final int GL_SUBTRACT = 0x84E7; public static final int GL_TEXTURE_BINDING_2D = 0x8069; public static final int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A; public static final int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092; public static final int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088; public static final int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A; public static final int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089; public static final int GL_TEXTURE_MATRIX = 0x0BA8; public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; public static final int GL_TEXTURE_STACK_DEPTH = 0x0BA5; public static final int GL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896; public static final int GL_VERTEX_ARRAY_POINTER = 0x808E; public static final int GL_VERTEX_ARRAY_SIZE = 0x807A; public static final int GL_VERTEX_ARRAY_STRIDE = 0x807C; public static final int GL_VERTEX_ARRAY_TYPE = 0x807B; public static final int GL_VIEWPORT = 0x0BA2; public static final int GL_WRITE_ONLY = 0x88B9; native private static void _nativeClassInit(); static { _nativeClassInit(); } private static Buffer _pointSizePointerOES; opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp0100644 0000000 0000000 00000001553 13077405420 020443 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES20Header.java-if0100644 0000000 0000000 00000061703 13077405420 021036 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated package android.opengl; /** OpenGL ES 2.0 */ public class GLES20 { public static final int GL_ACTIVE_TEXTURE = 0x84E0; public static final int GL_DEPTH_BUFFER_BIT = 0x00000100; public static final int GL_STENCIL_BUFFER_BIT = 0x00000400; public static final int GL_COLOR_BUFFER_BIT = 0x00004000; public static final int GL_FALSE = 0; public static final int GL_TRUE = 1; public static final int GL_POINTS = 0x0000; public static final int GL_LINES = 0x0001; public static final int GL_LINE_LOOP = 0x0002; public static final int GL_LINE_STRIP = 0x0003; public static final int GL_TRIANGLES = 0x0004; public static final int GL_TRIANGLE_STRIP = 0x0005; public static final int GL_TRIANGLE_FAN = 0x0006; public static final int GL_ZERO = 0; public static final int GL_ONE = 1; public static final int GL_SRC_COLOR = 0x0300; public static final int GL_ONE_MINUS_SRC_COLOR = 0x0301; public static final int GL_SRC_ALPHA = 0x0302; public static final int GL_ONE_MINUS_SRC_ALPHA = 0x0303; public static final int GL_DST_ALPHA = 0x0304; public static final int GL_ONE_MINUS_DST_ALPHA = 0x0305; public static final int GL_DST_COLOR = 0x0306; public static final int GL_ONE_MINUS_DST_COLOR = 0x0307; public static final int GL_SRC_ALPHA_SATURATE = 0x0308; public static final int GL_FUNC_ADD = 0x8006; public static final int GL_BLEND_EQUATION = 0x8009; public static final int GL_BLEND_EQUATION_RGB = 0x8009; /* same as BLEND_EQUATION */ public static final int GL_BLEND_EQUATION_ALPHA = 0x883D; public static final int GL_FUNC_SUBTRACT = 0x800A; public static final int GL_FUNC_REVERSE_SUBTRACT = 0x800B; public static final int GL_BLEND_DST_RGB = 0x80C8; public static final int GL_BLEND_SRC_RGB = 0x80C9; public static final int GL_BLEND_DST_ALPHA = 0x80CA; public static final int GL_BLEND_SRC_ALPHA = 0x80CB; public static final int GL_CONSTANT_COLOR = 0x8001; public static final int GL_ONE_MINUS_CONSTANT_COLOR = 0x8002; public static final int GL_CONSTANT_ALPHA = 0x8003; public static final int GL_ONE_MINUS_CONSTANT_ALPHA = 0x8004; public static final int GL_BLEND_COLOR = 0x8005; public static final int GL_ARRAY_BUFFER = 0x8892; public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; public static final int GL_ARRAY_BUFFER_BINDING = 0x8894; public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; public static final int GL_STREAM_DRAW = 0x88E0; public static final int GL_STATIC_DRAW = 0x88E4; public static final int GL_DYNAMIC_DRAW = 0x88E8; public static final int GL_BUFFER_SIZE = 0x8764; public static final int GL_BUFFER_USAGE = 0x8765; public static final int GL_CURRENT_VERTEX_ATTRIB = 0x8626; public static final int GL_FRONT = 0x0404; public static final int GL_BACK = 0x0405; public static final int GL_FRONT_AND_BACK = 0x0408; public static final int GL_TEXTURE_2D = 0x0DE1; public static final int GL_CULL_FACE = 0x0B44; public static final int GL_BLEND = 0x0BE2; public static final int GL_DITHER = 0x0BD0; public static final int GL_STENCIL_TEST = 0x0B90; public static final int GL_DEPTH_TEST = 0x0B71; public static final int GL_SCISSOR_TEST = 0x0C11; public static final int GL_POLYGON_OFFSET_FILL = 0x8037; public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; public static final int GL_SAMPLE_COVERAGE = 0x80A0; public static final int GL_NO_ERROR = 0; public static final int GL_INVALID_ENUM = 0x0500; public static final int GL_INVALID_VALUE = 0x0501; public static final int GL_INVALID_OPERATION = 0x0502; public static final int GL_OUT_OF_MEMORY = 0x0505; public static final int GL_CW = 0x0900; public static final int GL_CCW = 0x0901; public static final int GL_LINE_WIDTH = 0x0B21; public static final int GL_ALIASED_POINT_SIZE_RANGE = 0x846D; public static final int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; public static final int GL_CULL_FACE_MODE = 0x0B45; public static final int GL_FRONT_FACE = 0x0B46; public static final int GL_DEPTH_RANGE = 0x0B70; public static final int GL_DEPTH_WRITEMASK = 0x0B72; public static final int GL_DEPTH_CLEAR_VALUE = 0x0B73; public static final int GL_DEPTH_FUNC = 0x0B74; public static final int GL_STENCIL_CLEAR_VALUE = 0x0B91; public static final int GL_STENCIL_FUNC = 0x0B92; public static final int GL_STENCIL_FAIL = 0x0B94; public static final int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; public static final int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; public static final int GL_STENCIL_REF = 0x0B97; public static final int GL_STENCIL_VALUE_MASK = 0x0B93; public static final int GL_STENCIL_WRITEMASK = 0x0B98; public static final int GL_STENCIL_BACK_FUNC = 0x8800; public static final int GL_STENCIL_BACK_FAIL = 0x8801; public static final int GL_STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; public static final int GL_STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; public static final int GL_STENCIL_BACK_REF = 0x8CA3; public static final int GL_STENCIL_BACK_VALUE_MASK = 0x8CA4; public static final int GL_STENCIL_BACK_WRITEMASK = 0x8CA5; public static final int GL_VIEWPORT = 0x0BA2; public static final int GL_SCISSOR_BOX = 0x0C10; public static final int GL_COLOR_CLEAR_VALUE = 0x0C22; public static final int GL_COLOR_WRITEMASK = 0x0C23; public static final int GL_UNPACK_ALIGNMENT = 0x0CF5; public static final int GL_PACK_ALIGNMENT = 0x0D05; public static final int GL_MAX_TEXTURE_SIZE = 0x0D33; public static final int GL_MAX_VIEWPORT_DIMS = 0x0D3A; public static final int GL_SUBPIXEL_BITS = 0x0D50; public static final int GL_RED_BITS = 0x0D52; public static final int GL_GREEN_BITS = 0x0D53; public static final int GL_BLUE_BITS = 0x0D54; public static final int GL_ALPHA_BITS = 0x0D55; public static final int GL_DEPTH_BITS = 0x0D56; public static final int GL_STENCIL_BITS = 0x0D57; public static final int GL_POLYGON_OFFSET_UNITS = 0x2A00; public static final int GL_POLYGON_OFFSET_FACTOR = 0x8038; public static final int GL_TEXTURE_BINDING_2D = 0x8069; public static final int GL_SAMPLE_BUFFERS = 0x80A8; public static final int GL_SAMPLES = 0x80A9; public static final int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; public static final int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; public static final int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; public static final int GL_DONT_CARE = 0x1100; public static final int GL_FASTEST = 0x1101; public static final int GL_NICEST = 0x1102; public static final int GL_GENERATE_MIPMAP_HINT = 0x8192; public static final int GL_BYTE = 0x1400; public static final int GL_UNSIGNED_BYTE = 0x1401; public static final int GL_SHORT = 0x1402; public static final int GL_UNSIGNED_SHORT = 0x1403; public static final int GL_INT = 0x1404; public static final int GL_UNSIGNED_INT = 0x1405; public static final int GL_FLOAT = 0x1406; public static final int GL_FIXED = 0x140C; public static final int GL_DEPTH_COMPONENT = 0x1902; public static final int GL_ALPHA = 0x1906; public static final int GL_RGB = 0x1907; public static final int GL_RGBA = 0x1908; public static final int GL_LUMINANCE = 0x1909; public static final int GL_LUMINANCE_ALPHA = 0x190A; public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; public static final int GL_FRAGMENT_SHADER = 0x8B30; public static final int GL_VERTEX_SHADER = 0x8B31; public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; public static final int GL_MAX_VARYING_VECTORS = 0x8DFC; public static final int GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872; public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; public static final int GL_SHADER_TYPE = 0x8B4F; public static final int GL_DELETE_STATUS = 0x8B80; public static final int GL_LINK_STATUS = 0x8B82; public static final int GL_VALIDATE_STATUS = 0x8B83; public static final int GL_ATTACHED_SHADERS = 0x8B85; public static final int GL_ACTIVE_UNIFORMS = 0x8B86; public static final int GL_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87; public static final int GL_ACTIVE_ATTRIBUTES = 0x8B89; public static final int GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A; public static final int GL_SHADING_LANGUAGE_VERSION = 0x8B8C; public static final int GL_CURRENT_PROGRAM = 0x8B8D; public static final int GL_NEVER = 0x0200; public static final int GL_LESS = 0x0201; public static final int GL_EQUAL = 0x0202; public static final int GL_LEQUAL = 0x0203; public static final int GL_GREATER = 0x0204; public static final int GL_NOTEQUAL = 0x0205; public static final int GL_GEQUAL = 0x0206; public static final int GL_ALWAYS = 0x0207; public static final int GL_KEEP = 0x1E00; public static final int GL_REPLACE = 0x1E01; public static final int GL_INCR = 0x1E02; public static final int GL_DECR = 0x1E03; public static final int GL_INVERT = 0x150A; public static final int GL_INCR_WRAP = 0x8507; public static final int GL_DECR_WRAP = 0x8508; public static final int GL_VENDOR = 0x1F00; public static final int GL_RENDERER = 0x1F01; public static final int GL_VERSION = 0x1F02; public static final int GL_EXTENSIONS = 0x1F03; public static final int GL_NEAREST = 0x2600; public static final int GL_LINEAR = 0x2601; public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; public static final int GL_TEXTURE_MAG_FILTER = 0x2800; public static final int GL_TEXTURE_MIN_FILTER = 0x2801; public static final int GL_TEXTURE_WRAP_S = 0x2802; public static final int GL_TEXTURE_WRAP_T = 0x2803; public static final int GL_TEXTURE = 0x1702; public static final int GL_TEXTURE_CUBE_MAP = 0x8513; public static final int GL_TEXTURE_BINDING_CUBE_MAP = 0x8514; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; public static final int GL_TEXTURE0 = 0x84C0; public static final int GL_TEXTURE1 = 0x84C1; public static final int GL_TEXTURE2 = 0x84C2; public static final int GL_TEXTURE3 = 0x84C3; public static final int GL_TEXTURE4 = 0x84C4; public static final int GL_TEXTURE5 = 0x84C5; public static final int GL_TEXTURE6 = 0x84C6; public static final int GL_TEXTURE7 = 0x84C7; public static final int GL_TEXTURE8 = 0x84C8; public static final int GL_TEXTURE9 = 0x84C9; public static final int GL_TEXTURE10 = 0x84CA; public static final int GL_TEXTURE11 = 0x84CB; public static final int GL_TEXTURE12 = 0x84CC; public static final int GL_TEXTURE13 = 0x84CD; public static final int GL_TEXTURE14 = 0x84CE; public static final int GL_TEXTURE15 = 0x84CF; public static final int GL_TEXTURE16 = 0x84D0; public static final int GL_TEXTURE17 = 0x84D1; public static final int GL_TEXTURE18 = 0x84D2; public static final int GL_TEXTURE19 = 0x84D3; public static final int GL_TEXTURE20 = 0x84D4; public static final int GL_TEXTURE21 = 0x84D5; public static final int GL_TEXTURE22 = 0x84D6; public static final int GL_TEXTURE23 = 0x84D7; public static final int GL_TEXTURE24 = 0x84D8; public static final int GL_TEXTURE25 = 0x84D9; public static final int GL_TEXTURE26 = 0x84DA; public static final int GL_TEXTURE27 = 0x84DB; public static final int GL_TEXTURE28 = 0x84DC; public static final int GL_TEXTURE29 = 0x84DD; public static final int GL_TEXTURE30 = 0x84DE; public static final int GL_TEXTURE31 = 0x84DF; public static final int GL_REPEAT = 0x2901; public static final int GL_CLAMP_TO_EDGE = 0x812F; public static final int GL_MIRRORED_REPEAT = 0x8370; public static final int GL_FLOAT_VEC2 = 0x8B50; public static final int GL_FLOAT_VEC3 = 0x8B51; public static final int GL_FLOAT_VEC4 = 0x8B52; public static final int GL_INT_VEC2 = 0x8B53; public static final int GL_INT_VEC3 = 0x8B54; public static final int GL_INT_VEC4 = 0x8B55; public static final int GL_BOOL = 0x8B56; public static final int GL_BOOL_VEC2 = 0x8B57; public static final int GL_BOOL_VEC3 = 0x8B58; public static final int GL_BOOL_VEC4 = 0x8B59; public static final int GL_FLOAT_MAT2 = 0x8B5A; public static final int GL_FLOAT_MAT3 = 0x8B5B; public static final int GL_FLOAT_MAT4 = 0x8B5C; public static final int GL_SAMPLER_2D = 0x8B5E; public static final int GL_SAMPLER_CUBE = 0x8B60; public static final int GL_VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; public static final int GL_VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; public static final int GL_VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; public static final int GL_VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; public static final int GL_VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; public static final int GL_VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; public static final int GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; public static final int GL_IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A; public static final int GL_IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B; public static final int GL_COMPILE_STATUS = 0x8B81; public static final int GL_INFO_LOG_LENGTH = 0x8B84; public static final int GL_SHADER_SOURCE_LENGTH = 0x8B88; public static final int GL_SHADER_COMPILER = 0x8DFA; public static final int GL_SHADER_BINARY_FORMATS = 0x8DF8; public static final int GL_NUM_SHADER_BINARY_FORMATS = 0x8DF9; public static final int GL_LOW_FLOAT = 0x8DF0; public static final int GL_MEDIUM_FLOAT = 0x8DF1; public static final int GL_HIGH_FLOAT = 0x8DF2; public static final int GL_LOW_INT = 0x8DF3; public static final int GL_MEDIUM_INT = 0x8DF4; public static final int GL_HIGH_INT = 0x8DF5; public static final int GL_FRAMEBUFFER = 0x8D40; public static final int GL_RENDERBUFFER = 0x8D41; public static final int GL_RGBA4 = 0x8056; public static final int GL_RGB5_A1 = 0x8057; public static final int GL_RGB565 = 0x8D62; public static final int GL_DEPTH_COMPONENT16 = 0x81A5; // GL_STENCIL_INDEX does not appear in gl2.h or gl2ext.h, and there is no // token with value 0x1901. // @Deprecated public static final int GL_STENCIL_INDEX = 0x1901; public static final int GL_STENCIL_INDEX8 = 0x8D48; public static final int GL_RENDERBUFFER_WIDTH = 0x8D42; public static final int GL_RENDERBUFFER_HEIGHT = 0x8D43; public static final int GL_RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; public static final int GL_RENDERBUFFER_RED_SIZE = 0x8D50; public static final int GL_RENDERBUFFER_GREEN_SIZE = 0x8D51; public static final int GL_RENDERBUFFER_BLUE_SIZE = 0x8D52; public static final int GL_RENDERBUFFER_ALPHA_SIZE = 0x8D53; public static final int GL_RENDERBUFFER_DEPTH_SIZE = 0x8D54; public static final int GL_RENDERBUFFER_STENCIL_SIZE = 0x8D55; public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2; public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3; public static final int GL_COLOR_ATTACHMENT0 = 0x8CE0; public static final int GL_DEPTH_ATTACHMENT = 0x8D00; public static final int GL_STENCIL_ATTACHMENT = 0x8D20; public static final int GL_NONE = 0; public static final int GL_FRAMEBUFFER_COMPLETE = 0x8CD5; public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; public static final int GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD; public static final int GL_FRAMEBUFFER_BINDING = 0x8CA6; public static final int GL_RENDERBUFFER_BINDING = 0x8CA7; public static final int GL_MAX_RENDERBUFFER_SIZE = 0x84E8; public static final int GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506; native private static void _nativeClassInit(); static { _nativeClassInit(); } opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp0100644 0000000 0000000 00000001557 13077405420 020447 0ustar000000000 0000000 /* ** ** Copyright 2009, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES30Header.java-if0100644 0000000 0000000 00000062237 13077405420 021042 0ustar000000000 0000000 /* ** ** Copyright 2013, 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. */ // This source file is automatically generated package android.opengl; /** OpenGL ES 3.0 */ public class GLES30 extends GLES20 { public static final int GL_READ_BUFFER = 0x0C02; public static final int GL_UNPACK_ROW_LENGTH = 0x0CF2; public static final int GL_UNPACK_SKIP_ROWS = 0x0CF3; public static final int GL_UNPACK_SKIP_PIXELS = 0x0CF4; public static final int GL_PACK_ROW_LENGTH = 0x0D02; public static final int GL_PACK_SKIP_ROWS = 0x0D03; public static final int GL_PACK_SKIP_PIXELS = 0x0D04; public static final int GL_COLOR = 0x1800; public static final int GL_DEPTH = 0x1801; public static final int GL_STENCIL = 0x1802; public static final int GL_RED = 0x1903; public static final int GL_RGB8 = 0x8051; public static final int GL_RGBA8 = 0x8058; public static final int GL_RGB10_A2 = 0x8059; public static final int GL_TEXTURE_BINDING_3D = 0x806A; public static final int GL_UNPACK_SKIP_IMAGES = 0x806D; public static final int GL_UNPACK_IMAGE_HEIGHT = 0x806E; public static final int GL_TEXTURE_3D = 0x806F; public static final int GL_TEXTURE_WRAP_R = 0x8072; public static final int GL_MAX_3D_TEXTURE_SIZE = 0x8073; public static final int GL_UNSIGNED_INT_2_10_10_10_REV = 0x8368; public static final int GL_MAX_ELEMENTS_VERTICES = 0x80E8; public static final int GL_MAX_ELEMENTS_INDICES = 0x80E9; public static final int GL_TEXTURE_MIN_LOD = 0x813A; public static final int GL_TEXTURE_MAX_LOD = 0x813B; public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; public static final int GL_MIN = 0x8007; public static final int GL_MAX = 0x8008; public static final int GL_DEPTH_COMPONENT24 = 0x81A6; public static final int GL_MAX_TEXTURE_LOD_BIAS = 0x84FD; public static final int GL_TEXTURE_COMPARE_MODE = 0x884C; public static final int GL_TEXTURE_COMPARE_FUNC = 0x884D; public static final int GL_CURRENT_QUERY = 0x8865; public static final int GL_QUERY_RESULT = 0x8866; public static final int GL_QUERY_RESULT_AVAILABLE = 0x8867; public static final int GL_BUFFER_MAPPED = 0x88BC; public static final int GL_BUFFER_MAP_POINTER = 0x88BD; public static final int GL_STREAM_READ = 0x88E1; public static final int GL_STREAM_COPY = 0x88E2; public static final int GL_STATIC_READ = 0x88E5; public static final int GL_STATIC_COPY = 0x88E6; public static final int GL_DYNAMIC_READ = 0x88E9; public static final int GL_DYNAMIC_COPY = 0x88EA; public static final int GL_MAX_DRAW_BUFFERS = 0x8824; public static final int GL_DRAW_BUFFER0 = 0x8825; public static final int GL_DRAW_BUFFER1 = 0x8826; public static final int GL_DRAW_BUFFER2 = 0x8827; public static final int GL_DRAW_BUFFER3 = 0x8828; public static final int GL_DRAW_BUFFER4 = 0x8829; public static final int GL_DRAW_BUFFER5 = 0x882A; public static final int GL_DRAW_BUFFER6 = 0x882B; public static final int GL_DRAW_BUFFER7 = 0x882C; public static final int GL_DRAW_BUFFER8 = 0x882D; public static final int GL_DRAW_BUFFER9 = 0x882E; public static final int GL_DRAW_BUFFER10 = 0x882F; public static final int GL_DRAW_BUFFER11 = 0x8830; public static final int GL_DRAW_BUFFER12 = 0x8831; public static final int GL_DRAW_BUFFER13 = 0x8832; public static final int GL_DRAW_BUFFER14 = 0x8833; public static final int GL_DRAW_BUFFER15 = 0x8834; public static final int GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49; public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; public static final int GL_SAMPLER_3D = 0x8B5F; public static final int GL_SAMPLER_2D_SHADOW = 0x8B62; public static final int GL_FRAGMENT_SHADER_DERIVATIVE_HINT = 0x8B8B; public static final int GL_PIXEL_PACK_BUFFER = 0x88EB; public static final int GL_PIXEL_UNPACK_BUFFER = 0x88EC; public static final int GL_PIXEL_PACK_BUFFER_BINDING = 0x88ED; public static final int GL_PIXEL_UNPACK_BUFFER_BINDING = 0x88EF; public static final int GL_FLOAT_MAT2x3 = 0x8B65; public static final int GL_FLOAT_MAT2x4 = 0x8B66; public static final int GL_FLOAT_MAT3x2 = 0x8B67; public static final int GL_FLOAT_MAT3x4 = 0x8B68; public static final int GL_FLOAT_MAT4x2 = 0x8B69; public static final int GL_FLOAT_MAT4x3 = 0x8B6A; public static final int GL_SRGB = 0x8C40; public static final int GL_SRGB8 = 0x8C41; public static final int GL_SRGB8_ALPHA8 = 0x8C43; public static final int GL_COMPARE_REF_TO_TEXTURE = 0x884E; public static final int GL_MAJOR_VERSION = 0x821B; public static final int GL_MINOR_VERSION = 0x821C; public static final int GL_NUM_EXTENSIONS = 0x821D; public static final int GL_RGBA32F = 0x8814; public static final int GL_RGB32F = 0x8815; public static final int GL_RGBA16F = 0x881A; public static final int GL_RGB16F = 0x881B; public static final int GL_VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD; public static final int GL_MAX_ARRAY_TEXTURE_LAYERS = 0x88FF; public static final int GL_MIN_PROGRAM_TEXEL_OFFSET = 0x8904; public static final int GL_MAX_PROGRAM_TEXEL_OFFSET = 0x8905; public static final int GL_MAX_VARYING_COMPONENTS = 0x8B4B; public static final int GL_TEXTURE_2D_ARRAY = 0x8C1A; public static final int GL_TEXTURE_BINDING_2D_ARRAY = 0x8C1D; public static final int GL_R11F_G11F_B10F = 0x8C3A; public static final int GL_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B; public static final int GL_RGB9_E5 = 0x8C3D; public static final int GL_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E; public static final int GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = 0x8C76; public static final int GL_TRANSFORM_FEEDBACK_BUFFER_MODE = 0x8C7F; public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x8C80; public static final int GL_TRANSFORM_FEEDBACK_VARYINGS = 0x8C83; public static final int GL_TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84; public static final int GL_TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85; public static final int GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x8C88; public static final int GL_RASTERIZER_DISCARD = 0x8C89; public static final int GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A; public static final int GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B; public static final int GL_INTERLEAVED_ATTRIBS = 0x8C8C; public static final int GL_SEPARATE_ATTRIBS = 0x8C8D; public static final int GL_TRANSFORM_FEEDBACK_BUFFER = 0x8C8E; public static final int GL_TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F; public static final int GL_RGBA32UI = 0x8D70; public static final int GL_RGB32UI = 0x8D71; public static final int GL_RGBA16UI = 0x8D76; public static final int GL_RGB16UI = 0x8D77; public static final int GL_RGBA8UI = 0x8D7C; public static final int GL_RGB8UI = 0x8D7D; public static final int GL_RGBA32I = 0x8D82; public static final int GL_RGB32I = 0x8D83; public static final int GL_RGBA16I = 0x8D88; public static final int GL_RGB16I = 0x8D89; public static final int GL_RGBA8I = 0x8D8E; public static final int GL_RGB8I = 0x8D8F; public static final int GL_RED_INTEGER = 0x8D94; public static final int GL_RGB_INTEGER = 0x8D98; public static final int GL_RGBA_INTEGER = 0x8D99; public static final int GL_SAMPLER_2D_ARRAY = 0x8DC1; public static final int GL_SAMPLER_2D_ARRAY_SHADOW = 0x8DC4; public static final int GL_SAMPLER_CUBE_SHADOW = 0x8DC5; public static final int GL_UNSIGNED_INT_VEC2 = 0x8DC6; public static final int GL_UNSIGNED_INT_VEC3 = 0x8DC7; public static final int GL_UNSIGNED_INT_VEC4 = 0x8DC8; public static final int GL_INT_SAMPLER_2D = 0x8DCA; public static final int GL_INT_SAMPLER_3D = 0x8DCB; public static final int GL_INT_SAMPLER_CUBE = 0x8DCC; public static final int GL_INT_SAMPLER_2D_ARRAY = 0x8DCF; public static final int GL_UNSIGNED_INT_SAMPLER_2D = 0x8DD2; public static final int GL_UNSIGNED_INT_SAMPLER_3D = 0x8DD3; public static final int GL_UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4; public static final int GL_UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7; public static final int GL_BUFFER_ACCESS_FLAGS = 0x911F; public static final int GL_BUFFER_MAP_LENGTH = 0x9120; public static final int GL_BUFFER_MAP_OFFSET = 0x9121; public static final int GL_DEPTH_COMPONENT32F = 0x8CAC; public static final int GL_DEPTH32F_STENCIL8 = 0x8CAD; public static final int GL_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD; public static final int GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210; public static final int GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x8211; public static final int GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x8212; public static final int GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x8213; public static final int GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x8214; public static final int GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x8215; public static final int GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216; public static final int GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217; public static final int GL_FRAMEBUFFER_DEFAULT = 0x8218; public static final int GL_FRAMEBUFFER_UNDEFINED = 0x8219; public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A; public static final int GL_DEPTH_STENCIL = 0x84F9; public static final int GL_UNSIGNED_INT_24_8 = 0x84FA; public static final int GL_DEPTH24_STENCIL8 = 0x88F0; public static final int GL_UNSIGNED_NORMALIZED = 0x8C17; public static final int GL_DRAW_FRAMEBUFFER_BINDING = GL_FRAMEBUFFER_BINDING; public static final int GL_READ_FRAMEBUFFER = 0x8CA8; public static final int GL_DRAW_FRAMEBUFFER = 0x8CA9; public static final int GL_READ_FRAMEBUFFER_BINDING = 0x8CAA; public static final int GL_RENDERBUFFER_SAMPLES = 0x8CAB; public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x8CD4; public static final int GL_MAX_COLOR_ATTACHMENTS = 0x8CDF; public static final int GL_COLOR_ATTACHMENT1 = 0x8CE1; public static final int GL_COLOR_ATTACHMENT2 = 0x8CE2; public static final int GL_COLOR_ATTACHMENT3 = 0x8CE3; public static final int GL_COLOR_ATTACHMENT4 = 0x8CE4; public static final int GL_COLOR_ATTACHMENT5 = 0x8CE5; public static final int GL_COLOR_ATTACHMENT6 = 0x8CE6; public static final int GL_COLOR_ATTACHMENT7 = 0x8CE7; public static final int GL_COLOR_ATTACHMENT8 = 0x8CE8; public static final int GL_COLOR_ATTACHMENT9 = 0x8CE9; public static final int GL_COLOR_ATTACHMENT10 = 0x8CEA; public static final int GL_COLOR_ATTACHMENT11 = 0x8CEB; public static final int GL_COLOR_ATTACHMENT12 = 0x8CEC; public static final int GL_COLOR_ATTACHMENT13 = 0x8CED; public static final int GL_COLOR_ATTACHMENT14 = 0x8CEE; public static final int GL_COLOR_ATTACHMENT15 = 0x8CEF; public static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56; public static final int GL_MAX_SAMPLES = 0x8D57; public static final int GL_HALF_FLOAT = 0x140B; public static final int GL_MAP_READ_BIT = 0x0001; public static final int GL_MAP_WRITE_BIT = 0x0002; public static final int GL_MAP_INVALIDATE_RANGE_BIT = 0x0004; public static final int GL_MAP_INVALIDATE_BUFFER_BIT = 0x0008; public static final int GL_MAP_FLUSH_EXPLICIT_BIT = 0x0010; public static final int GL_MAP_UNSYNCHRONIZED_BIT = 0x0020; public static final int GL_RG = 0x8227; public static final int GL_RG_INTEGER = 0x8228; public static final int GL_R8 = 0x8229; public static final int GL_RG8 = 0x822B; public static final int GL_R16F = 0x822D; public static final int GL_R32F = 0x822E; public static final int GL_RG16F = 0x822F; public static final int GL_RG32F = 0x8230; public static final int GL_R8I = 0x8231; public static final int GL_R8UI = 0x8232; public static final int GL_R16I = 0x8233; public static final int GL_R16UI = 0x8234; public static final int GL_R32I = 0x8235; public static final int GL_R32UI = 0x8236; public static final int GL_RG8I = 0x8237; public static final int GL_RG8UI = 0x8238; public static final int GL_RG16I = 0x8239; public static final int GL_RG16UI = 0x823A; public static final int GL_RG32I = 0x823B; public static final int GL_RG32UI = 0x823C; public static final int GL_VERTEX_ARRAY_BINDING = 0x85B5; public static final int GL_R8_SNORM = 0x8F94; public static final int GL_RG8_SNORM = 0x8F95; public static final int GL_RGB8_SNORM = 0x8F96; public static final int GL_RGBA8_SNORM = 0x8F97; public static final int GL_SIGNED_NORMALIZED = 0x8F9C; public static final int GL_PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69; public static final int GL_COPY_READ_BUFFER = 0x8F36; public static final int GL_COPY_WRITE_BUFFER = 0x8F37; public static final int GL_COPY_READ_BUFFER_BINDING = GL_COPY_READ_BUFFER; public static final int GL_COPY_WRITE_BUFFER_BINDING = GL_COPY_WRITE_BUFFER; public static final int GL_UNIFORM_BUFFER = 0x8A11; public static final int GL_UNIFORM_BUFFER_BINDING = 0x8A28; public static final int GL_UNIFORM_BUFFER_START = 0x8A29; public static final int GL_UNIFORM_BUFFER_SIZE = 0x8A2A; public static final int GL_MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B; public static final int GL_MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D; public static final int GL_MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E; public static final int GL_MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F; public static final int GL_MAX_UNIFORM_BLOCK_SIZE = 0x8A30; public static final int GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31; public static final int GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33; public static final int GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34; public static final int GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 0x8A35; public static final int GL_ACTIVE_UNIFORM_BLOCKS = 0x8A36; public static final int GL_UNIFORM_TYPE = 0x8A37; public static final int GL_UNIFORM_SIZE = 0x8A38; public static final int GL_UNIFORM_NAME_LENGTH = 0x8A39; public static final int GL_UNIFORM_BLOCK_INDEX = 0x8A3A; public static final int GL_UNIFORM_OFFSET = 0x8A3B; public static final int GL_UNIFORM_ARRAY_STRIDE = 0x8A3C; public static final int GL_UNIFORM_MATRIX_STRIDE = 0x8A3D; public static final int GL_UNIFORM_IS_ROW_MAJOR = 0x8A3E; public static final int GL_UNIFORM_BLOCK_BINDING = 0x8A3F; public static final int GL_UNIFORM_BLOCK_DATA_SIZE = 0x8A40; public static final int GL_UNIFORM_BLOCK_NAME_LENGTH = 0x8A41; public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42; public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43; public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44; public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46; // GL_INVALID_INDEX is defined as 0xFFFFFFFFu in C. public static final int GL_INVALID_INDEX = -1; public static final int GL_MAX_VERTEX_OUTPUT_COMPONENTS = 0x9122; public static final int GL_MAX_FRAGMENT_INPUT_COMPONENTS = 0x9125; public static final int GL_MAX_SERVER_WAIT_TIMEOUT = 0x9111; public static final int GL_OBJECT_TYPE = 0x9112; public static final int GL_SYNC_CONDITION = 0x9113; public static final int GL_SYNC_STATUS = 0x9114; public static final int GL_SYNC_FLAGS = 0x9115; public static final int GL_SYNC_FENCE = 0x9116; public static final int GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117; public static final int GL_UNSIGNALED = 0x9118; public static final int GL_SIGNALED = 0x9119; public static final int GL_ALREADY_SIGNALED = 0x911A; public static final int GL_TIMEOUT_EXPIRED = 0x911B; public static final int GL_CONDITION_SATISFIED = 0x911C; public static final int GL_WAIT_FAILED = 0x911D; public static final int GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001; // GL_TIMEOUT_IGNORED is defined as 0xFFFFFFFFFFFFFFFFull in C. public static final long GL_TIMEOUT_IGNORED = -1; public static final int GL_VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE; public static final int GL_ANY_SAMPLES_PASSED = 0x8C2F; public static final int GL_ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A; public static final int GL_SAMPLER_BINDING = 0x8919; public static final int GL_RGB10_A2UI = 0x906F; public static final int GL_TEXTURE_SWIZZLE_R = 0x8E42; public static final int GL_TEXTURE_SWIZZLE_G = 0x8E43; public static final int GL_TEXTURE_SWIZZLE_B = 0x8E44; public static final int GL_TEXTURE_SWIZZLE_A = 0x8E45; public static final int GL_GREEN = 0x1904; public static final int GL_BLUE = 0x1905; public static final int GL_INT_2_10_10_10_REV = 0x8D9F; public static final int GL_TRANSFORM_FEEDBACK = 0x8E22; public static final int GL_TRANSFORM_FEEDBACK_PAUSED = 0x8E23; public static final int GL_TRANSFORM_FEEDBACK_ACTIVE = 0x8E24; public static final int GL_TRANSFORM_FEEDBACK_BINDING = 0x8E25; public static final int GL_PROGRAM_BINARY_RETRIEVABLE_HINT = 0x8257; public static final int GL_PROGRAM_BINARY_LENGTH = 0x8741; public static final int GL_NUM_PROGRAM_BINARY_FORMATS = 0x87FE; public static final int GL_PROGRAM_BINARY_FORMATS = 0x87FF; public static final int GL_COMPRESSED_R11_EAC = 0x9270; public static final int GL_COMPRESSED_SIGNED_R11_EAC = 0x9271; public static final int GL_COMPRESSED_RG11_EAC = 0x9272; public static final int GL_COMPRESSED_SIGNED_RG11_EAC = 0x9273; public static final int GL_COMPRESSED_RGB8_ETC2 = 0x9274; public static final int GL_COMPRESSED_SRGB8_ETC2 = 0x9275; public static final int GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276; public static final int GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277; public static final int GL_COMPRESSED_RGBA8_ETC2_EAC = 0x9278; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279; public static final int GL_TEXTURE_IMMUTABLE_FORMAT = 0x912F; public static final int GL_MAX_ELEMENT_INDEX = 0x8D6B; public static final int GL_NUM_SAMPLE_COUNTS = 0x9380; public static final int GL_TEXTURE_IMMUTABLE_LEVELS = 0x82DF; native private static void _nativeClassInit(); static { _nativeClassInit(); } opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp0100644 0000000 0000000 00000001557 13077405420 020450 0ustar000000000 0000000 /* ** ** Copyright 2013, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES31ExtHeader.java-if0100644 0000000 0000000 00000047307 13077405420 021525 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated package android.opengl; public class GLES31Ext { // GL_KHR_blend_equation_advanced public static final int GL_BLEND_ADVANCED_COHERENT_KHR = 0x9285; public static final int GL_MULTIPLY_KHR = 0x9294; public static final int GL_SCREEN_KHR = 0x9295; public static final int GL_OVERLAY_KHR = 0x9296; public static final int GL_DARKEN_KHR = 0x9297; public static final int GL_LIGHTEN_KHR = 0x9298; public static final int GL_COLORDODGE_KHR = 0x9299; public static final int GL_COLORBURN_KHR = 0x929A; public static final int GL_HARDLIGHT_KHR = 0x929B; public static final int GL_SOFTLIGHT_KHR = 0x929C; public static final int GL_DIFFERENCE_KHR = 0x929E; public static final int GL_EXCLUSION_KHR = 0x92A0; public static final int GL_HSL_HUE_KHR = 0x92AD; public static final int GL_HSL_SATURATION_KHR = 0x92AE; public static final int GL_HSL_COLOR_KHR = 0x92AF; public static final int GL_HSL_LUMINOSITY_KHR = 0x92B0; // GL_KHR_debug public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR = 0x8242; public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR = 0x8243; public static final int GL_DEBUG_CALLBACK_FUNCTION_KHR = 0x8244; public static final int GL_DEBUG_CALLBACK_USER_PARAM_KHR = 0x8245; public static final int GL_DEBUG_SOURCE_API_KHR = 0x8246; public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR = 0x8247; public static final int GL_DEBUG_SOURCE_SHADER_COMPILER_KHR = 0x8248; public static final int GL_DEBUG_SOURCE_THIRD_PARTY_KHR = 0x8249; public static final int GL_DEBUG_SOURCE_APPLICATION_KHR = 0x824A; public static final int GL_DEBUG_SOURCE_OTHER_KHR = 0x824B; public static final int GL_DEBUG_TYPE_ERROR_KHR = 0x824C; public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR = 0x824D; public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR = 0x824E; public static final int GL_DEBUG_TYPE_PORTABILITY_KHR = 0x824F; public static final int GL_DEBUG_TYPE_PERFORMANCE_KHR = 0x8250; public static final int GL_DEBUG_TYPE_OTHER_KHR = 0x8251; public static final int GL_DEBUG_TYPE_MARKER_KHR = 0x8268; public static final int GL_DEBUG_TYPE_PUSH_GROUP_KHR = 0x8269; public static final int GL_DEBUG_TYPE_POP_GROUP_KHR = 0x826A; public static final int GL_DEBUG_SEVERITY_NOTIFICATION_KHR = 0x826B; public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR = 0x826C; public static final int GL_DEBUG_GROUP_STACK_DEPTH_KHR = 0x826D; public static final int GL_BUFFER_KHR = 0x82E0; public static final int GL_SHADER_KHR = 0x82E1; public static final int GL_PROGRAM_KHR = 0x82E2; public static final int GL_VERTEX_ARRAY_KHR = 0x8074; public static final int GL_QUERY_KHR = 0x82E3; public static final int GL_SAMPLER_KHR = 0x82E6; public static final int GL_MAX_LABEL_LENGTH_KHR = 0x82E8; public static final int GL_MAX_DEBUG_MESSAGE_LENGTH_KHR = 0x9143; public static final int GL_MAX_DEBUG_LOGGED_MESSAGES_KHR = 0x9144; public static final int GL_DEBUG_LOGGED_MESSAGES_KHR = 0x9145; public static final int GL_DEBUG_SEVERITY_HIGH_KHR = 0x9146; public static final int GL_DEBUG_SEVERITY_MEDIUM_KHR = 0x9147; public static final int GL_DEBUG_SEVERITY_LOW_KHR = 0x9148; public static final int GL_DEBUG_OUTPUT_KHR = 0x92E0; public static final int GL_CONTEXT_FLAG_DEBUG_BIT_KHR = 0x00000002; public static final int GL_STACK_OVERFLOW_KHR = 0x0503; public static final int GL_STACK_UNDERFLOW_KHR = 0x0504; // GL_KHR_texture_compression_astc_ldr public static final int GL_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0; public static final int GL_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1; public static final int GL_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2; public static final int GL_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3; public static final int GL_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4; public static final int GL_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5; public static final int GL_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6; public static final int GL_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7; public static final int GL_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8; public static final int GL_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9; public static final int GL_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA; public static final int GL_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB; public static final int GL_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC; public static final int GL_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD; // GL_OES_sample_shading public static final int GL_SAMPLE_SHADING_OES = 0x8C36; public static final int GL_MIN_SAMPLE_SHADING_VALUE_OES = 0x8C37; // GL_OES_shader_multisample_interpolation public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES = 0x8E5B; public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES = 0x8E5C; public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES = 0x8E5D; // GL_OES_texture_stencil8 public static final int GL_STENCIL_INDEX_OES = 0x1901; public static final int GL_STENCIL_INDEX8_OES = 0x8D48; // GL_OES_texture_storage_multisample_2d_array public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES = 0x9102; public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES = 0x9105; public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x910B; public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x910C; public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x910D; // GL_EXT_geometry_shader public static final int GL_GEOMETRY_SHADER_EXT = 0x8DD9; public static final int GL_GEOMETRY_SHADER_BIT_EXT = 0x00000004; public static final int GL_GEOMETRY_LINKED_VERTICES_OUT_EXT = 0x8916; public static final int GL_GEOMETRY_LINKED_INPUT_TYPE_EXT = 0x8917; public static final int GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT = 0x8918; public static final int GL_GEOMETRY_SHADER_INVOCATIONS_EXT = 0x887F; public static final int GL_LAYER_PROVOKING_VERTEX_EXT = 0x825E; public static final int GL_LINES_ADJACENCY_EXT = 0x000A; public static final int GL_LINE_STRIP_ADJACENCY_EXT = 0x000B; public static final int GL_TRIANGLES_ADJACENCY_EXT = 0x000C; public static final int GL_TRIANGLE_STRIP_ADJACENCY_EXT = 0x000D; public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT = 0x8DDF; public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT = 0x8A2C; public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT = 0x8A32; public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT = 0x9123; public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT = 0x9124; public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT = 0x8DE0; public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT = 0x8DE1; public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT = 0x8E5A; public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT = 0x8C29; public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT = 0x92CF; public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT = 0x92D5; public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT = 0x90CD; public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT = 0x90D7; public static final int GL_FIRST_VERTEX_CONVENTION_EXT = 0x8E4D; public static final int GL_LAST_VERTEX_CONVENTION_EXT = 0x8E4E; public static final int GL_UNDEFINED_VERTEX_EXT = 0x8260; public static final int GL_PRIMITIVES_GENERATED_EXT = 0x8C87; public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT = 0x9312; public static final int GL_MAX_FRAMEBUFFER_LAYERS_EXT = 0x9317; public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT = 0x8DA8; public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT = 0x8DA7; public static final int GL_REFERENCED_BY_GEOMETRY_SHADER_EXT = 0x9309; // GL_EXT_primitive_bounding_box public static final int GL_PRIMITIVE_BOUNDING_BOX_EXT = 0x92BE; // GL_EXT_tessellation_shader public static final int GL_PATCHES_EXT = 0x000E; public static final int GL_PATCH_VERTICES_EXT = 0x8E72; public static final int GL_TESS_CONTROL_OUTPUT_VERTICES_EXT = 0x8E75; public static final int GL_TESS_GEN_MODE_EXT = 0x8E76; public static final int GL_TESS_GEN_SPACING_EXT = 0x8E77; public static final int GL_TESS_GEN_VERTEX_ORDER_EXT = 0x8E78; public static final int GL_TESS_GEN_POINT_MODE_EXT = 0x8E79; public static final int GL_ISOLINES_EXT = 0x8E7A; public static final int GL_QUADS_EXT = 0x0007; public static final int GL_FRACTIONAL_ODD_EXT = 0x8E7B; public static final int GL_FRACTIONAL_EVEN_EXT = 0x8E7C; public static final int GL_MAX_PATCH_VERTICES_EXT = 0x8E7D; public static final int GL_MAX_TESS_GEN_LEVEL_EXT = 0x8E7E; public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT = 0x8E7F; public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT = 0x8E80; public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT = 0x8E81; public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT = 0x8E82; public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT = 0x8E83; public static final int GL_MAX_TESS_PATCH_COMPONENTS_EXT = 0x8E84; public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT = 0x8E85; public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT = 0x8E86; public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT = 0x8E89; public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT = 0x8E8A; public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT = 0x886C; public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT = 0x886D; public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT = 0x8E1E; public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT = 0x8E1F; public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT = 0x92CD; public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT = 0x92CE; public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT = 0x92D3; public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT = 0x92D4; public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT = 0x90CB; public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT = 0x90CC; public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT = 0x90D8; public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT = 0x90D9; public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 0x8221; public static final int GL_IS_PER_PATCH_EXT = 0x92E7; public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT = 0x9307; public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT = 0x9308; public static final int GL_TESS_CONTROL_SHADER_EXT = 0x8E88; public static final int GL_TESS_EVALUATION_SHADER_EXT = 0x8E87; public static final int GL_TESS_CONTROL_SHADER_BIT_EXT = 0x00000008; public static final int GL_TESS_EVALUATION_SHADER_BIT_EXT = 0x00000010; // GL_EXT_texture_border_clamp public static final int GL_TEXTURE_BORDER_COLOR_EXT = 0x1004; public static final int GL_CLAMP_TO_BORDER_EXT = 0x812D; // GL_EXT_texture_buffer public static final int GL_TEXTURE_BUFFER_EXT = 0x8C2A; public static final int GL_TEXTURE_BUFFER_BINDING_EXT = 0x8C2A; public static final int GL_MAX_TEXTURE_BUFFER_SIZE_EXT = 0x8C2B; public static final int GL_TEXTURE_BINDING_BUFFER_EXT = 0x8C2C; public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT = 0x8C2D; public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT = 0x919F; public static final int GL_SAMPLER_BUFFER_EXT = 0x8DC2; public static final int GL_INT_SAMPLER_BUFFER_EXT = 0x8DD0; public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT = 0x8DD8; public static final int GL_IMAGE_BUFFER_EXT = 0x9051; public static final int GL_INT_IMAGE_BUFFER_EXT = 0x905C; public static final int GL_UNSIGNED_INT_IMAGE_BUFFER_EXT = 0x9067; public static final int GL_TEXTURE_BUFFER_OFFSET_EXT = 0x919D; public static final int GL_TEXTURE_BUFFER_SIZE_EXT = 0x919E; // GL_EXT_texture_cube_map_array public static final int GL_TEXTURE_CUBE_MAP_ARRAY_EXT = 0x9009; public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT = 0x900A; public static final int GL_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x900C; public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT = 0x900D; public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x900E; public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x900F; public static final int GL_IMAGE_CUBE_MAP_ARRAY_EXT = 0x9054; public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x905F; public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x906A; // GL_EXT_texture_sRGB_decode public static final int GL_TEXTURE_SRGB_DECODE_EXT = 0x8A48; public static final int GL_DECODE_EXT = 0x8A49; public static final int GL_SKIP_DECODE_EXT = 0x8A4A; native private static void _nativeClassInit(); static { _nativeClassInit(); } private GLES31Ext() {} opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp0100644 0000000 0000000 00000001556 13077405420 021131 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES31Header.java-if0100644 0000000 0000000 00000036750 13077405420 021044 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated package android.opengl; /** OpenGL ES 3.1 */ public class GLES31 extends GLES30 { public static final int GL_VERTEX_SHADER_BIT = 0x00000001; public static final int GL_FRAGMENT_SHADER_BIT = 0x00000002; public static final int GL_COMPUTE_SHADER_BIT = 0x00000020; public static final int GL_ALL_SHADER_BITS = -1; // 0xFFFFFFFF public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 0x00000001; public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 0x00000002; public static final int GL_UNIFORM_BARRIER_BIT = 0x00000004; public static final int GL_TEXTURE_FETCH_BARRIER_BIT = 0x00000008; public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 0x00000020; public static final int GL_COMMAND_BARRIER_BIT = 0x00000040; public static final int GL_PIXEL_BUFFER_BARRIER_BIT = 0x00000080; public static final int GL_TEXTURE_UPDATE_BARRIER_BIT = 0x00000100; public static final int GL_BUFFER_UPDATE_BARRIER_BIT = 0x00000200; public static final int GL_FRAMEBUFFER_BARRIER_BIT = 0x00000400; public static final int GL_TRANSFORM_FEEDBACK_BARRIER_BIT = 0x00000800; public static final int GL_ATOMIC_COUNTER_BARRIER_BIT = 0x00001000; public static final int GL_SHADER_STORAGE_BARRIER_BIT = 0x00002000; public static final int GL_ALL_BARRIER_BITS = -1; // 0xFFFFFFFF public static final int GL_TEXTURE_WIDTH = 0x1000; public static final int GL_TEXTURE_HEIGHT = 0x1001; public static final int GL_TEXTURE_INTERNAL_FORMAT = 0x1003; public static final int GL_STENCIL_INDEX = 0x1901; public static final int GL_TEXTURE_RED_SIZE = 0x805C; public static final int GL_TEXTURE_GREEN_SIZE = 0x805D; public static final int GL_TEXTURE_BLUE_SIZE = 0x805E; public static final int GL_TEXTURE_ALPHA_SIZE = 0x805F; public static final int GL_TEXTURE_DEPTH = 0x8071; public static final int GL_PROGRAM_SEPARABLE = 0x8258; public static final int GL_ACTIVE_PROGRAM = 0x8259; public static final int GL_PROGRAM_PIPELINE_BINDING = 0x825A; public static final int GL_MAX_COMPUTE_SHARED_MEMORY_SIZE = 0x8262; public static final int GL_MAX_COMPUTE_UNIFORM_COMPONENTS = 0x8263; public static final int GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS = 0x8264; public static final int GL_MAX_COMPUTE_ATOMIC_COUNTERS = 0x8265; public static final int GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS = 0x8266; public static final int GL_COMPUTE_WORK_GROUP_SIZE = 0x8267; public static final int GL_MAX_UNIFORM_LOCATIONS = 0x826E; public static final int GL_VERTEX_ATTRIB_BINDING = 0x82D4; public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x82D5; public static final int GL_VERTEX_BINDING_DIVISOR = 0x82D6; public static final int GL_VERTEX_BINDING_OFFSET = 0x82D7; public static final int GL_VERTEX_BINDING_STRIDE = 0x82D8; public static final int GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x82D9; public static final int GL_MAX_VERTEX_ATTRIB_BINDINGS = 0x82DA; public static final int GL_MAX_VERTEX_ATTRIB_STRIDE = 0x82E5; public static final int GL_TEXTURE_COMPRESSED = 0x86A1; public static final int GL_TEXTURE_DEPTH_SIZE = 0x884A; public static final int GL_READ_ONLY = 0x88B8; public static final int GL_WRITE_ONLY = 0x88B9; public static final int GL_READ_WRITE = 0x88BA; public static final int GL_TEXTURE_STENCIL_SIZE = 0x88F1; public static final int GL_TEXTURE_RED_TYPE = 0x8C10; public static final int GL_TEXTURE_GREEN_TYPE = 0x8C11; public static final int GL_TEXTURE_BLUE_TYPE = 0x8C12; public static final int GL_TEXTURE_ALPHA_TYPE = 0x8C13; public static final int GL_TEXTURE_DEPTH_TYPE = 0x8C16; public static final int GL_TEXTURE_SHARED_SIZE = 0x8C3F; public static final int GL_SAMPLE_POSITION = 0x8E50; public static final int GL_SAMPLE_MASK = 0x8E51; public static final int GL_SAMPLE_MASK_VALUE = 0x8E52; public static final int GL_MAX_SAMPLE_MASK_WORDS = 0x8E59; public static final int GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET = 0x8E5E; public static final int GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET = 0x8E5F; public static final int GL_MAX_IMAGE_UNITS = 0x8F38; public static final int GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES = 0x8F39; public static final int GL_IMAGE_BINDING_NAME = 0x8F3A; public static final int GL_IMAGE_BINDING_LEVEL = 0x8F3B; public static final int GL_IMAGE_BINDING_LAYERED = 0x8F3C; public static final int GL_IMAGE_BINDING_LAYER = 0x8F3D; public static final int GL_IMAGE_BINDING_ACCESS = 0x8F3E; public static final int GL_DRAW_INDIRECT_BUFFER = 0x8F3F; public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 0x8F43; public static final int GL_VERTEX_BINDING_BUFFER = 0x8F4F; public static final int GL_IMAGE_2D = 0x904D; public static final int GL_IMAGE_3D = 0x904E; public static final int GL_IMAGE_CUBE = 0x9050; public static final int GL_IMAGE_2D_ARRAY = 0x9053; public static final int GL_INT_IMAGE_2D = 0x9058; public static final int GL_INT_IMAGE_3D = 0x9059; public static final int GL_INT_IMAGE_CUBE = 0x905B; public static final int GL_INT_IMAGE_2D_ARRAY = 0x905E; public static final int GL_UNSIGNED_INT_IMAGE_2D = 0x9063; public static final int GL_UNSIGNED_INT_IMAGE_3D = 0x9064; public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 0x9066; public static final int GL_UNSIGNED_INT_IMAGE_2D_ARRAY = 0x9069; public static final int GL_IMAGE_BINDING_FORMAT = 0x906E; public static final int GL_IMAGE_FORMAT_COMPATIBILITY_TYPE = 0x90C7; public static final int GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE = 0x90C8; public static final int GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS = 0x90C9; public static final int GL_MAX_VERTEX_IMAGE_UNIFORMS = 0x90CA; public static final int GL_MAX_FRAGMENT_IMAGE_UNIFORMS = 0x90CE; public static final int GL_MAX_COMBINED_IMAGE_UNIFORMS = 0x90CF; public static final int GL_SHADER_STORAGE_BUFFER = 0x90D2; public static final int GL_SHADER_STORAGE_BUFFER_BINDING = 0x90D3; public static final int GL_SHADER_STORAGE_BUFFER_START = 0x90D4; public static final int GL_SHADER_STORAGE_BUFFER_SIZE = 0x90D5; public static final int GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS = 0x90D6; public static final int GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS = 0x90DA; public static final int GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS = 0x90DB; public static final int GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS = 0x90DC; public static final int GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS = 0x90DD; public static final int GL_MAX_SHADER_STORAGE_BLOCK_SIZE = 0x90DE; public static final int GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT = 0x90DF; public static final int GL_DEPTH_STENCIL_TEXTURE_MODE = 0x90EA; public static final int GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS = 0x90EB; public static final int GL_DISPATCH_INDIRECT_BUFFER = 0x90EE; public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 0x90EF; public static final int GL_TEXTURE_2D_MULTISAMPLE = 0x9100; public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE = 0x9104; public static final int GL_TEXTURE_SAMPLES = 0x9106; public static final int GL_TEXTURE_FIXED_SAMPLE_LOCATIONS = 0x9107; public static final int GL_SAMPLER_2D_MULTISAMPLE = 0x9108; public static final int GL_INT_SAMPLER_2D_MULTISAMPLE = 0x9109; public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 0x910A; public static final int GL_MAX_COLOR_TEXTURE_SAMPLES = 0x910E; public static final int GL_MAX_DEPTH_TEXTURE_SAMPLES = 0x910F; public static final int GL_MAX_INTEGER_SAMPLES = 0x9110; public static final int GL_COMPUTE_SHADER = 0x91B9; public static final int GL_MAX_COMPUTE_UNIFORM_BLOCKS = 0x91BB; public static final int GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS = 0x91BC; public static final int GL_MAX_COMPUTE_IMAGE_UNIFORMS = 0x91BD; public static final int GL_MAX_COMPUTE_WORK_GROUP_COUNT = 0x91BE; public static final int GL_MAX_COMPUTE_WORK_GROUP_SIZE = 0x91BF; public static final int GL_ATOMIC_COUNTER_BUFFER = 0x92C0; public static final int GL_ATOMIC_COUNTER_BUFFER_BINDING = 0x92C1; public static final int GL_ATOMIC_COUNTER_BUFFER_START = 0x92C2; public static final int GL_ATOMIC_COUNTER_BUFFER_SIZE = 0x92C3; public static final int GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS = 0x92CC; public static final int GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS = 0x92D0; public static final int GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS = 0x92D1; public static final int GL_MAX_VERTEX_ATOMIC_COUNTERS = 0x92D2; public static final int GL_MAX_FRAGMENT_ATOMIC_COUNTERS = 0x92D6; public static final int GL_MAX_COMBINED_ATOMIC_COUNTERS = 0x92D7; public static final int GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE = 0x92D8; public static final int GL_ACTIVE_ATOMIC_COUNTER_BUFFERS = 0x92D9; public static final int GL_UNSIGNED_INT_ATOMIC_COUNTER = 0x92DB; public static final int GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS = 0x92DC; public static final int GL_UNIFORM = 0x92E1; public static final int GL_UNIFORM_BLOCK = 0x92E2; public static final int GL_PROGRAM_INPUT = 0x92E3; public static final int GL_PROGRAM_OUTPUT = 0x92E4; public static final int GL_BUFFER_VARIABLE = 0x92E5; public static final int GL_SHADER_STORAGE_BLOCK = 0x92E6; public static final int GL_TRANSFORM_FEEDBACK_VARYING = 0x92F4; public static final int GL_ACTIVE_RESOURCES = 0x92F5; public static final int GL_MAX_NAME_LENGTH = 0x92F6; public static final int GL_MAX_NUM_ACTIVE_VARIABLES = 0x92F7; public static final int GL_NAME_LENGTH = 0x92F9; public static final int GL_TYPE = 0x92FA; public static final int GL_ARRAY_SIZE = 0x92FB; public static final int GL_OFFSET = 0x92FC; public static final int GL_BLOCK_INDEX = 0x92FD; public static final int GL_ARRAY_STRIDE = 0x92FE; public static final int GL_MATRIX_STRIDE = 0x92FF; public static final int GL_IS_ROW_MAJOR = 0x9300; public static final int GL_ATOMIC_COUNTER_BUFFER_INDEX = 0x9301; public static final int GL_BUFFER_BINDING = 0x9302; public static final int GL_BUFFER_DATA_SIZE = 0x9303; public static final int GL_NUM_ACTIVE_VARIABLES = 0x9304; public static final int GL_ACTIVE_VARIABLES = 0x9305; public static final int GL_REFERENCED_BY_VERTEX_SHADER = 0x9306; public static final int GL_REFERENCED_BY_FRAGMENT_SHADER = 0x930A; public static final int GL_REFERENCED_BY_COMPUTE_SHADER = 0x930B; public static final int GL_TOP_LEVEL_ARRAY_SIZE = 0x930C; public static final int GL_TOP_LEVEL_ARRAY_STRIDE = 0x930D; public static final int GL_LOCATION = 0x930E; public static final int GL_FRAMEBUFFER_DEFAULT_WIDTH = 0x9310; public static final int GL_FRAMEBUFFER_DEFAULT_HEIGHT = 0x9311; public static final int GL_FRAMEBUFFER_DEFAULT_SAMPLES = 0x9313; public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 0x9314; public static final int GL_MAX_FRAMEBUFFER_WIDTH = 0x9315; public static final int GL_MAX_FRAMEBUFFER_HEIGHT = 0x9316; public static final int GL_MAX_FRAMEBUFFER_SAMPLES = 0x9318; native private static void _nativeClassInit(); static { _nativeClassInit(); } /** @hide */ GLES31() {} opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp0100644 0000000 0000000 00000001547 13077405420 020450 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/GLES32Header.java-if0100644 0000000 0000000 00000045440 13077405420 021041 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated package android.opengl; /** OpenGL ES 3.2 */ public class GLES32 extends GLES31 { public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002; public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 0x00000004; public static final int GL_GEOMETRY_SHADER_BIT = 0x00000004; public static final int GL_TESS_CONTROL_SHADER_BIT = 0x00000008; public static final int GL_TESS_EVALUATION_SHADER_BIT = 0x00000010; public static final int GL_QUADS = 0x0007; public static final int GL_LINES_ADJACENCY = 0x000A; public static final int GL_LINE_STRIP_ADJACENCY = 0x000B; public static final int GL_TRIANGLES_ADJACENCY = 0x000C; public static final int GL_TRIANGLE_STRIP_ADJACENCY = 0x000D; public static final int GL_PATCHES = 0x000E; public static final int GL_STACK_OVERFLOW = 0x0503; public static final int GL_STACK_UNDERFLOW = 0x0504; public static final int GL_CONTEXT_LOST = 0x0507; public static final int GL_TEXTURE_BORDER_COLOR = 0x1004; public static final int GL_VERTEX_ARRAY = 0x8074; public static final int GL_CLAMP_TO_BORDER = 0x812D; public static final int GL_CONTEXT_FLAGS = 0x821E; public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 0x8221; public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 0x8242; public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 0x8243; public static final int GL_DEBUG_CALLBACK_FUNCTION = 0x8244; public static final int GL_DEBUG_CALLBACK_USER_PARAM = 0x8245; public static final int GL_DEBUG_SOURCE_API = 0x8246; public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 0x8247; public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 0x8248; public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 0x8249; public static final int GL_DEBUG_SOURCE_APPLICATION = 0x824A; public static final int GL_DEBUG_SOURCE_OTHER = 0x824B; public static final int GL_DEBUG_TYPE_ERROR = 0x824C; public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 0x824D; public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 0x824E; public static final int GL_DEBUG_TYPE_PORTABILITY = 0x824F; public static final int GL_DEBUG_TYPE_PERFORMANCE = 0x8250; public static final int GL_DEBUG_TYPE_OTHER = 0x8251; public static final int GL_LOSE_CONTEXT_ON_RESET = 0x8252; public static final int GL_GUILTY_CONTEXT_RESET = 0x8253; public static final int GL_INNOCENT_CONTEXT_RESET = 0x8254; public static final int GL_UNKNOWN_CONTEXT_RESET = 0x8255; public static final int GL_RESET_NOTIFICATION_STRATEGY = 0x8256; public static final int GL_LAYER_PROVOKING_VERTEX = 0x825E; public static final int GL_UNDEFINED_VERTEX = 0x8260; public static final int GL_NO_RESET_NOTIFICATION = 0x8261; public static final int GL_DEBUG_TYPE_MARKER = 0x8268; public static final int GL_DEBUG_TYPE_PUSH_GROUP = 0x8269; public static final int GL_DEBUG_TYPE_POP_GROUP = 0x826A; public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 0x826B; public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 0x826C; public static final int GL_DEBUG_GROUP_STACK_DEPTH = 0x826D; public static final int GL_BUFFER = 0x82E0; public static final int GL_SHADER = 0x82E1; public static final int GL_PROGRAM = 0x82E2; public static final int GL_QUERY = 0x82E3; public static final int GL_PROGRAM_PIPELINE = 0x82E4; public static final int GL_SAMPLER = 0x82E6; public static final int GL_MAX_LABEL_LENGTH = 0x82E8; public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 0x886C; public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 0x886D; public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 0x887F; public static final int GL_GEOMETRY_VERTICES_OUT = 0x8916; public static final int GL_GEOMETRY_INPUT_TYPE = 0x8917; public static final int GL_GEOMETRY_OUTPUT_TYPE = 0x8918; public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 0x8A2C; public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 0x8A32; public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 0x8C29; public static final int GL_TEXTURE_BUFFER = 0x8C2A; public static final int GL_TEXTURE_BUFFER_BINDING = 0x8C2A; public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 0x8C2B; public static final int GL_TEXTURE_BINDING_BUFFER = 0x8C2C; public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 0x8C2D; public static final int GL_SAMPLE_SHADING = 0x8C36; public static final int GL_MIN_SAMPLE_SHADING_VALUE = 0x8C37; public static final int GL_PRIMITIVES_GENERATED = 0x8C87; public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 0x8DA7; public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 0x8DA8; public static final int GL_SAMPLER_BUFFER = 0x8DC2; public static final int GL_INT_SAMPLER_BUFFER = 0x8DD0; public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 0x8DD8; public static final int GL_GEOMETRY_SHADER = 0x8DD9; public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 0x8DDF; public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 0x8DE0; public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 0x8DE1; public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E1E; public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E1F; public static final int GL_FIRST_VERTEX_CONVENTION = 0x8E4D; public static final int GL_LAST_VERTEX_CONVENTION = 0x8E4E; public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 0x8E5A; public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5B; public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5C; public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 0x8E5D; public static final int GL_PATCH_VERTICES = 0x8E72; public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 0x8E75; public static final int GL_TESS_GEN_MODE = 0x8E76; public static final int GL_TESS_GEN_SPACING = 0x8E77; public static final int GL_TESS_GEN_VERTEX_ORDER = 0x8E78; public static final int GL_TESS_GEN_POINT_MODE = 0x8E79; public static final int GL_ISOLINES = 0x8E7A; public static final int GL_FRACTIONAL_ODD = 0x8E7B; public static final int GL_FRACTIONAL_EVEN = 0x8E7C; public static final int GL_MAX_PATCH_VERTICES = 0x8E7D; public static final int GL_MAX_TESS_GEN_LEVEL = 0x8E7E; public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E7F; public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E80; public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 0x8E81; public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 0x8E82; public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 0x8E83; public static final int GL_MAX_TESS_PATCH_COMPONENTS = 0x8E84; public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 0x8E85; public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 0x8E86; public static final int GL_TESS_EVALUATION_SHADER = 0x8E87; public static final int GL_TESS_CONTROL_SHADER = 0x8E88; public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 0x8E89; public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 0x8E8A; public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 0x9009; public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 0x900A; public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 0x900C; public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 0x900D; public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900E; public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900F; public static final int GL_IMAGE_BUFFER = 0x9051; public static final int GL_IMAGE_CUBE_MAP_ARRAY = 0x9054; public static final int GL_INT_IMAGE_BUFFER = 0x905C; public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 0x905F; public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 0x9067; public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x906A; public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 0x90CB; public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 0x90CC; public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 0x90CD; public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 0x90D7; public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 0x90D8; public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 0x90D9; public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9102; public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 0x9105; public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910B; public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910C; public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910D; public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 0x9123; public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 0x9124; public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 0x9143; public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 0x9144; public static final int GL_DEBUG_LOGGED_MESSAGES = 0x9145; public static final int GL_DEBUG_SEVERITY_HIGH = 0x9146; public static final int GL_DEBUG_SEVERITY_MEDIUM = 0x9147; public static final int GL_DEBUG_SEVERITY_LOW = 0x9148; public static final int GL_TEXTURE_BUFFER_OFFSET = 0x919D; public static final int GL_TEXTURE_BUFFER_SIZE = 0x919E; public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 0x919F; public static final int GL_MULTIPLY = 0x9294; public static final int GL_SCREEN = 0x9295; public static final int GL_OVERLAY = 0x9296; public static final int GL_DARKEN = 0x9297; public static final int GL_LIGHTEN = 0x9298; public static final int GL_COLORDODGE = 0x9299; public static final int GL_COLORBURN = 0x929A; public static final int GL_HARDLIGHT = 0x929B; public static final int GL_SOFTLIGHT = 0x929C; public static final int GL_DIFFERENCE = 0x929E; public static final int GL_EXCLUSION = 0x92A0; public static final int GL_HSL_HUE = 0x92AD; public static final int GL_HSL_SATURATION = 0x92AE; public static final int GL_HSL_COLOR = 0x92AF; public static final int GL_HSL_LUMINOSITY = 0x92B0; public static final int GL_PRIMITIVE_BOUNDING_BOX = 0x92BE; public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 0x92CD; public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 0x92CE; public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 0x92CF; public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 0x92D3; public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 0x92D4; public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 0x92D5; public static final int GL_DEBUG_OUTPUT = 0x92E0; public static final int GL_IS_PER_PATCH = 0x92E7; public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 0x9307; public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x9308; public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 0x9309; public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 0x9312; public static final int GL_MAX_FRAMEBUFFER_LAYERS = 0x9317; public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 0x9381; public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 0x9382; public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 0x93B0; public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 0x93B1; public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 0x93B2; public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 0x93B3; public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 0x93B4; public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 0x93B5; public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 0x93B6; public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 0x93B7; public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 0x93B8; public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 0x93B9; public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 0x93BA; public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 0x93BB; public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 0x93BC; public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 0x93BD; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 0x93D0; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 0x93D1; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 0x93D2; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 0x93D3; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 0x93D4; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 0x93D5; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 0x93D6; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 0x93D7; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 0x93D8; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 0x93D9; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 0x93DA; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 0x93DB; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 0x93DC; public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 0x93DD; native private static void _nativeClassInit(); static { _nativeClassInit(); } private GLES32() {} opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp0100644 0000000 0000000 00000001546 13077405420 020450 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include #include opengl/tools/glgen/stubs/gles11/common.cpp0100644 0000000 0000000 00000033076 13077405420 017570 0ustar000000000 0000000 #include #include #include #include #include static int initialized = 0; static jclass nioAccessClass; static jclass bufferClass; static jmethodID getBasePointerID; static jmethodID getBaseArrayID; static jmethodID getBaseArrayOffsetID; static jfieldID positionID; static jfieldID limitID; static jfieldID elementSizeShiftID; /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ extern "C" { #ifdef GL_VERSION_ES_CM_1_1 GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr, GLsizei count); GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); #endif #ifdef GL_ES_VERSION_2_0 static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) { glVertexAttribPointer(indx, size, type, normalized, stride, pointer); } #endif #ifdef GL_ES_VERSION_3_0 static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count) { glVertexAttribIPointer(indx, size, type, stride, pointer); } #endif } /* Cache method IDs each time the class is loaded. */ static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); getBasePointerID = _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J"); getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); positionID = _env->GetFieldID(bufferClass, "position", "I"); limitID = _env->GetFieldID(bufferClass, "limit", "I"); elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); *remaining = (limit - position) << elementSizeShift; pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer); if (pointer != 0L) { *array = NULL; return reinterpret_cast(pointer); } *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); return NULL; } class ByteArrayGetter { public: static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) { return _env->GetByteArrayElements(array, is_copy); } }; class BooleanArrayGetter { public: static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) { return _env->GetBooleanArrayElements(array, is_copy); } }; class CharArrayGetter { public: static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) { return _env->GetCharArrayElements(array, is_copy); } }; class ShortArrayGetter { public: static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) { return _env->GetShortArrayElements(array, is_copy); } }; class IntArrayGetter { public: static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) { return _env->GetIntArrayElements(array, is_copy); } }; class LongArrayGetter { public: static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) { return _env->GetLongArrayElements(array, is_copy); } }; class FloatArrayGetter { public: static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) { return _env->GetFloatArrayElements(array, is_copy); } }; class DoubleArrayGetter { public: static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) { return _env->GetDoubleArrayElements(array, is_copy); } }; template static void* getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) { return ARRAYGETTER::Get(_env, array, is_copy); } class ByteArrayReleaser { public: static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) { _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class BooleanArrayReleaser { public: static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) { _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class CharArrayReleaser { public: static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) { _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class ShortArrayReleaser { public: static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) { _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class IntArrayReleaser { public: static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) { _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class LongArrayReleaser { public: static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) { _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class FloatArrayReleaser { public: static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) { _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; class DoubleArrayReleaser { public: static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) { _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT); } }; template static void releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) { ARRAYRELEASER::Release(_env, array, data, commit); } static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT); } static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { char* buf = (char*) _env->GetDirectBufferAddress(buffer); if (buf) { jint position = _env->GetIntField(buffer, positionID); jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); buf += position << elementSizeShift; } else { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); } return (void*) buf; } // -------------------------------------------------------------------------- /* * returns the number of values glGet returns for a given pname. * * The code below is written such that pnames requiring only one values * are the default (and are not explicitely tested for). This makes the * checking code much shorter/readable/efficient. * * This means that unknown pnames (e.g.: extensions) will default to 1. If * that unknown pname needs more than 1 value, then the validation check * is incomplete and the app may crash if it passed the wrong number params. */ static int getNeededCount(GLint pname) { int needed = 1; #ifdef GL_ES_VERSION_2_0 // GLES 2.x pnames switch (pname) { case GL_ALIASED_LINE_WIDTH_RANGE: case GL_ALIASED_POINT_SIZE_RANGE: needed = 2; break; case GL_BLEND_COLOR: case GL_COLOR_CLEAR_VALUE: case GL_COLOR_WRITEMASK: case GL_SCISSOR_BOX: case GL_VIEWPORT: needed = 4; break; case GL_COMPRESSED_TEXTURE_FORMATS: glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed); break; case GL_SHADER_BINARY_FORMATS: glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed); break; } #endif #ifdef GL_VERSION_ES_CM_1_1 // GLES 1.x pnames switch (pname) { case GL_ALIASED_LINE_WIDTH_RANGE: case GL_ALIASED_POINT_SIZE_RANGE: case GL_DEPTH_RANGE: case GL_SMOOTH_LINE_WIDTH_RANGE: case GL_SMOOTH_POINT_SIZE_RANGE: needed = 2; break; case GL_CURRENT_NORMAL: case GL_POINT_DISTANCE_ATTENUATION: needed = 3; break; case GL_COLOR_CLEAR_VALUE: case GL_COLOR_WRITEMASK: case GL_CURRENT_COLOR: case GL_CURRENT_TEXTURE_COORDS: case GL_FOG_COLOR: case GL_LIGHT_MODEL_AMBIENT: case GL_SCISSOR_BOX: case GL_VIEWPORT: needed = 4; break; case GL_MODELVIEW_MATRIX: case GL_PROJECTION_MATRIX: case GL_TEXTURE_MATRIX: needed = 16; break; case GL_COMPRESSED_TEXTURE_FORMATS: glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed); break; } #endif return needed; } template static void get (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; CTYPE *params_base = (CTYPE *) 0; jint _remaining; CTYPE *params = (CTYPE *) 0; int _needed = 0; if (!params_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "params == null"; goto exit; } if (offset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "offset < 0"; goto exit; } _remaining = _env->GetArrayLength(params_ref) - offset; _needed = getNeededCount(pname); // if we didn't find this pname, we just assume the user passed // an array of the right size -- this might happen with extensions // or if we forget an enum here. if (_remaining < _needed) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "length - offset < needed"; goto exit; } params_base = (CTYPE *) getArrayPointer( _env, params_ref, (jboolean *)0); params = params_base + offset; GET( (GLenum)pname, (CTYPE *)params ); exit: if (params_base) { releaseArrayPointer( _env, params_ref, params_base, !_exception); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } template static void getarray (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; JTYPEARRAY _array = (JTYPEARRAY) 0; jint _bufferOffset = (jint) 0; jint _remaining; CTYPE *params = (CTYPE *) 0; int _needed = 0; params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset); _remaining /= sizeof(CTYPE); // convert from bytes to item count _needed = getNeededCount(pname); // if we didn't find this pname, we just assume the user passed // an array of the right size -- this might happen with extensions // or if we forget an enum here. if (_needed>0 && _remaining < _needed) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "remaining() < needed"; goto exit; } if (params == NULL) { char * _paramsBase = (char *) getArrayPointer( _env, _array, (jboolean *) 0); params = (CTYPE *) (_paramsBase + _bufferOffset); } GET( (GLenum)pname, (CTYPE *)params ); exit: if (_array) { releaseArrayPointer( _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } // -------------------------------------------------------------------------- opengl/tools/glgen/stubs/gles11/glBindVertexBuffer.cpp0100644 0000000 0000000 00000001103 13077405420 022011 0ustar000000000 0000000 /* void glBindVertexBuffer ( GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride ) */ static void android_glBindVertexBuffer__IIJI (JNIEnv *_env, jobject _this, jint bindingindex, jint buffer, jlong offset, jint stride) { if (sizeof(GLintptr) != sizeof(jlong) && (offset < LONG_MIN || offset > LONG_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "offset too large"); return; } glBindVertexBuffer( (GLuint)bindingindex, (GLuint)buffer, (GLintptr)offset, (GLsizei)stride ); } opengl/tools/glgen/stubs/gles11/glBindVertexBuffer.java0100644 0000000 0000000 00000000403 13077405420 022152 0ustar000000000 0000000 // C function void glBindVertexBuffer ( GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride ) public static native void glBindVertexBuffer( int bindingindex, int buffer, long offset, int stride ); opengl/tools/glgen/stubs/gles11/glBindVertexBuffer.nativeReg0100644 0000000 0000000 00000000117 13077405420 023157 0ustar000000000 0000000 {"glBindVertexBuffer", "(IIJI)V", (void *) android_glBindVertexBuffer__IIJI }, opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.cpp0100644 0000000 0000000 00000004012 13077405420 022657 0ustar000000000 0000000 /* GLuint glCreateShaderProgramv ( GLenum type, GLsizei count, const GLchar *const *strings ) */ static jint android_glCreateShaderProgramv (JNIEnv *_env, jobject _this, jint type, jobjectArray strings) { jint _exception = 0; const char * _exceptionType = NULL; const char * _exceptionMessage = NULL; GLsizei _count; const GLchar** _strings = NULL; jstring* _jstrings = NULL; GLuint _returnValue = 0; if (!strings) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "strings == null"; goto exit; } _count = _env->GetArrayLength(strings); _strings = (const GLchar**) calloc(_count, sizeof(const GLchar*)); if (!_strings) { _exception = 1; _exceptionType = "java/lang/OutOfMemoryError"; _exceptionMessage = "out of memory"; goto exit; } _jstrings = (jstring*) calloc(_count, sizeof(jstring)); if (!_jstrings) { _exception = 1; _exceptionType = "java/lang/OutOfMemoryError"; _exceptionMessage = "out of memory"; goto exit; } for(int i = 0; i < _count; i++) { _jstrings[i] = (jstring) _env->GetObjectArrayElement(strings, i); if (!_jstrings[i]) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "strings == null"; goto exit; } _strings[i] = _env->GetStringUTFChars(_jstrings[i], 0); } _returnValue = glCreateShaderProgramv((GLenum)type, _count, _strings); exit: if (_strings && _jstrings) { for(int i = 0; i < _count; i++) { if (_strings[i] && _jstrings[i]) { _env->ReleaseStringUTFChars(_jstrings[i], _strings[i]); } } } if (_strings) { free(_strings); } if (_jstrings) { free(_jstrings); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } return (jint)_returnValue; } opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.java0100644 0000000 0000000 00000000326 13077405420 023022 0ustar000000000 0000000 // C function GLuint glCreateShaderProgramv ( GLenum type, GLsizei count, const GLchar *const *strings ) public static native int glCreateShaderProgramv( int type, String[] strings ); opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.nativeReg0100644 0000000 0000000 00000000141 13077405420 024020 0ustar000000000 0000000 {"glCreateShaderProgramv", "(I[Ljava/lang/String;)I", (void *) android_glCreateShaderProgramv }, opengl/tools/glgen/stubs/gles11/glDebugMessageCallback.cpp0100644 0000000 0000000 00000000417 13077405420 022564 0ustar000000000 0000000 /* void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam ) */ static void android_glDebugMessageCallback(JNIEnv *_env, jobject _this, jobject callback) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); } opengl/tools/glgen/stubs/gles11/glDebugMessageCallback.java0100644 0000000 0000000 00000000446 13077405420 022725 0ustar000000000 0000000 // C function void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam ) public interface DebugProc { void onMessage(int source, int type, int id, int severity, String message); } public static native void glDebugMessageCallback(DebugProc callback); opengl/tools/glgen/stubs/gles11/glDebugMessageCallback.nativeReg0100644 0000000 0000000 00000000156 13077405420 023726 0ustar000000000 0000000 {"glDebugMessageCallback", "(Landroid/opengl/GLES32$DebugProc;)V", (void *) android_glDebugMessageCallback }, opengl/tools/glgen/stubs/gles11/glDebugMessageCallbackKHR.cpp0100644 0000000 0000000 00000000430 13077405420 023124 0ustar000000000 0000000 /* void glDebugMessageCallbackKHR ( GLDEBUGPROCKHR callback, const void *userParam ) */ static void android_glDebugMessageCallbackKHR(JNIEnv *_env, jobject _this, jobject callback) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); } opengl/tools/glgen/stubs/gles11/glDebugMessageCallbackKHR.java0100644 0000000 0000000 00000000465 13077405420 023273 0ustar000000000 0000000 // C function void glDebugMessageCallbackKHR ( GLDEBUGPROCKHR callback, const void *userParam ) public interface DebugProcKHR { void onMessage(int source, int type, int id, int severity, String message); } public static native void glDebugMessageCallbackKHR(DebugProcKHR callback); opengl/tools/glgen/stubs/gles11/glDebugMessageCallbackKHR.nativeReg0100644 0000000 0000000 00000000172 13077405420 024271 0ustar000000000 0000000 {"glDebugMessageCallbackKHR", "(Landroid/opengl/GLES31Ext$DebugProcKHR;)V", (void *) android_glDebugMessageCallbackKHR }, opengl/tools/glgen/stubs/gles11/glDebugMessageInsertKHR.cpp0100644 0000000 0000000 00000002107 13077405420 022677 0ustar000000000 0000000 /* void glDebugMessageInsertKHR ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) */ static void android_glDebugMessageInsertKHR__IIIILjava_lang_String_2 (JNIEnv *_env, jobject _this, jint source, jint type, jint id, jint severity, jstring buf) { jint _exception = 0; const char * _exceptionType = NULL; const char * _exceptionMessage = NULL; const char* _nativebuf = 0; jint _length = 0; if (!buf) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "buf == null"; goto exit; } _nativebuf = _env->GetStringUTFChars(buf, 0); _length = _env->GetStringUTFLength(buf); glDebugMessageInsertKHR( (GLenum)source, (GLenum)type, (GLuint)id, (GLenum)severity, (GLsizei)_length, (GLchar *)_nativebuf ); exit: if (_nativebuf) { _env->ReleaseStringUTFChars(buf, _nativebuf); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } opengl/tools/glgen/stubs/gles11/glDebugMessageInsertKHR.java0100644 0000000 0000000 00000000454 13077405420 023041 0ustar000000000 0000000 // C function void glDebugMessageInsertKHR ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) public static native void glDebugMessageInsertKHR( int source, int type, int id, int severity, String buf ); opengl/tools/glgen/stubs/gles11/glDebugMessageInsertKHR.nativeReg0100644 0000000 0000000 00000000176 13077405420 024045 0ustar000000000 0000000 {"glDebugMessageInsertKHR", "(IIIILjava/lang/String;)V", (void *) android_glDebugMessageInsertKHR__IIIILjava_lang_String_2 }, opengl/tools/glgen/stubs/gles11/glDispatchComputeIndirect.cpp0100644 0000000 0000000 00000001235 13077405420 023371 0ustar000000000 0000000 /* void glDispatchComputeIndirect ( GLintptr indirect ) */ static void android_glDispatchComputeIndirect(JNIEnv *_env, jobject, jlong indirect) { // 'indirect' is a byte offset, not a pointer. GL checks for negative and too-large values. // Here we only need to check for successful 64-bit to 32-bit conversion. // - jlong is a int64_t (jni.h) // - GLintptr is a long (khrplatform.h) if (sizeof(GLintptr) != sizeof(jlong) && (indirect < LONG_MIN || indirect > LONG_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large"); return; } glDispatchComputeIndirect((GLintptr)indirect); } opengl/tools/glgen/stubs/gles11/glDispatchComputeIndirect.java0100644 0000000 0000000 00000000222 13077405420 023523 0ustar000000000 0000000 // C function void glDispatchComputeIndirect ( GLintptr indirect ); public static native void glDispatchComputeIndirect(long indirect); opengl/tools/glgen/stubs/gles11/glDispatchComputeIndirect.nativeReg0100644 0000000 0000000 00000000124 13077405420 024527 0ustar000000000 0000000 {"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect }, opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.cpp0100644 0000000 0000000 00000001205 13077405420 022351 0ustar000000000 0000000 /* void glDrawArraysIndirect ( GLenum mode, const void *indirect ) */ static void android_glDrawArraysIndirect(JNIEnv *_env, jobject, int mode, jlong indirect) { // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer. // GL checks for too-large values. Here we only need to check for successful signed 64-bit // to unsigned 32-bit conversion. if (sizeof(void*) != sizeof(jlong) && indirect > static_cast(UINT32_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large"); return; } glDrawArraysIndirect(mode, (const void*)indirect); } opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.java0100644 0000000 0000000 00000000242 13077405420 022510 0ustar000000000 0000000 // C function void glDrawArraysIndirect ( GLenum mode, const void *indirect ); public static native void glDrawArraysIndirect(int mode, long indirect); opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.nativeReg0100644 0000000 0000000 00000000113 13077405420 023510 0ustar000000000 0000000 {"glDrawArraysIndirect", "(IJ)V", (void *) android_glDrawArraysIndirect }, opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.cpp0100644 0000000 0000000 00000001252 13077405420 022666 0ustar000000000 0000000 /* void glDrawElementsIndirect ( GLenum mode, GLenum type, const void *indirect ) */ static void android_glDrawElementsIndirect(JNIEnv *_env, jobject, jint mode, jint type, jlong indirect) { // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer. // GL checks for too-large values. Here we only need to check for successful signed 64-bit // to unsigned 32-bit conversion. if (sizeof(void*) != sizeof(jlong) && indirect > static_cast(UINT32_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large"); return; } glDrawElementsIndirect(mode, type, (const void*)indirect); } opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.java0100644 0000000 0000000 00000000270 13077405420 023024 0ustar000000000 0000000 // C function glDrawElementsIndirect ( GLenum mode, GLenum type, const void *indirect ); public static native void glDrawElementsIndirect(int mode, int type, long indirect); opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.nativeReg0100644 0000000 0000000 00000000120 13077405420 024021 0ustar000000000 0000000 {"glDrawElementsIndirect", "(IIJ)V", (void *) android_glDrawElementsIndirect }, opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp0100644 0000000 0000000 00000002632 13077405420 023040 0ustar000000000 0000000 /* void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) */ static void android_glDrawElementsInstanced__IIILjava_nio_Buffer_2I (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint instanceCount) { jarray _array = (jarray) 0; jint _bufferOffset = (jint) 0; jint _remaining; GLvoid *indices = (GLvoid *) 0; indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset); if (indices == NULL) { char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0); indices = (GLvoid *) (_indicesBase + _bufferOffset); } glDrawElementsInstanced( (GLenum)mode, (GLsizei)count, (GLenum)type, (GLvoid *)indices, (GLsizei)instanceCount ); if (_array) { releasePointer(_env, _array, indices, JNI_FALSE); } } /* void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) */ static void android_glDrawElementsInstanced__IIIII (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint indicesOffset, jint instanceCount) { glDrawElementsInstanced( (GLenum)mode, (GLsizei)count, (GLenum)type, (GLvoid *)static_cast(indicesOffset), (GLsizei)instanceCount ); } opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.java0100644 0000000 0000000 00000001160 13077405420 023172 0ustar000000000 0000000 // C function void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) public static native void glDrawElementsInstanced( int mode, int count, int type, java.nio.Buffer indices, int instanceCount ); // C function void glDrawElementsInstanced ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instanceCount ) public static native void glDrawElementsInstanced( int mode, int count, int type, int indicesOffset, int instanceCount ); opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.nativeReg0100644 0000000 0000000 00000000327 13077405420 024201 0ustar000000000 0000000 {"glDrawElementsInstanced", "(IIILjava/nio/Buffer;I)V", (void *) android_glDrawElementsInstanced__IIILjava_nio_Buffer_2I }, {"glDrawElementsInstanced", "(IIIII)V", (void *) android_glDrawElementsInstanced__IIIII }, opengl/tools/glgen/stubs/gles11/glDrawElementsInstancedBaseVertex.cpp0100644 0000000 0000000 00000003636 13077405420 025036 0ustar000000000 0000000 /* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */ static void android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint instanceCount, jint basevertex) { jint _exception = 0; const char * _exceptionType = NULL; const char * _exceptionMessage = NULL; jarray _array = (jarray) 0; jint _bufferOffset = (jint) 0; jint _remaining; void *indices = (void *) 0; indices = (void *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset); if (_remaining < count-basevertex) { _exception = 1; _exceptionType = "java/lang/ArrayIndexOutOfBoundsException"; _exceptionMessage = "remaining() < count-basevertex < needed"; goto exit; } if (indices == NULL) { char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0); indices = (void *) (_indicesBase + _bufferOffset); } glDrawElementsInstancedBaseVertex( (GLenum)mode, (GLsizei)count, (GLenum)type, (void *)indices, (GLsizei)instanceCount, (GLint) basevertex ); exit: if (_array) { releasePointer(_env, _array, indices, JNI_FALSE); } } /* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */ static void android_glDrawElementsInstancedBaseVertex__IIIIII (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint indicesOffset, jint instanceCount, jint basevertex) { glDrawElementsInstancedBaseVertex( (GLenum)mode, (GLsizei)count, (GLenum)type, (void *)static_cast(indicesOffset), (GLsizei)instanceCount, (GLint)basevertex ); } opengl/tools/glgen/stubs/gles11/glDrawElementsInstancedBaseVertex.java0100644 0000000 0000000 00000001350 13077405420 025164 0ustar000000000 0000000 // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) public static native void glDrawElementsInstancedBaseVertex( int mode, int count, int type, java.nio.Buffer indices, int instanceCount, int basevertex ); // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) public static native void glDrawElementsInstancedBaseVertex( int mode, int count, int type, int indicesOffset, int instanceCount, int basevertex ); opengl/tools/glgen/stubs/gles11/glDrawElementsInstancedBaseVertex.nativeReg0100644 0000000 0000000 00000000403 13077405420 026165 0ustar000000000 0000000 {"glDrawElementsInstancedBaseVertex", "(IIILjava/nio/Buffer;II)V", (void *) android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II }, {"glDrawElementsInstancedBaseVertex", "(IIIIII)V", (void *) android_glDrawElementsInstancedBaseVertex__IIIIII }, opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp0100644 0000000 0000000 00000025500 13077405420 021635 0ustar000000000 0000000 /* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static void android_glGetActiveAttrib__III_3II_3II_3II_3BI (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLsizei *length_base = (GLsizei *) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; char *name_base = (char *) 0; jint _nameRemaining; char *name = (char *) 0; if (length_ref) { if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "name == null"; goto exit; } if (nameOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "nameOffset < 0"; goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetActiveAttrib( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, (char *)name ); exit: if (name_base) { _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static void android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (length == NULL) { char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveAttrib( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, reinterpret_cast(name) ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { releaseArrayPointer(_env, _lengthArray, (jint*)length, JNI_TRUE); } } /* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static jstring android_glGetActiveAttrib1 (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetActiveAttrib( (GLuint)program, (GLuint)index, (GLsizei)len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); exit: if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { result = _env->NewStringUTF(buf); } if (buf) { free(buf); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } if (result == 0) { result = _env->NewStringUTF(""); } return result; } /* void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static jstring android_glGetActiveAttrib2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveAttrib( (GLuint)program, (GLuint)index, (GLsizei)len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { free(buf); } return result; } opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java0100644 0000000 0000000 00000003011 13077405420 021765 0ustar000000000 0000000 // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native void glGetActiveAttrib( int program, int index, int bufsize, int[] length, int lengthOffset, int[] size, int sizeOffset, int[] type, int typeOffset, byte[] name, int nameOffset ); // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) /** @hide Method is broken, but used to be public (b/6006380) */ public static native void glGetActiveAttrib( int program, int index, int bufsize, java.nio.IntBuffer length, java.nio.IntBuffer size, java.nio.IntBuffer type, byte name ); // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native String glGetActiveAttrib( int program, int index, int[] size, int sizeOffset, int[] type, int typeOffset ); // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native String glGetActiveAttrib( int program, int index, java.nio.IntBuffer size, java.nio.IntBuffer type ); opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.nativeReg0100644 0000000 0000000 00000001013 13077405420 022770 0ustar000000000 0000000 {"glGetActiveAttrib", "(III[II[II[II[BI)V", (void *) android_glGetActiveAttrib__III_3II_3II_3II_3BI }, {"glGetActiveAttrib", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B }, {"glGetActiveAttrib", "(II[II[II)Ljava/lang/String;", (void *) android_glGetActiveAttrib1 }, {"glGetActiveAttrib", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetActiveAttrib2 }, opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp0100644 0000000 0000000 00000025402 13077405420 022030 0ustar000000000 0000000 /* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static void android_glGetActiveUniform__III_3II_3II_3II_3BI (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLsizei *length_base = (GLsizei *) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; char *name_base = (char *) 0; jint _nameRemaining; char *name = (char *) 0; if (length_ref) { if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "name == null"; goto exit; } if (nameOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "nameOffset < 0"; goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetActiveUniform( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, (char *)name ); exit: if (name_base) { _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static void android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (length == NULL) { char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveUniform( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, reinterpret_cast(name) ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { releaseArrayPointer(_env, _lengthArray, (jint*)length, JNI_TRUE); } } /* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static jstring android_glGetActiveUniform1 (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetActiveUniform( (GLuint)program, (GLuint)index, (GLsizei)len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); exit: if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { result = _env->NewStringUTF(buf); } if (buf) { free(buf); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } if (result == 0) { result = _env->NewStringUTF(""); } return result; } /* void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) */ static jstring android_glGetActiveUniform2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveUniform( (GLuint)program, (GLuint)index, len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { free(buf); } return result; } opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java0100644 0000000 0000000 00000003020 13077405420 022157 0ustar000000000 0000000 // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native void glGetActiveUniform( int program, int index, int bufsize, int[] length, int lengthOffset, int[] size, int sizeOffset, int[] type, int typeOffset, byte[] name, int nameOffset ); // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) /** @hide Method is broken, but used to be public (b/6006380) */ public static native void glGetActiveUniform( int program, int index, int bufsize, java.nio.IntBuffer length, java.nio.IntBuffer size, java.nio.IntBuffer type, byte name ); // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native String glGetActiveUniform( int program, int index, int[] size, int sizeOffset, int[] type, int typeOffset ); // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name ) public static native String glGetActiveUniform( int program, int index, java.nio.IntBuffer size, java.nio.IntBuffer type ); opengl/tools/glgen/stubs/gles11/glGetActiveUniform.nativeReg0100644 0000000 0000000 00000001023 13077405420 023163 0ustar000000000 0000000 {"glGetActiveUniform", "(III[II[II[II[BI)V", (void *) android_glGetActiveUniform__III_3II_3II_3II_3BI }, {"glGetActiveUniform", "(II[II[II)Ljava/lang/String;", (void *) android_glGetActiveUniform1 }, {"glGetActiveUniform", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B }, {"glGetActiveUniform", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetActiveUniform2 }, opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp0100644 0000000 0000000 00000010736 13077405420 023610 0ustar000000000 0000000 /* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static void android_glGetActiveUniformBlockName_III_3II_3BI (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, int bufSize, jintArray length_ref, jint lengthOffset, jbyteArray name_ref, jint nameOffset) { jint _exception = 0; const char* _exceptionType; const char* _exceptionMessage; GLsizei* _length_base = (GLsizei*)0; jint _lengthRemaining; GLsizei* _length = (GLsizei*)0; GLchar* _name_base = (GLchar*)0; jint _nameRemaining; GLchar* _name = (GLchar*)0; if (length_ref) { if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; _length_base = (GLsizei*)_env->GetIntArrayElements( length_ref, (jboolean*)0); _length = _length_base + lengthOffset; } if (!name_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformBlockName == null"; goto exit; } if (nameOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformBlockNameOffset < 0"; goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; _name_base = (GLchar*)_env->GetByteArrayElements( name_ref, (jboolean*)0); _name = _name_base + nameOffset; glGetActiveUniformBlockName( (GLuint)program, (GLuint)uniformBlockIndex, (GLsizei)bufSize, (GLsizei*)_length, (GLchar*)_name ); exit: if (_name_base) { _env->ReleaseByteArrayElements(name_ref, (jbyte*)_name_base, _exception ? JNI_ABORT: 0); } if (_length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)_length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static void android_glGetActiveUniformBlockName_IILjava_nio_Buffer_2Ljava_nio_Buffer_2 (JNIEnv* _env, jobject _this, jint program, jint uniformBlockIndex, jobject length_buf, jobject uniformBlockName_buf) { jint _exception = 0; const char* _exceptionType; const char* _exceptionMessage; jarray _lengthArray = (jarray)0; jint _lengthBufferOffset = (jint)0; GLsizei* _length = (GLsizei*)0; jint _lengthRemaining; jarray _nameArray = (jarray)0; jint _nameBufferOffset = (jint)0; GLchar* _name = (GLchar*)0; jint _nameRemaining; _length = (GLsizei*)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); if (_length == NULL) { GLsizei* _lengthBase = (GLsizei*)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean*)0); _length = (GLsizei*)(_lengthBase + _lengthBufferOffset); } _name = (GLchar*)getPointer(_env, uniformBlockName_buf, &_nameArray, &_nameRemaining, &_nameBufferOffset); if (_name == NULL) { GLchar* _nameBase = (GLchar*)_env->GetPrimitiveArrayCritical(_nameArray, (jboolean*)0); _name = (GLchar*)(_nameBase + _nameBufferOffset); } glGetActiveUniformBlockName( (GLuint)program, (GLuint)uniformBlockIndex, (GLsizei)_nameRemaining, _length, _name ); if (_nameArray) { releasePointer(_env, _nameArray, _name, JNI_TRUE); } if (_lengthArray) { releasePointer(_env, _lengthArray, _length, JNI_TRUE); } } /* void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) */ static jstring android_glGetActiveUniformBlockName_II (JNIEnv *_env, jobject _this, jint program, jint uniformBlockIndex) { GLint len = 0; glGetActiveUniformBlockiv((GLuint)program, (GLuint)uniformBlockIndex, GL_UNIFORM_BLOCK_NAME_LENGTH, &len); GLchar* name = (GLchar*)malloc(len); glGetActiveUniformBlockName((GLuint)program, (GLuint)uniformBlockIndex, len, NULL, name); jstring result = _env->NewStringUTF(name); free(name); return result; } opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.java0100644 0000000 0000000 00000002017 13077405420 023740 0ustar000000000 0000000 // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) public static native void glGetActiveUniformBlockName( int program, int uniformBlockIndex, int bufSize, int[] length, int lengthOffset, byte[] uniformBlockName, int uniformBlockNameOffset ); // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) public static native void glGetActiveUniformBlockName( int program, int uniformBlockIndex, java.nio.Buffer length, java.nio.Buffer uniformBlockName ); // C function void glGetActiveUniformBlockName ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName ) public static native String glGetActiveUniformBlockName( int program, int uniformBlockIndex ); opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.nativeReg0100644 0000000 0000000 00000000572 13077405420 024747 0ustar000000000 0000000 {"glGetActiveUniformBlockName", "(III[II[BI)V", (void *) android_glGetActiveUniformBlockName_III_3II_3BI }, {"glGetActiveUniformBlockName", "(IILjava/nio/Buffer;Ljava/nio/Buffer;)V", (void *) android_glGetActiveUniformBlockName_IILjava_nio_Buffer_2Ljava_nio_Buffer_2 }, {"glGetActiveUniformBlockName", "(II)Ljava/lang/String;", (void *) android_glGetActiveUniformBlockName_II },opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp0100644 0000000 0000000 00000001226 13077405420 021020 0ustar000000000 0000000 /* void glGetBooleanv ( GLenum pname, GLboolean *params ) */ static void android_glGetBooleanv__I_3ZI (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) { get( _env, _this, pname, params_ref, offset); } /* void glGetBooleanv ( GLenum pname, GLboolean *params ) */ static void android_glGetBooleanv__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { getarray( _env, _this, pname, params_buf); } opengl/tools/glgen/stubs/gles11/glGetBooleanv.java0100644 0000000 0000000 00000000563 13077405420 021162 0ustar000000000 0000000 // C function void glGetBooleanv ( GLenum pname, GLboolean *params ) public static native void glGetBooleanv( int pname, boolean[] params, int offset ); // C function void glGetBooleanv ( GLenum pname, GLboolean *params ) public static native void glGetBooleanv( int pname, java.nio.IntBuffer params ); opengl/tools/glgen/stubs/gles11/glGetBooleanv.nativeReg0100644 0000000 0000000 00000000256 13077405420 022164 0ustar000000000 0000000 {"glGetBooleanv", "(I[ZI)V", (void *) android_glGetBooleanv__I_3ZI }, {"glGetBooleanv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetBooleanv__ILjava_nio_IntBuffer_2 }, opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.cpp0100644 0000000 0000000 00000000651 13077405420 022214 0ustar000000000 0000000 /* void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params ) */ static jobject android_glGetBufferPointerv__II (JNIEnv *_env, jobject _this, jint target, jint pname) { GLint64 _mapLength; GLvoid* _p; glGetBufferParameteri64v((GLenum)target, GL_BUFFER_MAP_LENGTH, &_mapLength); glGetBufferPointerv((GLenum)target, (GLenum)pname, &_p); return _env->NewDirectByteBuffer(_p, _mapLength); } opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java0100644 0000000 0000000 00000000311 13077405420 022344 0ustar000000000 0000000 // C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params ) public static native java.nio.Buffer glGetBufferPointerv( int target, int pname ); opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.nativeReg0100644 0000000 0000000 00000000134 13077405420 023352 0ustar000000000 0000000 {"glGetBufferPointerv", "(II)Ljava/nio/Buffer;", (void *) android_glGetBufferPointerv__II },opengl/tools/glgen/stubs/gles11/glGetDebugMessageLog.cpp0100644 0000000 0000000 00000004545 13077405420 022257 0ustar000000000 0000000 /* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jint android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI (JNIEnv *_env, jobject _this, jint count, jint bufSize, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset, jintArray lengths_ref, jint lengthsOffset, jbyteArray messageLog_ref, jint messageLogOffset) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static uint android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref, jobject lengths_ref, jobject messageLog_ref) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jobjectArray android_glGetDebugMessageLog__I_3II_3II_3II_3II (JNIEnv *_env, jobject _this, jint count, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jobjectArray android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } opengl/tools/glgen/stubs/gles11/glGetDebugMessageLog.java0100644 0000000 0000000 00000003564 13077405420 022416 0ustar000000000 0000000 // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native int glGetDebugMessageLog( int count, int bufSize, int[] sources, int sourcesOffset, int[] types, int typesOffset, int[] ids, int idsOffset, int[] severities, int severitiesOffset, int[] lengths, int lengthsOffset, byte[] messageLog, int messageLogOffset); // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native int glGetDebugMessageLog( int count, java.nio.IntBuffer sources, java.nio.IntBuffer types, java.nio.IntBuffer ids, java.nio.IntBuffer severities, java.nio.IntBuffer lengths, java.nio.ByteBuffer messageLog); // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native String[] glGetDebugMessageLog( int count, int[] sources, int sourcesOffset, int[] types, int typesOffset, int[] ids, int idsOffset, int[] severities, int severitiesOffset); // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native String[] glGetDebugMessageLog( int count, java.nio.IntBuffer sources, java.nio.IntBuffer types, java.nio.IntBuffer ids, java.nio.IntBuffer severities); opengl/tools/glgen/stubs/gles11/glGetDebugMessageLog.nativeReg0100644 0000000 0000000 00000001474 13077405420 023417 0ustar000000000 0000000 {"glGetDebugMessageLog", "(II[II[II[II[II[II[BI)I", (void *) android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI }, {"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)I", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 }, {"glGetDebugMessageLog", "(I[II[II[II[II)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__I_3II_3II_3II_3II }, {"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 }, opengl/tools/glgen/stubs/gles11/glGetDebugMessageLogKHR.cpp0100644 0000000 0000000 00000004575 13077405420 022627 0ustar000000000 0000000 /* GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jint android_glGetDebugMessageLogKHR__II_3II_3II_3II_3II_3II_3BI (JNIEnv *_env, jobject _this, jint count, jint bufSize, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset, jintArray lengths_ref, jint lengthsOffset, jbyteArray messageLog_ref, jint messageLogOffset) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static uint android_glGetDebugMessageLogKHR__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref, jobject lengths_ref, jobject messageLog_ref) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jobjectArray android_glGetDebugMessageLogKHR__I_3II_3II_3II_3II (JNIEnv *_env, jobject _this, jint count, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } /* GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */ static jobjectArray android_glGetDebugMessageLogKHR__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return 0; } opengl/tools/glgen/stubs/gles11/glGetDebugMessageLogKHR.java0100644 0000000 0000000 00000003614 13077405420 022757 0ustar000000000 0000000 // C function GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native int glGetDebugMessageLogKHR( int count, int bufSize, int[] sources, int sourcesOffset, int[] types, int typesOffset, int[] ids, int idsOffset, int[] severities, int severitiesOffset, int[] lengths, int lengthsOffset, byte[] messageLog, int messageLogOffset); // C function GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native int glGetDebugMessageLogKHR( int count, java.nio.IntBuffer sources, java.nio.IntBuffer types, java.nio.IntBuffer ids, java.nio.IntBuffer severities, java.nio.IntBuffer lengths, java.nio.ByteBuffer messageLog); // C function GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native String[] glGetDebugMessageLogKHR( int count, int[] sources, int sourcesOffset, int[] types, int typesOffset, int[] ids, int idsOffset, int[] severities, int severitiesOffset); // C function GLuint glGetDebugMessageLogKHR ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) public static native String[] glGetDebugMessageLogKHR( int count, java.nio.IntBuffer sources, java.nio.IntBuffer types, java.nio.IntBuffer ids, java.nio.IntBuffer severities); opengl/tools/glgen/stubs/gles11/glGetDebugMessageLogKHR.nativeReg0100644 0000000 0000000 00000001524 13077405420 023760 0ustar000000000 0000000 {"glGetDebugMessageLogKHR", "(II[II[II[II[II[II[BI)I", (void *) android_glGetDebugMessageLogKHR__II_3II_3II_3II_3II_3II_3BI }, {"glGetDebugMessageLogKHR", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)I", (void *) android_glGetDebugMessageLogKHR__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 }, {"glGetDebugMessageLogKHR", "(I[II[II[II[II)[Ljava/lang/String;", (void *) android_glGetDebugMessageLogKHR__I_3II_3II_3II_3II }, {"glGetDebugMessageLogKHR", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)[Ljava/lang/String;", (void *) android_glGetDebugMessageLogKHR__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 }, opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp0100644 0000000 0000000 00000001202 13077405420 020500 0ustar000000000 0000000 /* void glGetFloatv ( GLenum pname, GLfloat *params ) */ static void android_glGetFloatv__I_3FI (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { get( _env, _this, pname, params_ref, offset); } /* void glGetFloatv ( GLenum pname, GLfloat *params ) */ static void android_glGetFloatv__ILjava_nio_FloatBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { getarray( _env, _this, pname, params_buf); } opengl/tools/glgen/stubs/gles11/glGetFloatv.java0100644 0000000 0000000 00000000547 13077405420 020652 0ustar000000000 0000000 // C function void glGetFloatv ( GLenum pname, GLfloat *params ) public static native void glGetFloatv( int pname, float[] params, int offset ); // C function void glGetFloatv ( GLenum pname, GLfloat *params ) public static native void glGetFloatv( int pname, java.nio.FloatBuffer params ); opengl/tools/glgen/stubs/gles11/glGetFloatv.nativeReg0100644 0000000 0000000 00000000252 13077405420 021646 0ustar000000000 0000000 {"glGetFloatv", "(I[FI)V", (void *) android_glGetFloatv__I_3FI }, {"glGetFloatv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetFloatv__ILjava_nio_FloatBuffer_2 }, opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp0100644 0000000 0000000 00000001162 13077405420 021035 0ustar000000000 0000000 /* void glGetIntegerv ( GLenum pname, GLint *params ) */ static void android_glGetIntegerv__I_3II (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { get( _env, _this, pname, params_ref, offset); } /* void glGetIntegerv ( GLenum pname, GLint *params ) */ static void android_glGetIntegerv__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { getarray( _env, _this, pname, params_buf); } opengl/tools/glgen/stubs/gles11/glGetIntegerv.java0100644 0000000 0000000 00000000547 13077405420 021202 0ustar000000000 0000000 // C function void glGetIntegerv ( GLenum pname, GLint *params ) public static native void glGetIntegerv( int pname, int[] params, int offset ); // C function void glGetIntegerv ( GLenum pname, GLint *params ) public static native void glGetIntegerv( int pname, java.nio.IntBuffer params ); opengl/tools/glgen/stubs/gles11/glGetIntegerv.nativeReg0100644 0000000 0000000 00000000256 13077405420 022202 0ustar000000000 0000000 {"glGetIntegerv", "(I[II)V", (void *) android_glGetIntegerv__I_3II }, {"glGetIntegerv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetIntegerv__ILjava_nio_IntBuffer_2 }, opengl/tools/glgen/stubs/gles11/glGetObjectLabel.cpp0100644 0000000 0000000 00000000506 13077405420 021421 0ustar000000000 0000000 /* void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) */ static jstring android_glGetObjectLabel(JNIEnv *_env, jobject _this, jint identifier, jint name) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetObjectLabel.java0100644 0000000 0000000 00000000312 13077405420 021553 0ustar000000000 0000000 // C function void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) public static native String glGetObjectLabel(int identifier, int name); opengl/tools/glgen/stubs/gles11/glGetObjectLabel.nativeReg0100644 0000000 0000000 00000000124 13077405420 022557 0ustar000000000 0000000 {"glGetObjectLabel", "(II)Ljava/lang/String;", (void *) android_glGetObjectLabel }, opengl/tools/glgen/stubs/gles11/glGetObjectLabelKHR.cpp0100644 0000000 0000000 00000000514 13077405420 021765 0ustar000000000 0000000 /* void glGetObjectLabelKHR ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) */ static jstring android_glGetObjectLabelKHR(JNIEnv *_env, jobject _this, jint identifier, jint name) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetObjectLabelKHR.java0100644 0000000 0000000 00000000320 13077405420 022117 0ustar000000000 0000000 // C function void glGetObjectLabelKHR ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) public static native String glGetObjectLabelKHR(int identifier, int name); opengl/tools/glgen/stubs/gles11/glGetObjectLabelKHR.nativeReg0100644 0000000 0000000 00000000132 13077405420 023123 0ustar000000000 0000000 {"glGetObjectLabelKHR", "(II)Ljava/lang/String;", (void *) android_glGetObjectLabelKHR }, opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabel.cpp0100644 0000000 0000000 00000000454 13077405420 022111 0ustar000000000 0000000 /* void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) */ static jstring android_glGetObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabel.java0100644 0000000 0000000 00000000261 13077405420 022244 0ustar000000000 0000000 // C function void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) public static native String glGetObjectPtrLabel(long ptr); opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabel.nativeReg0100644 0000000 0000000 00000000131 13077405420 023243 0ustar000000000 0000000 {"glGetObjectPtrLabel", "(J)Ljava/lang/String;", (void *) android_glGetObjectPtrLabel }, opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabelKHR.cpp0100644 0000000 0000000 00000000462 13077405420 022455 0ustar000000000 0000000 /* void glGetObjectPtrLabelKHR ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) */ static jstring android_glGetObjectPtrLabelKHR(JNIEnv *_env, jobject _this, jlong ptr) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabelKHR.java0100644 0000000 0000000 00000000267 13077405420 022617 0ustar000000000 0000000 // C function void glGetObjectPtrLabelKHR ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) public static native String glGetObjectPtrLabelKHR(long ptr); opengl/tools/glgen/stubs/gles11/glGetObjectPtrLabelKHR.nativeReg0100644 0000000 0000000 00000000137 13077405420 023616 0ustar000000000 0000000 {"glGetObjectPtrLabelKHR", "(J)Ljava/lang/String;", (void *) android_glGetObjectPtrLabelKHR }, opengl/tools/glgen/stubs/gles11/glGetPointerv.cpp0100644 0000000 0000000 00000000372 13077405420 021062 0ustar000000000 0000000 /* void glGetPointerv ( GLenum pname, void **params ) */ static jlong android_glGetPointerv(JNIEnv *_env, jobject _this, jint pname) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetPointerv.java0100644 0000000 0000000 00000000215 13077405420 021215 0ustar000000000 0000000 // C function void glGetPointerv ( GLenum pname, void **params ) public static native long glGetPointerv( int pname ); opengl/tools/glgen/stubs/gles11/glGetPointerv.nativeReg0100644 0000000 0000000 00000000074 13077405420 022223 0ustar000000000 0000000 {"glGetPointerv", "(I)J", (void *) android_glGetPointerv }, opengl/tools/glgen/stubs/gles11/glGetPointervKHR.cpp0100644 0000000 0000000 00000000402 13077405420 021421 0ustar000000000 0000000 /* void glGetPointervKHR ( GLenum pname, void **params ) */ static jobject android_glGetDebugMessageCallbackKHR(JNIEnv *_env, jobject _this) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetPointervKHR.java0100644 0000000 0000000 00000000220 13077405420 021556 0ustar000000000 0000000 // C function void glGetPointervKHR ( GLenum pname, void **params ) public static native DebugProcKHR glGetDebugMessageCallbackKHR(); opengl/tools/glgen/stubs/gles11/glGetPointervKHR.nativeReg0100644 0000000 0000000 00000000177 13077405420 022574 0ustar000000000 0000000 {"glGetDebugMessageCallbackKHR", "()Landroid/opengl/GLES31Ext$DebugProcKHR;", (void *) android_glGetDebugMessageCallbackKHR }, opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp0100644 0000000 0000000 00000001230 13077405420 022133 0ustar000000000 0000000 #include /* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */ static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) { GLint infoLen = 0; glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (!infoLen) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(infoLen); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } glGetProgramInfoLog(shader, infoLen, NULL, buf); jstring result = _env->NewStringUTF(buf); free(buf); return result; } opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.java0100644 0000000 0000000 00000000320 13077405420 022271 0ustar000000000 0000000 // C function void glGetProgramInfoLog( GLuint program, GLsizei maxLength, GLsizei * length, // GLchar * infoLog); public static native String glGetProgramInfoLog( int program ); opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.nativeReg0100644 0000000 0000000 00000000131 13077405420 023274 0ustar000000000 0000000 {"glGetProgramInfoLog", "(I)Ljava/lang/String;", (void *) android_glGetProgramInfoLog }, opengl/tools/glgen/stubs/gles11/glGetProgramPipelineInfoLog.cpp0100644 0000000 0000000 00000001260 13077405420 023624 0ustar000000000 0000000 #include /* void glGetProgramPipelineInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */ static jstring android_glGetProgramPipelineInfoLog(JNIEnv *_env, jobject, jint shader) { GLint infoLen = 0; glGetProgramPipelineiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (!infoLen) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(infoLen); if (buf == NULL) { jniThrowException(_env, "java/lang/OutOfMemoryError", "out of memory"); return NULL; } glGetProgramPipelineInfoLog(shader, infoLen, NULL, buf); jstring result = _env->NewStringUTF(buf); free(buf); return result; } opengl/tools/glgen/stubs/gles11/glGetProgramPipelineInfoLog.java0100644 0000000 0000000 00000000326 13077405420 023765 0ustar000000000 0000000 // C function void glGetProgramPipelineInfoLog( GLuint program, GLsizei maxLength, GLsizei * length, GLchar * infoLog); public static native String glGetProgramPipelineInfoLog( int program ); opengl/tools/glgen/stubs/gles11/glGetProgramPipelineInfoLog.nativeReg0100644 0000000 0000000 00000000151 13077405420 024764 0ustar000000000 0000000 {"glGetProgramPipelineInfoLog", "(I)Ljava/lang/String;", (void *) android_glGetProgramPipelineInfoLog }, opengl/tools/glgen/stubs/gles11/glGetProgramResourceName.cpp0100644 0000000 0000000 00000000604 13077405420 023172 0ustar000000000 0000000 /* void glGetProgramResourceName ( GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name ) */ static jstring android_glGetProgramResourceName (JNIEnv *_env, jobject _this, jint program, jint programInterface, jint index) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); return NULL; } opengl/tools/glgen/stubs/gles11/glGetProgramResourceName.java0100644 0000000 0000000 00000000442 13077405420 023331 0ustar000000000 0000000 // C function void glGetProgramResourceName ( GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name ) public static native String glGetProgramResourceName( int program, int programInterface, int index ); opengl/tools/glgen/stubs/gles11/glGetProgramResourceName.nativeReg0100644 0000000 0000000 00000000145 13077405420 024334 0ustar000000000 0000000 {"glGetProgramResourceName", "(III)Ljava/lang/String;", (void *) android_glGetProgramResourceName }, opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp0100644 0000000 0000000 00000001224 13077405420 021735 0ustar000000000 0000000 #include /* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */ static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (!infoLen) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(infoLen); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } glGetShaderInfoLog(shader, infoLen, NULL, buf); jstring result = _env->NewStringUTF(buf); free(buf); return result; } opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.java0100644 0000000 0000000 00000000314 13077405420 022073 0ustar000000000 0000000 // C function void glGetShaderInfoLog( GLuint shader, GLsizei maxLength, GLsizei * length, // GLchar * infoLog); public static native String glGetShaderInfoLog( int shader ); opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.nativeReg0100644 0000000 0000000 00000000127 13077405420 023100 0ustar000000000 0000000 {"glGetShaderInfoLog", "(I)Ljava/lang/String;", (void *) android_glGetShaderInfoLog }, opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp0100644 0000000 0000000 00000007227 13077405420 021651 0ustar000000000 0000000 /* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ static void android_glGetShaderSource__II_3II_3BI (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jintArray length_ref, jint lengthOffset, jbyteArray source_ref, jint sourceOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLsizei *length_base = (GLsizei *) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; char *source_base = (char *) 0; jint _sourceRemaining; char *source = (char *) 0; if (length_ref) { if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; } if (!source_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "source == null"; goto exit; } if (sourceOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sourceOffset < 0"; goto exit; } _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset; source_base = (char *) _env->GetByteArrayElements(source_ref, (jboolean *)0); source = source_base + sourceOffset; glGetShaderSource( (GLuint)shader, (GLsizei)bufsize, (GLsizei *)length, (char *)source ); exit: if (source_base) { _env->ReleaseByteArrayElements(source_ref, (jbyte*)source_base, _exception ? JNI_ABORT: 0); } if (length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ static void android_glGetShaderSource__IILjava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jobject length_buf, jbyte source) { jintArray _array = (jintArray) 0; jint _bufferOffset = (jint) 0; jint _remaining; GLsizei *length = (GLsizei *) 0; length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_array, &_remaining, &_bufferOffset); if (length == NULL) { char * _lengthBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _bufferOffset); } glGetShaderSource( (GLuint)shader, (GLsizei)bufsize, (GLsizei *)length, reinterpret_cast(source) ); if (_array) { releaseArrayPointer(_env, _array, (jint*)length, JNI_TRUE); } } /* void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) */ static jstring android_glGetShaderSource(JNIEnv *_env, jobject, jint shader) { GLint shaderLen = 0; glGetShaderiv((GLuint)shader, GL_SHADER_SOURCE_LENGTH, &shaderLen); if (!shaderLen) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(shaderLen); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } glGetShaderSource(shader, shaderLen, NULL, buf); jstring result = _env->NewStringUTF(buf); free(buf); return result; } opengl/tools/glgen/stubs/gles11/glGetShaderSource.java0100644 0000000 0000000 00000001461 13077405420 022002 0ustar000000000 0000000 // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) public static native void glGetShaderSource( int shader, int bufsize, int[] length, int lengthOffset, byte[] source, int sourceOffset ); // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) /** @hide Method is broken, but used to be public (b/6006380) */ public static native void glGetShaderSource( int shader, int bufsize, java.nio.IntBuffer length, byte source ); // C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source ) public static native String glGetShaderSource( int shader ); opengl/tools/glgen/stubs/gles11/glGetShaderSource.nativeReg0100644 0000000 0000000 00000000440 13077405420 023001 0ustar000000000 0000000 {"glGetShaderSource", "(II[II[BI)V", (void *) android_glGetShaderSource__II_3II_3BI }, {"glGetShaderSource", "(IILjava/nio/IntBuffer;B)V", (void *) android_glGetShaderSource__IILjava_nio_IntBuffer_2B }, {"glGetShaderSource", "(I)Ljava/lang/String;", (void *) android_glGetShaderSource }, opengl/tools/glgen/stubs/gles11/glGetString.cpp0100644 0000000 0000000 00000000350 13077405420 020516 0ustar000000000 0000000 /* const GLubyte * glGetString ( GLenum name ) */ static jstring android_glGetString(JNIEnv* _env, jobject, jint name) { const char* chars = (const char*) glGetString((GLenum) name); return _env->NewStringUTF(chars); } opengl/tools/glgen/stubs/gles11/glGetString.java0100644 0000000 0000000 00000000204 13077405420 020653 0ustar000000000 0000000 // C function const GLubyte * glGetString ( GLenum name ) public static native String glGetString( int name ); opengl/tools/glgen/stubs/gles11/glGetString.nativeReg0100644 0000000 0000000 00000000112 13077405420 021654 0ustar000000000 0000000 {"glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString }, opengl/tools/glgen/stubs/gles11/glGetStringi.cpp0100644 0000000 0000000 00000000440 13077405420 020667 0ustar000000000 0000000 /* const GLubyte * glGetStringi ( GLenum name, GLuint index ) */ static jstring android_glGetStringi__II (JNIEnv *_env, jobject _this, jint name, jint index) { const GLubyte* _chars = glGetStringi((GLenum)name, (GLuint)index); return _env->NewStringUTF((const char*)_chars); } opengl/tools/glgen/stubs/gles11/glGetStringi.java0100644 0000000 0000000 00000000250 13077405420 021025 0ustar000000000 0000000 // C function const GLubyte * glGetStringi ( GLenum name, GLuint index ) public static native String glGetStringi( int name, int index ); opengl/tools/glgen/stubs/gles11/glGetStringi.nativeReg0100644 0000000 0000000 00000000117 13077405420 022032 0ustar000000000 0000000 {"glGetStringi", "(II)Ljava/lang/String;", (void *) android_glGetStringi__II },opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp0100644 0000000 0000000 00000030005 13077405420 024170 0ustar000000000 0000000 /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */ static void android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jintArray length_ref, jint lengthOffset, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset, jbyteArray name_ref, jint nameOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLsizei *length_base = (GLsizei *) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; char *name_base = (char *) 0; jint _nameRemaining; char *name = (char *) 0; if (length_ref) { if (lengthOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "lengthOffset < 0"; goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "name == null"; goto exit; } if (nameOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "nameOffset < 0"; goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetTransformFeedbackVarying( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, (char *)name ); exit: if (name_base) { _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */ static void android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated"); } /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */ static void android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) { jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jbyteArray _nameArray = (jbyteArray)0; jint _nameBufferOffset = (jint)0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jint _nameRemaining; GLchar* name = (GLchar*)0; length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset); if (length == NULL) { char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } if (name == NULL) { char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0); name = (GLchar *) (_nameBase + _nameBufferOffset); } glGetTransformFeedbackVarying( (GLuint)program, (GLuint)index, (GLsizei)bufsize, (GLsizei *)length, (GLint *)size, (GLenum *)type, (GLchar*)name ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { releaseArrayPointer(_env, _lengthArray, (jint*)length, JNI_TRUE); } if (_nameArray) { releaseArrayPointer(_env, _nameArray, (jbyte*)name, JNI_TRUE); } } /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */ static jstring android_glGetTransformFeedbackVarying1 (JNIEnv *_env, jobject _this, jint program, jint index, jintArray size_ref, jint sizeOffset, jintArray type_ref, jint typeOffset) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; GLint *size_base = (GLint *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; GLenum *type_base = (GLenum *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } if (!size_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "size == null"; goto exit; } if (sizeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "sizeOffset < 0"; goto exit; } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "type == null"; goto exit; } if (typeOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "typeOffset < 0"; goto exit; } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetTransformFeedbackVarying( (GLuint)program, (GLuint)index, (GLsizei)len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); exit: if (type_base) { _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { result = _env->NewStringUTF(buf); } if (buf) { free(buf); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } if (result == 0) { result = _env->NewStringUTF(""); } return result; } /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */ static jstring android_glGetTransformFeedbackVarying2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; jint _typeRemaining; GLenum *type = (GLenum *) 0; jstring result = 0; GLint len = 0; glGetProgramiv((GLuint)program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); if (!len) { return _env->NewStringUTF(""); } char* buf = (char*) malloc(len); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetTransformFeedbackVarying( (GLuint)program, (GLuint)index, (GLsizei)len, NULL, (GLint *)size, (GLenum *)type, (char *)buf ); if (_typeArray) { releaseArrayPointer(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { releaseArrayPointer(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { free(buf); } return result; } opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java0100644 0000000 0000000 00000004146 13077405420 024336 0ustar000000000 0000000 // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) public static native void glGetTransformFeedbackVarying( int program, int index, int bufsize, int[] length, int lengthOffset, int[] size, int sizeOffset, int[] type, int typeOffset, byte[] name, int nameOffset ); // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) /** * @deprecated * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String. * */ public static native void glGetTransformFeedbackVarying( int program, int index, int bufsize, java.nio.IntBuffer length, java.nio.IntBuffer size, java.nio.IntBuffer type, byte name ); // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) public static native void glGetTransformFeedbackVarying( int program, int index, int bufsize, java.nio.IntBuffer length, java.nio.IntBuffer size, java.nio.IntBuffer type, java.nio.ByteBuffer name ); // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) public static native String glGetTransformFeedbackVarying( int program, int index, int[] size, int sizeOffset, int[] type, int typeOffset ); // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) public static native String glGetTransformFeedbackVarying( int program, int index, java.nio.IntBuffer size, java.nio.IntBuffer type ); opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg0100644 0000000 0000000 00000001564 13077405420 025342 0ustar000000000 0000000 {"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI }, {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B }, {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 }, {"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 }, {"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 }, opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp0100644 0000000 0000000 00000012501 13077405420 022167 0ustar000000000 0000000 /* void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) */ static void android_glGetUniformIndices_array (JNIEnv *_env, jobject _this, jint program, jobjectArray uniformNames_ref, jintArray uniformIndices_ref, jint uniformIndicesOffset) { jint _exception = 0; const char* _exceptionType = NULL; const char* _exceptionMessage = NULL; jint _count = 0; jint _i; const char** _names = NULL; GLuint* _indices_base = NULL; GLuint* _indices = NULL; if (!uniformNames_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformNames == null"; goto exit; } _count = _env->GetArrayLength(uniformNames_ref); _names = (const char**)calloc(_count, sizeof(const char*)); for (_i = 0; _i < _count; _i++) { jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i); if (!_name) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "null uniformNames element"; goto exit; } _names[_i] = _env->GetStringUTFChars(_name, 0); } if (!uniformIndices_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformIndices == null"; goto exit; } if (uniformIndicesOffset < 0) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformIndicesOffset < 0"; goto exit; } if (_env->GetArrayLength(uniformIndices_ref) - uniformIndicesOffset < _count) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "not enough space in uniformIndices"; goto exit; } _indices_base = (GLuint*)_env->GetIntArrayElements( uniformIndices_ref, 0); _indices = _indices_base + uniformIndicesOffset; glGetUniformIndices(program, _count, _names, _indices); exit: if (_indices_base) { _env->ReleaseIntArrayElements(uniformIndices_ref, (jint*)_indices_base, _exception ? JNI_ABORT : 0); } for (_i = _count - 1; _i >= 0; _i--) { if (_names[_i]) { jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i); if (_name) { _env->ReleaseStringUTFChars(_name, _names[_i]); } } } free(_names); if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } /* void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) */ static void android_glGetUniformIndices_buffer (JNIEnv *_env, jobject _this, jint program, jobjectArray uniformNames_ref, jobject uniformIndices_buf) { jint _exception = 0; const char* _exceptionType = NULL; const char* _exceptionMessage = NULL; jint _count = 0; jint _i; const char** _names = NULL; jintArray _uniformIndicesArray = (jintArray)0; jint _uniformIndicesRemaining; jint _uniformIndicesOffset = 0; GLuint* _indices = NULL; char* _indicesBase = NULL; if (!uniformNames_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformNames == null"; goto exit; } if (!uniformIndices_buf) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "uniformIndices == null"; goto exit; } _count = _env->GetArrayLength(uniformNames_ref); _names = (const char**)calloc(_count, sizeof(const char*)); for (_i = 0; _i < _count; _i++) { jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i); if (!_name) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "null uniformNames element"; goto exit; } _names[_i] = _env->GetStringUTFChars(_name, 0); } _indices = (GLuint*)getPointer(_env, uniformIndices_buf, (jarray*)&_uniformIndicesArray, &_uniformIndicesRemaining, &_uniformIndicesOffset); if (!_indices) { _indicesBase = (char*)_env->GetIntArrayElements( _uniformIndicesArray, 0); _indices = (GLuint*)(_indicesBase + _uniformIndicesOffset); } if (_uniformIndicesRemaining < _count) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "not enough space in uniformIndices"; goto exit; } glGetUniformIndices(program, _count, _names, _indices); exit: if (_uniformIndicesArray) { releaseArrayPointer( _env, _uniformIndicesArray, (jint*)_indicesBase, JNI_TRUE); } for (_i = _count - 1; _i >= 0; _i--) { if (_names[_i]) { jstring _name = (jstring)_env->GetObjectArrayElement(uniformNames_ref, _i); if (_name) { _env->ReleaseStringUTFChars(_name, _names[_i]); } } } free(_names); if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } opengl/tools/glgen/stubs/gles11/glGetUniformIndices.java0100644 0000000 0000000 00000001147 13077405420 022332 0ustar000000000 0000000 // C function void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) public static native void glGetUniformIndices( int program, String[] uniformNames, int[] uniformIndices, int uniformIndicesOffset ); // C function void glGetUniformIndices ( GLuint program, GLsizei uniformCount, const GLchar *const *uniformNames, GLuint *uniformIndices ) public static native void glGetUniformIndices( int program, String[] uniformNames, java.nio.IntBuffer uniformIndices ); opengl/tools/glgen/stubs/gles11/glGetUniformIndices.nativeReg0100644 0000000 0000000 00000000332 13077405420 023330 0ustar000000000 0000000 {"glGetUniformIndices", "(I[Ljava/lang/String;[II)V", (void *) android_glGetUniformIndices_array }, {"glGetUniformIndices", "(I[Ljava/lang/String;Ljava/nio/IntBuffer;)V", (void *) android_glGetUniformIndices_buffer }, opengl/tools/glgen/stubs/gles11/glMapBufferRange.cpp0100644 0000000 0000000 00000000743 13077405420 021442 0ustar000000000 0000000 /* GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) */ static jobject android_glMapBufferRange__IIII (JNIEnv *_env, jobject _this, jint target, jint offset, jint length, jint access) { GLvoid* _p = glMapBufferRange((GLenum)target, (GLintptr)offset, (GLsizeiptr)length, (GLbitfield)access); jobject _buf = (jobject)0; if (_p) { _buf = _env->NewDirectByteBuffer(_p, length); } return _buf; } opengl/tools/glgen/stubs/gles11/glMapBufferRange.java0100644 0000000 0000000 00000000410 13077405420 021570 0ustar000000000 0000000 // C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) public static native java.nio.Buffer glMapBufferRange( int target, int offset, int length, int access ); opengl/tools/glgen/stubs/gles11/glMapBufferRange.nativeReg0100644 0000000 0000000 00000000132 13077405420 022574 0ustar000000000 0000000 {"glMapBufferRange", "(IIII)Ljava/nio/Buffer;", (void *) android_glMapBufferRange__IIII },opengl/tools/glgen/stubs/gles11/glObjectPtrLabel.cpp0100644 0000000 0000000 00000000425 13077405420 021447 0ustar000000000 0000000 /* void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label ) */ static void android_glObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr, jstring label) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); } opengl/tools/glgen/stubs/gles11/glObjectPtrLabel.java0100644 0000000 0000000 00000000253 13077405420 021605 0ustar000000000 0000000 // C function void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label ) public static native void glObjectPtrLabel(long ptr, String label); opengl/tools/glgen/stubs/gles11/glObjectPtrLabel.nativeReg0100644 0000000 0000000 00000000124 13077405420 022605 0ustar000000000 0000000 {"glObjectPtrLabel", "(JLjava/lang/String;)V", (void *) android_glObjectPtrLabel }, opengl/tools/glgen/stubs/gles11/glObjectPtrLabelKHR.cpp0100644 0000000 0000000 00000000433 13077405420 022013 0ustar000000000 0000000 /* void glObjectPtrLabelKHR ( const void *ptr, GLsizei length, const GLchar *label ) */ static void android_glObjectPtrLabelKHR(JNIEnv *_env, jobject _this, jlong ptr, jstring label) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented"); } opengl/tools/glgen/stubs/gles11/glObjectPtrLabelKHR.java0100644 0000000 0000000 00000000261 13077405420 022151 0ustar000000000 0000000 // C function void glObjectPtrLabelKHR ( const void *ptr, GLsizei length, const GLchar *label ) public static native void glObjectPtrLabelKHR(long ptr, String label); opengl/tools/glgen/stubs/gles11/glObjectPtrLabelKHR.nativeReg0100644 0000000 0000000 00000000132 13077405420 023151 0ustar000000000 0000000 {"glObjectPtrLabelKHR", "(JLjava/lang/String;)V", (void *) android_glObjectPtrLabelKHR }, opengl/tools/glgen/stubs/gles11/glShaderSource.cpp0100644 0000000 0000000 00000001045 13077405420 021201 0ustar000000000 0000000 /* void glShaderSource ( GLuint shader, GLsizei count, const GLchar ** string, const GLint * length ) */ static void android_glShaderSource (JNIEnv *_env, jobject _this, jint shader, jstring string) { if (!string) { jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null"); return; } const char* nativeString = _env->GetStringUTFChars(string, 0); const char* strings[] = {nativeString}; glShaderSource(shader, 1, strings, 0); _env->ReleaseStringUTFChars(string, nativeString); } opengl/tools/glgen/stubs/gles11/glShaderSource.java0100644 0000000 0000000 00000000324 13077405420 021337 0ustar000000000 0000000 // C function void glShaderSource ( GLuint shader, GLsizei count, const GLchar ** string, const GLint* length ) public static native void glShaderSource( int shader, String string ); opengl/tools/glgen/stubs/gles11/glShaderSource.nativeReg0100644 0000000 0000000 00000000120 13077405420 022334 0ustar000000000 0000000 {"glShaderSource", "(ILjava/lang/String;)V", (void *) android_glShaderSource }, opengl/tools/glgen/stubs/gles11/glTransformFeedbackVaryings.cpp0100644 0000000 0000000 00000003157 13077405420 023723 0ustar000000000 0000000 /* void glTransformFeedbackVaryings ( GLuint program, GLsizei count, const GLchar *varyings, GLenum bufferMode ) */ static void android_glTransformFeedbackVaryings (JNIEnv *_env, jobject _this, jint program, jobjectArray varyings_ref, jint bufferMode) { jint _exception = 0; const char* _exceptionType = NULL; const char* _exceptionMessage = NULL; jint _count = 0, _i; const char** _varyings = NULL; const char* _varying = NULL; if (!varyings_ref) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "varyings == null"; goto exit; } _count = _env->GetArrayLength(varyings_ref); _varyings = (const char**)calloc(_count, sizeof(const char*)); for (_i = 0; _i < _count; _i++) { jstring _varying = (jstring)_env->GetObjectArrayElement(varyings_ref, _i); if (!_varying) { _exception = 1; _exceptionType = "java/lang/IllegalArgumentException"; _exceptionMessage = "null varyings element"; goto exit; } _varyings[_i] = _env->GetStringUTFChars(_varying, 0); } glTransformFeedbackVaryings(program, _count, _varyings, bufferMode); exit: for (_i = _count - 1; _i >= 0; _i--) { if (_varyings[_i]) { jstring _varying = (jstring)_env->GetObjectArrayElement(varyings_ref, _i); if (_varying) { _env->ReleaseStringUTFChars(_varying, _varyings[_i]); } } } free(_varyings); if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); } } opengl/tools/glgen/stubs/gles11/glTransformFeedbackVaryings.java0100644 0000000 0000000 00000000413 13077405420 024052 0ustar000000000 0000000 // C function void glTransformFeedbackVaryings ( GLuint program, GLsizei count, const GLchar *varyings, GLenum bufferMode ) public static native void glTransformFeedbackVaryings( int program, String[] varyings, int bufferMode ); opengl/tools/glgen/stubs/gles11/glTransformFeedbackVaryings.nativeReg0100644 0000000 0000000 00000000154 13077405420 025057 0ustar000000000 0000000 {"glTransformFeedbackVaryings", "(I[Ljava/lang/String;I)V", (void *) android_glTransformFeedbackVaryings }, opengl/tools/glgen/stubs/jsr239/0040755 0000000 0000000 00000000000 13077405420 015526 5ustar000000000 0000000 opengl/tools/glgen/stubs/jsr239/GL10ExtHeader.java-if0100644 0000000 0000000 00000001365 13077405420 021224 0ustar000000000 0000000 ** ** Copyright 2007, 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. */ // This source file is automatically generated package javax.microedition.khronos.opengles; public interface GL10Ext extends GL { opengl/tools/glgen/stubs/jsr239/GL10Header.java-if0100644 0000000 0000000 00000034570 13077405420 020547 0ustar000000000 0000000 ** ** Copyright 2006, 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. */ // This source file is automatically generated package javax.microedition.khronos.opengles; public interface GL10 extends GL { int GL_ADD = 0x0104; int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; int GL_ALIASED_POINT_SIZE_RANGE = 0x846D; int GL_ALPHA = 0x1906; int GL_ALPHA_BITS = 0x0D55; int GL_ALPHA_TEST = 0x0BC0; int GL_ALWAYS = 0x0207; int GL_AMBIENT = 0x1200; int GL_AMBIENT_AND_DIFFUSE = 0x1602; int GL_AND = 0x1501; int GL_AND_INVERTED = 0x1504; int GL_AND_REVERSE = 0x1502; int GL_BACK = 0x0405; int GL_BLEND = 0x0BE2; int GL_BLUE_BITS = 0x0D54; int GL_BYTE = 0x1400; int GL_CCW = 0x0901; int GL_CLAMP_TO_EDGE = 0x812F; int GL_CLEAR = 0x1500; int GL_COLOR_ARRAY = 0x8076; int GL_COLOR_BUFFER_BIT = 0x4000; int GL_COLOR_LOGIC_OP = 0x0BF2; int GL_COLOR_MATERIAL = 0x0B57; int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; int GL_CONSTANT_ATTENUATION = 0x1207; int GL_COPY = 0x1503; int GL_COPY_INVERTED = 0x150C; int GL_CULL_FACE = 0x0B44; int GL_CW = 0x0900; int GL_DECAL = 0x2101; int GL_DECR = 0x1E03; int GL_DEPTH_BITS = 0x0D56; int GL_DEPTH_BUFFER_BIT = 0x0100; int GL_DEPTH_TEST = 0x0B71; int GL_DIFFUSE = 0x1201; int GL_DITHER = 0x0BD0; int GL_DONT_CARE = 0x1100; int GL_DST_ALPHA = 0x0304; int GL_DST_COLOR = 0x0306; int GL_EMISSION = 0x1600; int GL_EQUAL = 0x0202; int GL_EQUIV = 0x1509; int GL_EXP = 0x0800; int GL_EXP2 = 0x0801; int GL_EXTENSIONS = 0x1F03; int GL_FALSE = 0; int GL_FASTEST = 0x1101; int GL_FIXED = 0x140C; int GL_FLAT = 0x1D00; int GL_FLOAT = 0x1406; int GL_FOG = 0x0B60; int GL_FOG_COLOR = 0x0B66; int GL_FOG_DENSITY = 0x0B62; int GL_FOG_END = 0x0B64; int GL_FOG_HINT = 0x0C54; int GL_FOG_MODE = 0x0B65; int GL_FOG_START = 0x0B63; int GL_FRONT = 0x0404; int GL_FRONT_AND_BACK = 0x0408; int GL_GEQUAL = 0x0206; int GL_GREATER = 0x0204; int GL_GREEN_BITS = 0x0D53; int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x8B9B; int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x8B9A; int GL_INCR = 0x1E02; int GL_INVALID_ENUM = 0x0500; int GL_INVALID_OPERATION = 0x0502; int GL_INVALID_VALUE = 0x0501; int GL_INVERT = 0x150A; int GL_KEEP = 0x1E00; int GL_LEQUAL = 0x0203; int GL_LESS = 0x0201; int GL_LIGHT_MODEL_AMBIENT = 0x0B53; int GL_LIGHT_MODEL_TWO_SIDE = 0x0B52; int GL_LIGHT0 = 0x4000; int GL_LIGHT1 = 0x4001; int GL_LIGHT2 = 0x4002; int GL_LIGHT3 = 0x4003; int GL_LIGHT4 = 0x4004; int GL_LIGHT5 = 0x4005; int GL_LIGHT6 = 0x4006; int GL_LIGHT7 = 0x4007; int GL_LIGHTING = 0x0B50; int GL_LINE_LOOP = 0x0002; int GL_LINE_SMOOTH = 0x0B20; int GL_LINE_SMOOTH_HINT = 0x0C52; int GL_LINE_STRIP = 0x0003; int GL_LINEAR = 0x2601; int GL_LINEAR_ATTENUATION = 0x1208; int GL_LINEAR_MIPMAP_LINEAR = 0x2703; int GL_LINEAR_MIPMAP_NEAREST = 0x2701; int GL_LINES = 0x0001; int GL_LUMINANCE = 0x1909; int GL_LUMINANCE_ALPHA = 0x190A; int GL_MAX_ELEMENTS_INDICES = 0x80E9; int GL_MAX_ELEMENTS_VERTICES = 0x80E8; int GL_MAX_LIGHTS = 0x0D31; int GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36; int GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38; int GL_MAX_TEXTURE_SIZE = 0x0D33; int GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39; int GL_MAX_TEXTURE_UNITS = 0x84E2; int GL_MAX_VIEWPORT_DIMS = 0x0D3A; int GL_MODELVIEW = 0x1700; int GL_MODULATE = 0x2100; int GL_MULTISAMPLE = 0x809D; int GL_NAND = 0x150E; int GL_NEAREST = 0x2600; int GL_NEAREST_MIPMAP_LINEAR = 0x2702; int GL_NEAREST_MIPMAP_NEAREST = 0x2700; int GL_NEVER = 0x0200; int GL_NICEST = 0x1102; int GL_NO_ERROR = 0; int GL_NOOP = 0x1505; int GL_NOR = 0x1508; int GL_NORMAL_ARRAY = 0x8075; int GL_NORMALIZE = 0x0BA1; int GL_NOTEQUAL = 0x0205; int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; int GL_ONE = 1; int GL_ONE_MINUS_DST_ALPHA = 0x0305; int GL_ONE_MINUS_DST_COLOR = 0x0307; int GL_ONE_MINUS_SRC_ALPHA = 0x0303; int GL_ONE_MINUS_SRC_COLOR = 0x0301; int GL_OR = 0x1507; int GL_OR_INVERTED = 0x150D; int GL_OR_REVERSE = 0x150B; int GL_OUT_OF_MEMORY = 0x0505; int GL_PACK_ALIGNMENT = 0x0D05; int GL_PALETTE4_R5_G6_B5_OES = 0x8B92; int GL_PALETTE4_RGB5_A1_OES = 0x8B94; int GL_PALETTE4_RGB8_OES = 0x8B90; int GL_PALETTE4_RGBA4_OES = 0x8B93; int GL_PALETTE4_RGBA8_OES = 0x8B91; int GL_PALETTE8_R5_G6_B5_OES = 0x8B97; int GL_PALETTE8_RGB5_A1_OES = 0x8B99; int GL_PALETTE8_RGB8_OES = 0x8B95; int GL_PALETTE8_RGBA4_OES = 0x8B98; int GL_PALETTE8_RGBA8_OES = 0x8B96; int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50; int GL_POINT_SMOOTH = 0x0B10; int GL_POINT_SMOOTH_HINT = 0x0C51; int GL_POINTS = 0x0000; int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; int GL_POINT_SIZE = 0x0B11; int GL_POLYGON_OFFSET_FILL = 0x8037; int GL_POLYGON_SMOOTH_HINT = 0x0C53; int GL_POSITION = 0x1203; int GL_PROJECTION = 0x1701; int GL_QUADRATIC_ATTENUATION = 0x1209; int GL_RED_BITS = 0x0D52; int GL_RENDERER = 0x1F01; int GL_REPEAT = 0x2901; int GL_REPLACE = 0x1E01; int GL_RESCALE_NORMAL = 0x803A; int GL_RGB = 0x1907; int GL_RGBA = 0x1908; int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; int GL_SAMPLE_ALPHA_TO_ONE = 0x809F; int GL_SAMPLE_COVERAGE = 0x80A0; int GL_SCISSOR_TEST = 0x0C11; int GL_SET = 0x150F; int GL_SHININESS = 0x1601; int GL_SHORT = 0x1402; int GL_SMOOTH = 0x1D01; int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22; int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12; int GL_SPECULAR = 0x1202; int GL_SPOT_CUTOFF = 0x1206; int GL_SPOT_DIRECTION = 0x1204; int GL_SPOT_EXPONENT = 0x1205; int GL_SRC_ALPHA = 0x0302; int GL_SRC_ALPHA_SATURATE = 0x0308; int GL_SRC_COLOR = 0x0300; int GL_STACK_OVERFLOW = 0x0503; int GL_STACK_UNDERFLOW = 0x0504; int GL_STENCIL_BITS = 0x0D57; int GL_STENCIL_BUFFER_BIT = 0x0400; int GL_STENCIL_TEST = 0x0B90; int GL_SUBPIXEL_BITS = 0x0D50; int GL_TEXTURE = 0x1702; int GL_TEXTURE_2D = 0x0DE1; int GL_TEXTURE_COORD_ARRAY = 0x8078; int GL_TEXTURE_ENV = 0x2300; int GL_TEXTURE_ENV_COLOR = 0x2201; int GL_TEXTURE_ENV_MODE = 0x2200; int GL_TEXTURE_MAG_FILTER = 0x2800; int GL_TEXTURE_MIN_FILTER = 0x2801; int GL_TEXTURE_WRAP_S = 0x2802; int GL_TEXTURE_WRAP_T = 0x2803; int GL_TEXTURE0 = 0x84C0; int GL_TEXTURE1 = 0x84C1; int GL_TEXTURE2 = 0x84C2; int GL_TEXTURE3 = 0x84C3; int GL_TEXTURE4 = 0x84C4; int GL_TEXTURE5 = 0x84C5; int GL_TEXTURE6 = 0x84C6; int GL_TEXTURE7 = 0x84C7; int GL_TEXTURE8 = 0x84C8; int GL_TEXTURE9 = 0x84C9; int GL_TEXTURE10 = 0x84CA; int GL_TEXTURE11 = 0x84CB; int GL_TEXTURE12 = 0x84CC; int GL_TEXTURE13 = 0x84CD; int GL_TEXTURE14 = 0x84CE; int GL_TEXTURE15 = 0x84CF; int GL_TEXTURE16 = 0x84D0; int GL_TEXTURE17 = 0x84D1; int GL_TEXTURE18 = 0x84D2; int GL_TEXTURE19 = 0x84D3; int GL_TEXTURE20 = 0x84D4; int GL_TEXTURE21 = 0x84D5; int GL_TEXTURE22 = 0x84D6; int GL_TEXTURE23 = 0x84D7; int GL_TEXTURE24 = 0x84D8; int GL_TEXTURE25 = 0x84D9; int GL_TEXTURE26 = 0x84DA; int GL_TEXTURE27 = 0x84DB; int GL_TEXTURE28 = 0x84DC; int GL_TEXTURE29 = 0x84DD; int GL_TEXTURE30 = 0x84DE; int GL_TEXTURE31 = 0x84DF; int GL_TRIANGLE_FAN = 0x0006; int GL_TRIANGLE_STRIP = 0x0005; int GL_TRIANGLES = 0x0004; int GL_TRUE = 1; int GL_UNPACK_ALIGNMENT = 0x0CF5; int GL_UNSIGNED_BYTE = 0x1401; int GL_UNSIGNED_SHORT = 0x1403; int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; int GL_VENDOR = 0x1F00; int GL_VERSION = 0x1F02; int GL_VERTEX_ARRAY = 0x8074; int GL_XOR = 0x1506; int GL_ZERO = 0; opengl/tools/glgen/stubs/jsr239/GL11ExtHeader.java-if0100644 0000000 0000000 00000003363 13077405420 021225 0ustar000000000 0000000 ** ** Copyright 2007, 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. */ // This source file is automatically generated package javax.microedition.khronos.opengles; public interface GL11Ext extends GL { int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E; int GL_MATRIX_INDEX_ARRAY_OES = 0x8844; int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x8849; int GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x8846; int GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x8848; int GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x8847; int GL_MATRIX_PALETTE_OES = 0x8840; int GL_MAX_PALETTE_MATRICES_OES = 0x8842; int GL_MAX_VERTEX_UNITS_OES = 0x86A4; int GL_TEXTURE_CROP_RECT_OES = 0x8B9D; int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x889E; int GL_WEIGHT_ARRAY_OES = 0x86AD; int GL_WEIGHT_ARRAY_POINTER_OES = 0x86AC; int GL_WEIGHT_ARRAY_SIZE_OES = 0x86AB; int GL_WEIGHT_ARRAY_STRIDE_OES = 0x86AA; int GL_WEIGHT_ARRAY_TYPE_OES = 0x86A9; void glTexParameterfv(int target, int pname, float[] param, int offset); opengl/tools/glgen/stubs/jsr239/GL11ExtensionPackHeader.java-if0100644 0000000 0000000 00000015177 13077405420 023246 0ustar000000000 0000000 ** ** Copyright 2007, 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. */ // This source file is automatically generated package javax.microedition.khronos.opengles; public interface GL11ExtensionPack extends GL { int GL_BLEND_DST_ALPHA = 0x80CA; int GL_BLEND_DST_RGB = 0x80C8; int GL_BLEND_EQUATION = 0x8009; int GL_BLEND_EQUATION_ALPHA = 0x883D; int GL_BLEND_EQUATION_RGB = 0x8009; int GL_BLEND_SRC_ALPHA = 0x80CB; int GL_BLEND_SRC_RGB = 0x80C9; int GL_COLOR_ATTACHMENT0_OES = 0x8CE0; int GL_COLOR_ATTACHMENT1_OES = 0x8CE1; int GL_COLOR_ATTACHMENT2_OES = 0x8CE2; int GL_COLOR_ATTACHMENT3_OES = 0x8CE3; int GL_COLOR_ATTACHMENT4_OES = 0x8CE4; int GL_COLOR_ATTACHMENT5_OES = 0x8CE5; int GL_COLOR_ATTACHMENT6_OES = 0x8CE6; int GL_COLOR_ATTACHMENT7_OES = 0x8CE7; int GL_COLOR_ATTACHMENT8_OES = 0x8CE8; int GL_COLOR_ATTACHMENT9_OES = 0x8CE9; int GL_COLOR_ATTACHMENT10_OES = 0x8CEA; int GL_COLOR_ATTACHMENT11_OES = 0x8CEB; int GL_COLOR_ATTACHMENT12_OES = 0x8CEC; int GL_COLOR_ATTACHMENT13_OES = 0x8CED; int GL_COLOR_ATTACHMENT14_OES = 0x8CEE; int GL_COLOR_ATTACHMENT15_OES = 0x8CEF; int GL_DECR_WRAP = 0x8508; int GL_DEPTH_ATTACHMENT_OES = 0x8D00; int GL_DEPTH_COMPONENT = 0x1902; int GL_DEPTH_COMPONENT16 = 0x81A5; int GL_DEPTH_COMPONENT24 = 0x81A6; int GL_DEPTH_COMPONENT32 = 0x81A7; int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x8CD1; int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x8CD0; int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3; int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x8CD2; int GL_FRAMEBUFFER_BINDING_OES = 0x8CA6; int GL_FRAMEBUFFER_COMPLETE_OES = 0x8CD5; int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x8CD6; int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x8CD9; int GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES = 0x8CDB; int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x8CDA; int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x8CD7; int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES = 0x8CDC; int GL_FRAMEBUFFER_OES = 0x8D40; int GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x8CDD; int GL_FUNC_ADD = 0x8006; int GL_FUNC_REVERSE_SUBTRACT = 0x800B; int GL_FUNC_SUBTRACT = 0x800A; int GL_INCR_WRAP = 0x8507; int GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x0506; int GL_MAX_COLOR_ATTACHMENTS_OES = 0x8CDF; int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; int GL_MAX_RENDERBUFFER_SIZE_OES = 0x84E8; int GL_MIRRORED_REPEAT = 0x8370; int GL_NORMAL_MAP = 0x8511; int GL_REFLECTION_MAP = 0x8512; int GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x8D53; int GL_RENDERBUFFER_BINDING_OES = 0x8CA7; int GL_RENDERBUFFER_BLUE_SIZE_OES = 0x8D52; int GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x8D54; int GL_RENDERBUFFER_GREEN_SIZE_OES = 0x8D51; int GL_RENDERBUFFER_HEIGHT_OES = 0x8D43; int GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x8D44; int GL_RENDERBUFFER_OES = 0x8D41; int GL_RENDERBUFFER_RED_SIZE_OES = 0x8D50; int GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x8D55; int GL_RENDERBUFFER_WIDTH_OES = 0x8D42; int GL_RGB5_A1 = 0x8057; int GL_RGB565_OES = 0x8D62; int GL_RGB8 = 0x8051; int GL_RGBA4 = 0x8056; int GL_RGBA8 = 0x8058; int GL_STENCIL_ATTACHMENT_OES = 0x8D20; int GL_STENCIL_INDEX = 0x1901; int GL_STENCIL_INDEX1_OES = 0x8D46; int GL_STENCIL_INDEX4_OES = 0x8D47; int GL_STENCIL_INDEX8_OES = 0x8D48; int GL_STR = -1; int GL_TEXTURE_BINDING_CUBE_MAP = 0x8514; int GL_TEXTURE_CUBE_MAP = 0x8513; int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; int GL_TEXTURE_GEN_MODE = 0x2500; int GL_TEXTURE_GEN_STR = 0x8D60; opengl/tools/glgen/stubs/jsr239/GL11Header.java-if0100644 0000000 0000000 00000020103 13077405420 020533 0ustar000000000 0000000 ** ** Copyright 2006, 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. */ // This source file is automatically generated package javax.microedition.khronos.opengles; public interface GL11 extends GL10 { int GL_ACTIVE_TEXTURE = 0x84E0; int GL_ADD_SIGNED = 0x8574; int GL_ALPHA_SCALE = 0x0D1C; int GL_ALPHA_TEST_FUNC = 0x0BC1; int GL_ALPHA_TEST_REF = 0x0BC2; int GL_ARRAY_BUFFER = 0x8892; int GL_ARRAY_BUFFER_BINDING = 0x8894; int GL_BLEND_DST = 0x0BE0; int GL_BLEND_SRC = 0x0BE1; int GL_BUFFER_ACCESS = 0x88BB; int GL_BUFFER_SIZE = 0x8764; int GL_BUFFER_USAGE = 0x8765; int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1; int GL_CLIP_PLANE0 = 0x3000; int GL_CLIP_PLANE1 = 0x3001; int GL_CLIP_PLANE2 = 0x3002; int GL_CLIP_PLANE3 = 0x3003; int GL_CLIP_PLANE4 = 0x3004; int GL_CLIP_PLANE5 = 0x3005; int GL_COLOR_ARRAY_BUFFER_BINDING = 0x8898; int GL_COLOR_ARRAY_POINTER = 0x8090; int GL_COLOR_ARRAY_SIZE = 0x8081; int GL_COLOR_ARRAY_STRIDE = 0x8083; int GL_COLOR_ARRAY_TYPE = 0x8082; int GL_COLOR_CLEAR_VALUE = 0x0C22; int GL_COLOR_WRITEMASK = 0x0C23; int GL_COMBINE = 0x8570; int GL_COMBINE_ALPHA = 0x8572; int GL_COMBINE_RGB = 0x8571; int GL_CONSTANT = 0x8576; int GL_COORD_REPLACE_OES = 0x8862; int GL_CULL_FACE_MODE = 0x0B45; int GL_CURRENT_COLOR = 0x0B00; int GL_CURRENT_NORMAL = 0x0B02; int GL_CURRENT_TEXTURE_COORDS = 0x0B03; int GL_DEPTH_CLEAR_VALUE = 0x0B73; int GL_DEPTH_FUNC = 0x0B74; int GL_DEPTH_RANGE = 0x0B70; int GL_DEPTH_WRITEMASK = 0x0B72; int GL_DOT3_RGB = 0x86AE; int GL_DOT3_RGBA = 0x86AF; int GL_DYNAMIC_DRAW = 0x88E8; int GL_ELEMENT_ARRAY_BUFFER = 0x8893; int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; int GL_FRONT_FACE = 0x0B46; int GL_GENERATE_MIPMAP = 0x8191; int GL_GENERATE_MIPMAP_HINT = 0x8192; int GL_INTERPOLATE = 0x8575; int GL_LINE_WIDTH = 0x0B21; int GL_LOGIC_OP_MODE = 0x0BF0; int GL_MATRIX_MODE = 0x0BA0; int GL_MAX_CLIP_PLANES = 0x0D32; int GL_MODELVIEW_MATRIX = 0x0BA6; int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; int GL_MODELVIEW_STACK_DEPTH = 0x0BA3; int GL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897; int GL_NORMAL_ARRAY_POINTER = 0x808F; int GL_NORMAL_ARRAY_STRIDE = 0x807F; int GL_NORMAL_ARRAY_TYPE = 0x807E; int GL_OPERAND0_ALPHA = 0x8598; int GL_OPERAND0_RGB = 0x8590; int GL_OPERAND1_ALPHA = 0x8599; int GL_OPERAND1_RGB = 0x8591; int GL_OPERAND2_ALPHA = 0x859A; int GL_OPERAND2_RGB = 0x8592; int GL_POINT_DISTANCE_ATTENUATION = 0x8129; int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; int GL_POINT_SIZE = 0x0B11; int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x8B9F; int GL_POINT_SIZE_ARRAY_OES = 0x8B9C; int GL_POINT_SIZE_ARRAY_POINTER_OES = 0x898C; int GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x898B; int GL_POINT_SIZE_ARRAY_TYPE_OES = 0x898A; int GL_POINT_SIZE_MAX = 0x8127; int GL_POINT_SIZE_MIN = 0x8126; int GL_POINT_SPRITE_OES = 0x8861; int GL_POLYGON_OFFSET_FACTOR = 0x8038; int GL_POLYGON_OFFSET_UNITS = 0x2A00; int GL_PREVIOUS = 0x8578; int GL_PRIMARY_COLOR = 0x8577; int GL_PROJECTION_MATRIX = 0x0BA7; int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; int GL_PROJECTION_STACK_DEPTH = 0x0BA4; int GL_RGB_SCALE = 0x8573; int GL_SAMPLE_BUFFERS = 0x80A8; int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; int GL_SAMPLES = 0x80A9; int GL_SCISSOR_BOX = 0x0C10; int GL_SHADE_MODEL = 0x0B54; int GL_SRC0_ALPHA = 0x8588; int GL_SRC0_RGB = 0x8580; int GL_SRC1_ALPHA = 0x8589; int GL_SRC1_RGB = 0x8581; int GL_SRC2_ALPHA = 0x858A; int GL_SRC2_RGB = 0x8582; int GL_STATIC_DRAW = 0x88E4; int GL_STENCIL_CLEAR_VALUE = 0x0B91; int GL_STENCIL_FAIL = 0x0B94; int GL_STENCIL_FUNC = 0x0B92; int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; int GL_STENCIL_REF = 0x0B97; int GL_STENCIL_VALUE_MASK = 0x0B93; int GL_STENCIL_WRITEMASK = 0x0B98; int GL_SUBTRACT = 0x84E7; int GL_TEXTURE_BINDING_2D = 0x8069; int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A; int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092; int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088; int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A; int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089; int GL_TEXTURE_MATRIX = 0x0BA8; int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; int GL_TEXTURE_STACK_DEPTH = 0x0BA5; int GL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896; int GL_VERTEX_ARRAY_POINTER = 0x808E; int GL_VERTEX_ARRAY_SIZE = 0x807A; int GL_VERTEX_ARRAY_STRIDE = 0x807C; int GL_VERTEX_ARRAY_TYPE = 0x807B; int GL_VIEWPORT = 0x0BA2; int GL_WRITE_ONLY = 0x88B9; void glGetPointerv(int pname, java.nio.Buffer[] params); opengl/tools/glgen/stubs/jsr239/GL11ImplHeader.java-impl0100644 0000000 0000000 00000001145 13077405420 021725 0ustar000000000 0000000 // Copyright 2006 The Android Open Source Project // All Rights Reserved. // This source file is automatically generated package com.google.android.gles_jni; import java.nio.Buffer; import javax.microedition.khronos.opengles.GL11; import android.graphics.Canvas; public class GL11Impl implements GL11 { // Private accessors for native code native private static void _nativeClassInit(); static { _nativeClassInit(); } Buffer _colorPointer = null; Buffer _normalPointer = null; Buffer _texCoordPointer = null; Buffer _vertexPointer = null; public GL11Impl() { } opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp0100644 0000000 0000000 00000023003 13077405420 017743 0ustar000000000 0000000 ** ** Copyright 2006, 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. */ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" #include "JNIHelp.h" #include #include #include #include #include // Work around differences between the generated name and the actual name. #define glBlendEquation glBlendEquationOES #define glBlendEquationSeparate glBlendEquationSeparateOES #define glBlendFuncSeparate glBlendFuncSeparateOES #define glGetTexGenfv glGetTexGenfvOES #define glGetTexGeniv glGetTexGenivOES #define glGetTexGenxv glGetTexGenxvOES #define glTexGenf glTexGenfOES #define glTexGenfv glTexGenfvOES #define glTexGeni glTexGeniOES #define glTexGeniv glTexGenivOES #define glTexGenx glTexGenxOES #define glTexGenxv glTexGenxvOES /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ extern "C" { GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr, GLsizei count); GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); } static int initialized = 0; static jclass nioAccessClass; static jclass bufferClass; static jclass G11ImplClass; static jmethodID getBasePointerID; static jmethodID getBaseArrayID; static jmethodID getBaseArrayOffsetID; static jmethodID allowIndirectBuffersID; static jfieldID positionID; static jfieldID limitID; static jfieldID elementSizeShiftID; static jfieldID haveCheckedExtensionsID; static jfieldID have_OES_blend_equation_separateID; static jfieldID have_OES_blend_subtractID; static jfieldID have_OES_framebuffer_objectID; static jfieldID have_OES_texture_cube_mapID; /* Cache method IDs each time the class is loaded. */ static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl"); G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal); haveCheckedExtensionsID = _env->GetFieldID(G11ImplClass, "haveCheckedExtensions", "Z"); have_OES_blend_equation_separateID = _env->GetFieldID(G11ImplClass, "have_OES_blend_equation_separate", "Z"); have_OES_blend_subtractID = _env->GetFieldID(G11ImplClass, "have_OES_blend_subtract", "Z"); have_OES_framebuffer_objectID = _env->GetFieldID(G11ImplClass, "have_OES_framebuffer_object", "Z"); have_OES_texture_cube_mapID = _env->GetFieldID(G11ImplClass, "have_OES_texture_cube_map", "Z"); getBasePointerID = _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J"); getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); allowIndirectBuffersID = _env->GetStaticMethodID(g11impClassLocal, "allowIndirectBuffers", "(Ljava/lang/String;)Z"); positionID = _env->GetFieldID(bufferClass, "position", "I"); limitID = _env->GetFieldID(bufferClass, "limit", "I"); elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset) { jint position; jint limit; jint elementSizeShift; jlong pointer; position = _env->GetIntField(buffer, positionID); limit = _env->GetIntField(buffer, limitID); elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); *remaining = (limit - position) << elementSizeShift; pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer); if (pointer != 0L) { *array = NULL; return reinterpret_cast(pointer); } *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); if (*array == NULL) { return (void*) NULL; } *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer); return NULL; } static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT); } extern "C" { extern char* __progname; } static bool allowIndirectBuffers(JNIEnv *_env) { static jint sIndirectBufferCompatability; if (sIndirectBufferCompatability == 0) { jobject appName = _env->NewStringUTF(::__progname); sIndirectBufferCompatability = _env->CallStaticBooleanMethod(G11ImplClass, allowIndirectBuffersID, appName) ? 2 : 1; } return sIndirectBufferCompatability == 2; } static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { if (!buffer) { return NULL; } void* buf = _env->GetDirectBufferAddress(buffer); if (buf) { jint position = _env->GetIntField(buffer, positionID); jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); buf = ((char*) buf) + (position << elementSizeShift); } else { if (allowIndirectBuffers(_env)) { jarray array = 0; jint remaining; jint offset; buf = getPointer(_env, buffer, &array, &remaining, &offset); if (array) { releasePointer(_env, array, buf, 0); } buf = (char*)buf + offset; } else { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); } } return buf; } static int getNumCompressedTextureFormats() { int numCompressedTextureFormats = 0; glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats); return numCompressedTextureFormats; } // Check if the extension at the head of pExtensions is pExtension. Note that pExtensions is // terminated by either 0 or space, while pExtension is terminated by 0. static bool extensionEqual(const GLubyte* pExtensions, const GLubyte* pExtension) { while (true) { char a = *pExtensions++; char b = *pExtension++; bool aEnd = a == '\0' || a == ' '; bool bEnd = b == '\0'; if ( aEnd || bEnd) { return aEnd == bEnd; } if ( a != b ) { return false; } } } static const GLubyte* nextExtension(const GLubyte* pExtensions) { while (true) { char a = *pExtensions++; if ( a == '\0') { return pExtensions-1; } else if ( a == ' ') { return pExtensions; } } } static bool checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) { for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) { if (extensionEqual(pExtensions, pExtension)) { return true; } } return false; } static bool supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) { if (!_env->GetBooleanField(impl, haveCheckedExtensionsID)) { _env->SetBooleanField(impl, haveCheckedExtensionsID, true); const GLubyte* sExtensions = glGetString(GL_EXTENSIONS); _env->SetBooleanField(impl, have_OES_blend_equation_separateID, checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_equation_separate")); _env->SetBooleanField(impl, have_OES_blend_subtractID, checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_subtract")); _env->SetBooleanField(impl, have_OES_framebuffer_objectID, checkForExtension(sExtensions, (const GLubyte*) "GL_OES_framebuffer_object")); _env->SetBooleanField(impl, have_OES_texture_cube_mapID, checkForExtension(sExtensions, (const GLubyte*) "GL_OES_texture_cube_map")); } return _env->GetBooleanField(impl, fieldId); } // -------------------------------------------------------------------------- opengl/tools/glgen/stubs/jsr239/GLHeader.java-if0100644 0000000 0000000 00000001374 13077405420 020402 0ustar000000000 0000000 /* //device/java/android/javax/microedition/khronos/opengles/GL.java ** ** Copyright 2006, 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 javax.microedition.khronos.opengles; public interface GL { } opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl0100644 0000000 0000000 00000005505 13077405420 021567 0ustar000000000 0000000 ** ** Copyright 2006, 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. */ // This source file is automatically generated package com.google.android.gles_jni; import android.app.AppGlobals; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.os.Build; import android.os.UserHandle; import android.util.Log; import java.nio.Buffer; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10Ext; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11Ext; import javax.microedition.khronos.opengles.GL11ExtensionPack; public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { // Private accessors for native code native private static void _nativeClassInit(); static { _nativeClassInit(); } Buffer _colorPointer = null; Buffer _normalPointer = null; Buffer _texCoordPointer = null; Buffer _vertexPointer = null; Buffer _pointSizePointerOES = null; Buffer _matrixIndexPointerOES = null; Buffer _weightPointerOES = null; private boolean haveCheckedExtensions; private boolean have_OES_blend_equation_separate; private boolean have_OES_blend_subtract; private boolean have_OES_framebuffer_object; private boolean have_OES_texture_cube_map; public GLImpl() { } public void glGetPointerv(int pname, java.nio.Buffer[] params) { throw new UnsupportedOperationException("glGetPointerv"); } private static boolean allowIndirectBuffers(String appName) { boolean result = false; int version = 0; IPackageManager pm = AppGlobals.getPackageManager(); try { ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0, UserHandle.myUserId()); if (applicationInfo != null) { version = applicationInfo.targetSdkVersion; } } catch (android.os.RemoteException e) { // ignore } Log.e("OpenGLES", String.format( "Application %s (SDK target %d) called a GL11 Pointer method with an indirect Buffer.", appName, version)); if (version <= Build.VERSION_CODES.CUPCAKE) { result = true; } return result; } opengl/tools/glgen/stubs/jsr239/glGetString.cpp0100644 0000000 0000000 00000000350 13077405420 020456 0ustar000000000 0000000 /* const GLubyte * glGetString ( GLenum name ) */ static jstring android_glGetString(JNIEnv *_env, jobject, jint name) { const char* chars = (const char*) glGetString((GLenum) name); return _env->NewStringUTF(chars); } opengl/tools/glgen/stubs/jsr239/glGetString.java-10-if0100644 0000000 0000000 00000000074 13077405420 021432 0ustar000000000 0000000 public String glGetString( int name ); opengl/tools/glgen/stubs/jsr239/glGetString.java-if0100644 0000000 0000000 00000000074 13077405420 021214 0ustar000000000 0000000 public String glGetString( int name ); opengl/tools/glgen/stubs/jsr239/glGetString.java-impl0100644 0000000 0000000 00000000506 13077405420 021557 0ustar000000000 0000000 // C function const GLubyte * glGetString ( GLenum name ) public native String _glGetString( int name ); public String glGetString( int name ) { String returnValue; returnValue = _glGetString( name ); return returnValue; } opengl/tools/glgen/stubs/jsr239/glGetString.nativeReg0100644 0000000 0000000 00000000113 13077405420 021615 0ustar000000000 0000000 {"_glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString }, opengl/tools/glgen2/0040755 0000000 0000000 00000000000 13077405420 013414 5ustar000000000 0000000 opengl/tools/glgen2/.gitignore0100644 0000000 0000000 00000000021 13077405420 015372 0ustar000000000 0000000 registry/reg.pyc opengl/tools/glgen2/glgen.py0100755 0000000 0000000 00000024656 13077405420 015077 0ustar000000000 0000000 #!/usr/bin/env python # # Copyright 2014 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function from operator import itemgetter import collections import os.path import re import sys # Avoid endlessly adding to the path if this module is imported multiple # times, e.g. in an interactive session regpath = os.path.join(sys.path[0], "registry") if sys.path[1] != regpath: sys.path.insert(1, regpath) import reg AEP_EXTENSIONS = [ 'GL_KHR_blend_equation_advanced', 'GL_KHR_debug', 'GL_KHR_texture_compression_astc_ldr', 'GL_OES_sample_shading', 'GL_OES_sample_variables', 'GL_OES_shader_image_atomic', 'GL_OES_shader_multisample_interpolation', 'GL_OES_texture_stencil8', 'GL_OES_texture_storage_multisample_2d_array', 'GL_EXT_copy_image', 'GL_EXT_draw_buffers_indexed', 'GL_EXT_geometry_shader', 'GL_EXT_gpu_shader5', 'GL_EXT_primitive_bounding_box', 'GL_EXT_shader_io_blocks', 'GL_EXT_tessellation_shader', 'GL_EXT_texture_border_clamp', 'GL_EXT_texture_buffer', 'GL_EXT_texture_cube_map_array', 'GL_EXT_texture_sRGB_decode'] def nonestr(s): return s if s else "" def parseProto(elem): type = nonestr(elem.text) name = None for subelem in elem: text = nonestr(subelem.text) if subelem.tag == 'name': name = text else: type += text type += nonestr(subelem.tail) return (type.strip(), name) def parseParam(elem): name = elem.find('name').text declaration = ''.join(elem.itertext()) return (name, declaration) # Format a list of (type, declaration) tuples as a C-style parameter list def fmtParams(params): if not params: return 'void' return ', '.join(p[1] for p in params) # Format a list of (type, declaration) tuples as a C-style argument list def fmtArgs(params): return ', '.join(p[0] for p in params) def overrideSymbolName(sym, apiname): # The wrapper intercepts various glGet and glGetString functions and # (sometimes) calls the generated thunk which dispatches to the # driver's implementation wrapped_get_syms = { 'gles1' : [ 'glGetString' ], 'gles2' : [ 'glGetString', 'glGetStringi', 'glGetBooleanv', 'glGetFloatv', 'glGetIntegerv', 'glGetInteger64v', ], } if sym in wrapped_get_syms.get(apiname): return '__' + sym else: return sym # Generate API trampoline templates: # API_ENTRY()() { # CALL_GL_API(, ); # // or # CALL_GL_API_RETURN(, ); # } class TrampolineGen(reg.OutputGenerator): def __init__(self): reg.OutputGenerator.__init__(self, sys.stderr, sys.stderr, None) def genCmd(self, cmd, name): reg.OutputGenerator.genCmd(self, cmd, name) rtype, fname = parseProto(cmd.elem.find('proto')) params = [parseParam(p) for p in cmd.elem.findall('param')] call = 'CALL_GL_API' if rtype == 'void' else 'CALL_GL_API_RETURN' print('%s API_ENTRY(%s)(%s) {\n' ' %s(%s%s%s);\n' '}' % (rtype, overrideSymbolName(fname, self.genOpts.apiname), fmtParams(params), call, fname, ', ' if len(params) > 0 else '', fmtArgs(params)), file=self.outFile) # Collect all API prototypes across all families, remove duplicates, # emit to entries.in and enums.in files. class ApiGenerator(reg.OutputGenerator): def __init__(self): reg.OutputGenerator.__init__(self, sys.stderr, sys.stderr, None) self.cmds = [] self.enums = collections.OrderedDict() def genCmd(self, cmd, name): reg.OutputGenerator.genCmd(self, cmd, name) rtype, fname = parseProto(cmd.elem.find('proto')) params = [parseParam(p) for p in cmd.elem.findall('param')] self.cmds.append({'rtype': rtype, 'name': fname, 'params': params}) def genEnum(self, enuminfo, name): reg.OutputGenerator.genEnum(self, enuminfo, name) value = enuminfo.elem.get('value') # Skip bitmask enums. Pattern matches: # - GL_DEPTH_BUFFER_BIT # - GL_MAP_INVALIDATE_BUFFER_BIT_EXT # - GL_COLOR_BUFFER_BIT1_QCOM # but not # - GL_DEPTH_BITS # - GL_QUERY_COUNTER_BITS_EXT # # TODO: Assuming a naming pattern and using a regex is what the # old glenumsgen script did. But the registry XML knows which enums are # parts of bitmask groups, so we should just use that. I'm not sure how # to get the information out though, and it's not critical right now, # so leaving for later. if re.search('_BIT($|\d*_)', name): return # Skip non-hex values (GL_TRUE, GL_FALSE, header guard junk) if not re.search('0x[0-9A-Fa-f]+', value): return # Append 'u' or 'ull' type suffix if present type = enuminfo.elem.get('type') if type and type != 'i': value += type if value not in self.enums: self.enums[value] = name def finish(self): # sort by function name, remove duplicates self.cmds.sort(key=itemgetter('name')) cmds = [] for cmd in self.cmds: if len(cmds) == 0 or cmd != cmds[-1]: cmds.append(cmd) self.cmds = cmds # Write entries.in def writeEntries(self, outfile): for cmd in self.cmds: print('GL_ENTRY(%s, %s, %s)' % (cmd['rtype'], cmd['name'], fmtParams(cmd['params'])), file=outfile) # Write enums.in def writeEnums(self, outfile): for enum in self.enums.iteritems(): print('GL_ENUM(%s,%s)' % (enum[0], enum[1]), file=outfile) # Generate .spec entries for use by legacy 'gen' script class SpecGenerator(reg.OutputGenerator): def __init__(self): reg.OutputGenerator.__init__(self, sys.stderr, sys.stderr, None) def genCmd(self, cmd, name): reg.OutputGenerator.genCmd(self, cmd, name) rtype, fname = parseProto(cmd.elem.find('proto')) params = [parseParam(p) for p in cmd.elem.findall('param')] print('%s %s ( %s )' % (rtype, fname, fmtParams(params)), file=self.outFile) if __name__ == '__main__': registry = reg.Registry() registry.loadFile('registry/gl.xml') registry.setGenerator(TrampolineGen()) TRAMPOLINE_OPTIONS = [ reg.GeneratorOptions( apiname = 'gles1', profile = 'common', filename = '../../libs/GLES_CM/gl_api.in'), reg.GeneratorOptions( apiname = 'gles1', profile = 'common', emitversions = None, defaultExtensions = 'gles1', filename = '../../libs/GLES_CM/glext_api.in'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common', filename = '../../libs/GLES2/gl2_api.in'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common', emitversions = None, defaultExtensions = 'gles2', filename = '../../libs/GLES2/gl2ext_api.in')] for opts in TRAMPOLINE_OPTIONS: registry.apiGen(opts) apigen = ApiGenerator() registry.setGenerator(apigen) API_OPTIONS = [ # Generate non-extension versions of each API first, then extensions, # so that if an extension enum was later standardized, we see the non- # suffixed version first. reg.GeneratorOptions( apiname = 'gles1', profile = 'common'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common'), reg.GeneratorOptions( apiname = 'gles1', profile = 'common', emitversions = None, defaultExtensions = 'gles1'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common', emitversions = None, defaultExtensions = 'gles2')] for opts in API_OPTIONS: registry.apiGen(opts) apigen.finish() with open('../../libs/entries.in', 'w') as f: apigen.writeEntries(f) with open('../../libs/enums.in', 'w') as f: apigen.writeEnums(f) registry.setGenerator(SpecGenerator()) SPEC_OPTIONS = [ reg.GeneratorOptions( apiname = 'gles2', profile = 'common', versions = '3\.1', filename = '../glgen/specs/gles11/GLES31.spec'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common', emitversions = None, defaultExtensions = None, addExtensions = '^({})$'.format('|'.join(AEP_EXTENSIONS)), filename = '../glgen/specs/gles11/GLES31Ext.spec'), reg.GeneratorOptions( apiname = 'gles2', profile = 'common', versions = '3\.2', filename = '../glgen/specs/gles11/GLES32.spec')] # SpecGenerator creates a good starting point, but the CFunc.java parser is # so terrible that the .spec file needs a lot of manual massaging before # it works. Commenting this out to avoid accidentally overwriting all the # manual modifications. # # Eventually this script should generate the Java and JNI code directly, # skipping the intermediate .spec step, and obsoleting the existing # ../glgen system. # # for opts in SPEC_OPTIONS: # registry.apiGen(opts) opengl/tools/glgen2/registry/0040755 0000000 0000000 00000000000 13077405420 015264 5ustar000000000 0000000 opengl/tools/glgen2/registry/egl.xml0100755 0000000 0000000 00000405623 13077405420 016567 0ustar000000000 0000000 #include <KHR/khrplatform.h> #include <EGL/eglplatform.h> typedef unsigned int EGLBoolean; typedef unsigned int EGLenum; typedef intptr_t EGLAttribKHR; typedef intptr_t EGLAttrib; typedef void *EGLClientBuffer; typedef void *EGLConfig; typedef void *EGLContext; typedef void *EGLDeviceEXT; typedef void *EGLDisplay; typedef void *EGLImage; typedef void *EGLImageKHR; typedef void *EGLLabelKHR; typedef void *EGLObjectKHR; typedef void *EGLOutputLayerEXT; typedef void *EGLOutputPortEXT; typedef void *EGLStreamKHR; typedef void *EGLSurface; typedef void *EGLSync; typedef void *EGLSyncKHR; typedef void *EGLSyncNV; typedef void (*__eglMustCastToProperFunctionPointerType)(void); typedef khronos_utime_nanoseconds_t EGLTimeKHR; typedef khronos_utime_nanoseconds_t EGLTime; typedef khronos_utime_nanoseconds_t EGLTimeNV; typedef khronos_utime_nanoseconds_t EGLuint64NV; typedef khronos_uint64_t EGLuint64KHR; typedef int EGLNativeFileDescriptorKHR; typedef khronos_ssize_t EGLsizeiANDROID; typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); struct EGLClientPixmapHI { void *pData; EGLint iWidth; EGLint iHeight; EGLint iStride; }; typedef void ( *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); EGLBoolean eglBindAPI EGLenum api EGLBoolean eglBindTexImage EGLDisplay dpy EGLSurface surface EGLint buffer EGLBoolean eglChooseConfig EGLDisplay dpy const EGLint *attrib_list EGLConfig *configs EGLint config_size EGLint *num_config EGLint eglClientWaitSync EGLDisplay dpy EGLSync sync EGLint flags EGLTime timeout EGLint eglClientWaitSyncKHR EGLDisplay dpy EGLSyncKHR sync EGLint flags EGLTimeKHR timeout EGLint eglClientWaitSyncNV EGLSyncNV sync EGLint flags EGLTimeNV timeout EGLBoolean eglCopyBuffers EGLDisplay dpy EGLSurface surface EGLNativePixmapType target EGLContext eglCreateContext EGLDisplay dpy EGLConfig config EGLContext share_context const EGLint *attrib_list EGLImageKHR eglCreateDRMImageMESA EGLDisplay dpy const EGLint *attrib_list EGLSyncNV eglCreateFenceSyncNV EGLDisplay dpy EGLenum condition const EGLint *attrib_list EGLImage eglCreateImage EGLDisplay dpy EGLContext ctx EGLenum target EGLClientBuffer buffer const EGLAttrib *attrib_list EGLImageKHR eglCreateImageKHR EGLDisplay dpy EGLContext ctx EGLenum target EGLClientBuffer buffer const EGLint *attrib_list EGLSurface eglCreatePbufferFromClientBuffer EGLDisplay dpy EGLenum buftype EGLClientBuffer buffer EGLConfig config const EGLint *attrib_list EGLSurface eglCreatePbufferSurface EGLDisplay dpy EGLConfig config const EGLint *attrib_list EGLSurface eglCreatePixmapSurface EGLDisplay dpy EGLConfig config EGLNativePixmapType pixmap const EGLint *attrib_list EGLSurface eglCreatePixmapSurfaceHI EGLDisplay dpy EGLConfig config struct EGLClientPixmapHI *pixmap EGLSurface eglCreatePlatformPixmapSurface EGLDisplay dpy EGLConfig config void *native_pixmap const EGLAttrib *attrib_list EGLSurface eglCreatePlatformPixmapSurfaceEXT EGLDisplay dpy EGLConfig config void *native_pixmap const EGLint *attrib_list EGLSurface eglCreatePlatformWindowSurface EGLDisplay dpy EGLConfig config void *native_window const EGLAttrib *attrib_list EGLSurface eglCreatePlatformWindowSurfaceEXT EGLDisplay dpy EGLConfig config void *native_window const EGLint *attrib_list EGLStreamKHR eglCreateStreamFromFileDescriptorKHR EGLDisplay dpy EGLNativeFileDescriptorKHR file_descriptor EGLStreamKHR eglCreateStreamKHR EGLDisplay dpy const EGLint *attrib_list EGLSurface eglCreateStreamProducerSurfaceKHR EGLDisplay dpy EGLConfig config EGLStreamKHR stream const EGLint *attrib_list EGLSyncKHR eglCreateStreamSyncNV EGLDisplay dpy EGLStreamKHR stream EGLenum type const EGLint *attrib_list EGLSync eglCreateSync EGLDisplay dpy EGLenum type const EGLAttrib *attrib_list EGLSyncKHR eglCreateSyncKHR EGLDisplay dpy EGLenum type const EGLint *attrib_list EGLSyncKHR eglCreateSync64KHR EGLDisplay dpy EGLenum type const EGLAttribKHR *attrib_list EGLSurface eglCreateWindowSurface EGLDisplay dpy EGLConfig config EGLNativeWindowType win const EGLint *attrib_list EGLint eglDebugMessageControlKHR EGLDEBUGPROCKHR callback const EGLAttrib *attrib_list EGLBoolean eglDestroyContext EGLDisplay dpy EGLContext ctx EGLBoolean eglDestroyImage EGLDisplay dpy EGLImage image EGLBoolean eglDestroyImageKHR EGLDisplay dpy EGLImageKHR image EGLBoolean eglDestroyStreamKHR EGLDisplay dpy EGLStreamKHR stream EGLBoolean eglDestroySurface EGLDisplay dpy EGLSurface surface EGLBoolean eglDestroySync EGLDisplay dpy EGLSync sync EGLBoolean eglDestroySyncKHR EGLDisplay dpy EGLSyncKHR sync EGLBoolean eglDestroySyncNV EGLSyncNV sync EGLint eglDupNativeFenceFDANDROID EGLDisplay dpy EGLSyncKHR sync EGLBoolean eglExportDMABUFImageMESA EGLDisplay dpy EGLImageKHR image int *fds EGLint *strides EGLint *offsets EGLBoolean eglExportDMABUFImageQueryMESA EGLDisplay dpy EGLImageKHR image int *fourcc int *num_planes EGLuint64KHR *modifiers EGLBoolean eglExportDRMImageMESA EGLDisplay dpy EGLImageKHR image EGLint *name EGLint *handle EGLint *stride EGLBoolean eglFenceNV EGLSyncNV sync EGLBoolean eglGetConfigAttrib EGLDisplay dpy EGLConfig config EGLint attribute EGLint *value EGLBoolean eglGetConfigs EGLDisplay dpy EGLConfig *configs EGLint config_size EGLint *num_config EGLContext eglGetCurrentContext EGLDisplay eglGetCurrentDisplay EGLSurface eglGetCurrentSurface EGLint readdraw EGLDisplay eglGetDisplay EGLNativeDisplayType display_id EGLint eglGetError EGLBoolean eglGetOutputLayersEXT EGLDisplay dpy const EGLAttrib *attrib_list EGLOutputLayerEXT *layers EGLint max_layers EGLint *num_layers EGLBoolean eglGetOutputPortsEXT EGLDisplay dpy const EGLAttrib *attrib_list EGLOutputPortEXT *ports EGLint max_ports EGLint *num_ports EGLDisplay eglGetPlatformDisplay EGLenum platform void *native_display const EGLAttrib *attrib_list EGLDisplay eglGetPlatformDisplayEXT EGLenum platform void *native_display const EGLint *attrib_list __eglMustCastToProperFunctionPointerType eglGetProcAddress const char *procname EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR EGLDisplay dpy EGLStreamKHR stream EGLBoolean eglGetSyncAttrib EGLDisplay dpy EGLSync sync EGLint attribute EGLAttrib *value EGLBoolean eglGetSyncAttribKHR EGLDisplay dpy EGLSyncKHR sync EGLint attribute EGLint *value EGLBoolean eglGetSyncAttribNV EGLSyncNV sync EGLint attribute EGLint *value EGLuint64NV eglGetSystemTimeFrequencyNV EGLuint64NV eglGetSystemTimeNV EGLBoolean eglInitialize EGLDisplay dpy EGLint *major EGLint *minor EGLint eglLabelObjectKHR EGLDisplay display EGLenum objectType EGLObjectKHR object EGLLabelKHR label EGLBoolean eglLockSurfaceKHR EGLDisplay dpy EGLSurface surface const EGLint *attrib_list EGLBoolean eglMakeCurrent EGLDisplay dpy EGLSurface draw EGLSurface read EGLContext ctx EGLBoolean eglOutputLayerAttribEXT EGLDisplay dpy EGLOutputLayerEXT layer EGLint attribute EGLAttrib value EGLBoolean eglOutputPortAttribEXT EGLDisplay dpy EGLOutputPortEXT port EGLint attribute EGLAttrib value EGLBoolean eglPostSubBufferNV EGLDisplay dpy EGLSurface surface EGLint x EGLint y EGLint width EGLint height EGLenum eglQueryAPI EGLBoolean eglQueryContext EGLDisplay dpy EGLContext ctx EGLint attribute EGLint *value EGLBoolean eglQueryDebugKHR EGLint attribute EGLAttrib *value EGLBoolean eglQueryDeviceAttribEXT EGLDeviceEXT device EGLint attribute EGLAttrib *value const char *eglQueryDeviceStringEXT EGLDeviceEXT device EGLint name EGLBoolean eglQueryDevicesEXT EGLint max_devices EGLDeviceEXT *devices EGLint *num_devices EGLBoolean eglQueryDisplayAttribEXT EGLDisplay dpy EGLint attribute EGLAttrib *value EGLBoolean eglQueryDisplayAttribNV EGLDisplay dpy EGLint attribute EGLAttrib *value EGLBoolean eglQueryNativeDisplayNV EGLDisplay dpy EGLNativeDisplayType *display_id EGLBoolean eglQueryNativePixmapNV EGLDisplay dpy EGLSurface surf EGLNativePixmapType *pixmap EGLBoolean eglQueryNativeWindowNV EGLDisplay dpy EGLSurface surf EGLNativeWindowType *window EGLBoolean eglQueryOutputLayerAttribEXT EGLDisplay dpy EGLOutputLayerEXT layer EGLint attribute EGLAttrib *value const char *eglQueryOutputLayerStringEXT EGLDisplay dpy EGLOutputLayerEXT layer EGLint name EGLBoolean eglQueryOutputPortAttribEXT EGLDisplay dpy EGLOutputPortEXT port EGLint attribute EGLAttrib *value const char *eglQueryOutputPortStringEXT EGLDisplay dpy EGLOutputPortEXT port EGLint name EGLBoolean eglQueryStreamKHR EGLDisplay dpy EGLStreamKHR stream EGLenum attribute EGLint *value EGLBoolean eglQueryStreamMetadataNV EGLDisplay dpy EGLStreamKHR stream EGLenum name EGLint n EGLint offset EGLint size void *data EGLBoolean eglQueryStreamTimeKHR EGLDisplay dpy EGLStreamKHR stream EGLenum attribute EGLTimeKHR *value EGLBoolean eglQueryStreamu64KHR EGLDisplay dpy EGLStreamKHR stream EGLenum attribute EGLuint64KHR *value const char *eglQueryString EGLDisplay dpy EGLint name EGLBoolean eglQuerySurface EGLDisplay dpy EGLSurface surface EGLint attribute EGLint *value EGLBoolean eglQuerySurface64KHR EGLDisplay dpy EGLSurface surface EGLint attribute EGLAttribKHR *value EGLBoolean eglQuerySurfacePointerANGLE EGLDisplay dpy EGLSurface surface EGLint attribute void **value EGLBoolean eglReleaseTexImage EGLDisplay dpy EGLSurface surface EGLint buffer EGLBoolean eglReleaseThread void eglSetBlobCacheFuncsANDROID EGLDisplay dpy EGLSetBlobFuncANDROID set EGLGetBlobFuncANDROID get EGLBoolean eglSetDamageRegionKHR EGLDisplay dpy EGLSurface surface EGLint *rects EGLint n_rects EGLBoolean eglSetStreamMetadataNV EGLDisplay dpy EGLStreamKHR stream EGLint n EGLint offset EGLint size const void *data EGLBoolean eglSignalSyncKHR EGLDisplay dpy EGLSyncKHR sync EGLenum mode EGLBoolean eglSignalSyncNV EGLSyncNV sync EGLenum mode EGLBoolean eglStreamAttribKHR EGLDisplay dpy EGLStreamKHR stream EGLenum attribute EGLint value EGLBoolean eglStreamConsumerAcquireKHR EGLDisplay dpy EGLStreamKHR stream EGLBoolean eglStreamConsumerGLTextureExternalKHR EGLDisplay dpy EGLStreamKHR stream EGLBoolean eglStreamConsumerGLTextureExternalAttribsNV EGLDisplay dpy EGLStreamKHR stream EGLAttrib *attrib_list EGLBoolean eglStreamConsumerOutputEXT EGLDisplay dpy EGLStreamKHR stream EGLOutputLayerEXT layer EGLBoolean eglStreamConsumerReleaseKHR EGLDisplay dpy EGLStreamKHR stream EGLBoolean eglSurfaceAttrib EGLDisplay dpy EGLSurface surface EGLint attribute EGLint value EGLBoolean eglSwapBuffers EGLDisplay dpy EGLSurface surface EGLBoolean eglSwapBuffersWithDamageEXT EGLDisplay dpy EGLSurface surface EGLint *rects EGLint n_rects EGLBoolean eglSwapBuffersWithDamageKHR EGLDisplay dpy EGLSurface surface EGLint *rects EGLint n_rects EGLBoolean eglSwapBuffersRegionNOK EGLDisplay dpy EGLSurface surface EGLint numRects const EGLint *rects EGLBoolean eglSwapBuffersRegion2NOK EGLDisplay dpy EGLSurface surface EGLint numRects const EGLint *rects EGLBoolean eglSwapInterval EGLDisplay dpy EGLint interval EGLBoolean eglTerminate EGLDisplay dpy EGLBoolean eglUnlockSurfaceKHR EGLDisplay dpy EGLSurface surface EGLBoolean eglWaitClient EGLBoolean eglWaitGL EGLBoolean eglWaitNative EGLint engine EGLBoolean eglWaitSync EGLDisplay dpy EGLSync sync EGLint flags EGLint eglWaitSyncKHR EGLDisplay dpy EGLSyncKHR sync EGLint flags opengl/tools/glgen2/registry/genheaders.py0100755 0000000 0000000 00000055101 13077405420 017745 0ustar000000000 0000000 #!/usr/bin/env python # # Copyright (c) 2013-2015 The Khronos Group Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and/or associated documentation files (the # "Materials"), to deal in the Materials without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Materials, and to # permit persons to whom the Materials are furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Materials. # # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. import sys, time, pdb, string, cProfile from reg import * # debug - start header generation in debugger # dump - dump registry after loading # profile - enable Python profiling # protect - whether to use #ifndef protections # registry - use specified XML registry instead of gl.xml # target - string name of target header, or all targets if None # timeit - time length of registry loading & header generation # validate - validate return & parameter group tags against debug = False dump = False profile = False protect = True target = None timeit = False validate= False # Default input / log files errFilename = None diagFilename = 'diag.txt' regFilename = 'gl.xml' if __name__ == '__main__': i = 1 while (i < len(sys.argv)): arg = sys.argv[i] i = i + 1 if (arg == '-debug'): write('Enabling debug (-debug)', file=sys.stderr) debug = True elif (arg == '-dump'): write('Enabling dump (-dump)', file=sys.stderr) dump = True elif (arg == '-noprotect'): write('Disabling inclusion protection in output headers', file=sys.stderr) protect = False elif (arg == '-profile'): write('Enabling profiling (-profile)', file=sys.stderr) profile = True elif (arg == '-registry'): regFilename = sys.argv[i] i = i+1 write('Using registry ', regFilename, file=sys.stderr) elif (arg == '-time'): write('Enabling timing (-time)', file=sys.stderr) timeit = True elif (arg == '-validate'): write('Enabling group validation (-validate)', file=sys.stderr) validate = True elif (arg[0:1] == '-'): write('Unrecognized argument:', arg, file=sys.stderr) exit(1) else: target = arg write('Using target', target, file=sys.stderr) # Simple timer functions startTime = None def startTimer(): global startTime startTime = time.clock() def endTimer(msg): global startTime endTime = time.clock() if (timeit): write(msg, endTime - startTime) startTime = None # Load & parse registry reg = Registry() startTimer() tree = etree.parse(regFilename) endTimer('Time to make ElementTree =') startTimer() reg.loadElementTree(tree) endTimer('Time to parse ElementTree =') if (validate): reg.validateGroups() if (dump): write('***************************************') write('Performing Registry dump to regdump.txt') write('***************************************') reg.dumpReg(filehandle = open('regdump.txt','w')) # Turn a list of strings into a regexp string matching exactly those strings def makeREstring(list): return '^(' + '|'.join(list) + ')$' # These are "mandatory" OpenGL ES 1 extensions, to # be included in the core GLES/gl.h header. es1CoreList = [ 'GL_OES_read_format', 'GL_OES_compressed_paletted_texture', 'GL_OES_point_size_array', 'GL_OES_point_sprite' ] # Descriptive names for various regexp patterns used to select # versions and extensions allVersions = allExtensions = '.*' noVersions = noExtensions = None gl12andLaterPat = '1\.[2-9]|[234]\.[0-9]' gles2onlyPat = '2\.[0-9]' gles2and30Pat = '2\.[0-9]|3.0' gles2and30and31Pat = '2.[0-9]|3.[01]' es1CorePat = makeREstring(es1CoreList) # Extensions in old glcorearb.h but not yet tagged accordingly in gl.xml glCoreARBPat = None glx13andLaterPat = '1\.[3-9]' # Copyright text prefixing all headers (list of strings). prefixStrings = [ '/*', '** Copyright (c) 2013-2015 The Khronos Group Inc.', '**', '** Permission is hereby granted, free of charge, to any person obtaining a', '** copy of this software and/or associated documentation files (the', '** "Materials"), to deal in the Materials without restriction, including', '** without limitation the rights to use, copy, modify, merge, publish,', '** distribute, sublicense, and/or sell copies of the Materials, and to', '** permit persons to whom the Materials are furnished to do so, subject to', '** the following conditions:', '**', '** The above copyright notice and this permission notice shall be included', '** in all copies or substantial portions of the Materials.', '**', '** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,', '** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF', '** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.', '** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY', '** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,', '** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE', '** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.', '*/', '/*', '** This header is generated from the Khronos OpenGL / OpenGL ES XML', '** API Registry. The current version of the Registry, generator scripts', '** used to make the header, and the header can be found at', '** http://www.opengl.org/registry/', '**', '** Khronos $' + 'Revision$ on $' + 'Date$', '*/', '' ] # glext.h / glcorearb.h define calling conventions inline (no GL *platform.h) glExtPlatformStrings = [ '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)', '#ifndef WIN32_LEAN_AND_MEAN', '#define WIN32_LEAN_AND_MEAN 1', '#endif', '#include ', '#endif', '', '#ifndef APIENTRY', '#define APIENTRY', '#endif', '#ifndef APIENTRYP', '#define APIENTRYP APIENTRY *', '#endif', '#ifndef GLAPI', '#define GLAPI extern', '#endif', '' ] glCorearbPlatformStrings = glExtPlatformStrings + [ '/* glcorearb.h is for use with OpenGL core profile implementations.', '** It should should be placed in the same directory as gl.h and', '** included as .', '**', '** glcorearb.h includes only APIs in the latest OpenGL core profile', '** implementation together with APIs in newer ARB extensions which ', '** can be supported by the core profile. It does not, and never will', '** include functionality removed from the core profile, such as', '** fixed-function vertex and fragment processing.', '**', '** Do not #include both and either of or', '** in the same source file.', '*/', '' ] # wglext.h needs Windows include wglPlatformStrings = [ '#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)', '#define WIN32_LEAN_AND_MEAN 1', '#include ', '#endif', '', ] # GLES 1/2/3 core .h have separate *platform.h files to define calling conventions gles1PlatformStrings = [ '#include ', '' ] gles2PlatformStrings = [ '#include ', '' ] gles3PlatformStrings = [ '#include ', '' ] eglPlatformStrings = [ '#include ', '' ] # GLES headers have a small addition to calling convention headers for function pointer typedefs apiEntryPrefixStrings = [ '#ifndef GL_APIENTRYP', '#define GL_APIENTRYP GL_APIENTRY*', '#endif', '' ] # Insert generation date in a comment for headers not having *GLEXT_VERSION macros genDateCommentString = [ format("/* Generated on date %s */" % time.strftime("%Y%m%d")), '' ] # GL_GLEXT_VERSION is defined only in glext.h glextVersionStrings = [ format("#define GL_GLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # WGL_WGLEXT_VERSION is defined only in wglext.h wglextVersionStrings = [ format("#define WGL_WGLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # GLX_GLXEXT_VERSION is defined only in glxext.h glxextVersionStrings = [ format("#define GLX_GLXEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # EGL_EGLEXT_VERSION is defined only in eglext.h eglextVersionStrings = [ format("#define EGL_EGLEXT_VERSION %s" % time.strftime("%Y%m%d")), '' ] # Defaults for generating re-inclusion protection wrappers (or not) protectFile = protect protectFeature = protect protectProto = protect buildList = [ # GL API 1.2+ + extensions - GL/glext.h CGeneratorOptions( filename = 'GL/glext.h', apiname = 'gl', profile = 'compatibility', versions = allVersions, emitversions = gl12andLaterPat, defaultExtensions = 'gl', # Default extensions for GL addExtensions = None, removeExtensions = None, prefixText = prefixStrings + glExtPlatformStrings + glextVersionStrings, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GLAPI ', apientry = 'APIENTRY ', apientryp = 'APIENTRYP '), # GL core profile + extensions - GL/glcorearb.h CGeneratorOptions( filename = 'GL/glcorearb.h', apiname = 'gl', profile = 'core', versions = allVersions, emitversions = allVersions, defaultExtensions = 'glcore', # Default extensions for GL core profile (only) addExtensions = glCoreARBPat, removeExtensions = None, prefixText = prefixStrings + glCorearbPlatformStrings, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GLAPI ', apientry = 'APIENTRY ', apientryp = 'APIENTRYP '), # GLES 1.x API + mandatory extensions - GLES/gl.h (no function pointers) CGeneratorOptions( filename = 'GLES/gl.h', apiname = 'gles1', profile = 'common', versions = allVersions, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = es1CorePat, # Add mandatory ES1 extensions in GLES1/gl.h removeExtensions = None, prefixText = prefixStrings + gles1PlatformStrings + genDateCommentString, genFuncPointers = False, protectFile = protectFile, protectFeature = protectFeature, protectProto = False, # Core ES API functions are in the static link libraries protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_API ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # GLES 1.x extensions - GLES/glext.h CGeneratorOptions( filename = 'GLES/glext.h', apiname = 'gles1', profile = 'common', versions = allVersions, emitversions = noVersions, defaultExtensions = 'gles1', # Default extensions for GLES 1 addExtensions = None, removeExtensions = es1CorePat, # Remove mandatory ES1 extensions in GLES1/glext.h prefixText = prefixStrings + apiEntryPrefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_API ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # GLES 2.0 API - GLES2/gl2.h (now with function pointers) CGeneratorOptions( filename = 'GLES2/gl2.h', apiname = 'gles2', profile = 'common', versions = gles2onlyPat, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = None, removeExtensions = None, prefixText = prefixStrings + gles2PlatformStrings + apiEntryPrefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, # Core ES API functions are in the static link libraries protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_APICALL ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # GLES 3.1 / 3.0 / 2.0 extensions - GLES2/gl2ext.h CGeneratorOptions( filename = 'GLES2/gl2ext.h', apiname = 'gles2', profile = 'common', versions = gles2onlyPat, emitversions = None, defaultExtensions = 'gles2', # Default extensions for GLES 2 addExtensions = None, removeExtensions = None, prefixText = prefixStrings + apiEntryPrefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_APICALL ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # GLES 3.1 API - GLES3/gl31.h (now with function pointers) CGeneratorOptions( filename = 'GLES3/gl31.h', apiname = 'gles2', profile = 'common', versions = gles2and30and31Pat, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = None, removeExtensions = None, prefixText = prefixStrings + gles3PlatformStrings + apiEntryPrefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, # Core ES API functions are in the static link libraries protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_APICALL ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # GLES 3.0 API - GLES3/gl3.h (now with function pointers) CGeneratorOptions( filename = 'GLES3/gl3.h', apiname = 'gles2', profile = 'common', versions = gles2and30Pat, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = None, removeExtensions = None, prefixText = prefixStrings + gles3PlatformStrings + apiEntryPrefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, # Core ES API functions are in the static link libraries protectProtoStr = 'GL_GLEXT_PROTOTYPES', apicall = 'GL_APICALL ', apientry = 'GL_APIENTRY ', apientryp = 'GL_APIENTRYP '), # EGL API - EGL/egl.h (no function pointers, yet @@@) CGeneratorOptions( filename = 'EGL/egl.h', apiname = 'egl', profile = None, versions = allVersions, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = None, removeExtensions = None, prefixText = prefixStrings + eglPlatformStrings + genDateCommentString, genFuncPointers = False, protectFile = protectFile, protectFeature = protectFeature, protectProto = False, protectProtoStr = 'EGL_EGLEXT_PROTOTYPES', apicall = 'EGLAPI ', apientry = 'EGLAPIENTRY ', apientryp = 'EGLAPIENTRYP '), # EGL extensions - EGL/eglext.h (no function pointers, yet @@@) CGeneratorOptions( filename = 'EGL/eglext.h', apiname = 'egl', profile = None, versions = allVersions, emitversions = None, defaultExtensions = 'egl', # Default extensions for EGL addExtensions = None, removeExtensions = None, prefixText = prefixStrings + eglPlatformStrings + eglextVersionStrings, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'EGL_EGLEXT_PROTOTYPES', apicall = 'EGLAPI ', apientry = 'EGLAPIENTRY ', apientryp = 'EGLAPIENTRYP '), # GLX 1.* API - GL/glx.h CGeneratorOptions( filename = 'GL/glx.h', apiname = 'glx', profile = None, versions = allVersions, emitversions = allVersions, defaultExtensions = None, # No default extensions addExtensions = None, removeExtensions = None, # add glXPlatformStrings? prefixText = prefixStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GLX_GLXEXT_PROTOTYPES', apicall = '', apientry = '', apientryp = ' *'), # GLX 1.3+ API + extensions - GL/glxext.h (no function pointers, yet @@@) CGeneratorOptions( filename = 'GL/glxext.h', apiname = 'glx', profile = None, versions = allVersions, emitversions = glx13andLaterPat, defaultExtensions = 'glx', # Default extensions for GLX addExtensions = None, removeExtensions = None, # add glXPlatformStrings? prefixText = prefixStrings + glxextVersionStrings, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'GLX_GLXEXT_PROTOTYPES', apicall = '', apientry = '', apientryp = ' *'), # WGL API + extensions - GL/wgl.h (no function pointers, yet @@@) CGeneratorOptions( filename = 'GL/wgl.h', apiname = 'wgl', profile = None, versions = allVersions, emitversions = allVersions, defaultExtensions = 'wgl', # Default extensions for WGL addExtensions = None, removeExtensions = None, prefixText = prefixStrings + wglPlatformStrings + genDateCommentString, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'WGL_WGLEXT_PROTOTYPES', apicall = '', apientry = 'WINAPI ', apientryp = 'WINAPI * '), # WGL extensions - GL/wglext.h (no function pointers, yet @@@) CGeneratorOptions( filename = 'GL/wglext.h', apiname = 'wgl', profile = None, versions = allVersions, emitversions = None, defaultExtensions = 'wgl', # Default extensions for WGL addExtensions = None, removeExtensions = None, prefixText = prefixStrings + wglPlatformStrings + wglextVersionStrings, genFuncPointers = True, protectFile = protectFile, protectFeature = protectFeature, protectProto = protectProto, protectProtoStr = 'WGL_WGLEXT_PROTOTYPES', apicall = '', apientry = 'WINAPI ', apientryp = 'WINAPI * '), # End of list None ] # create error/warning & diagnostic files if (errFilename): errWarn = open(errFilename,'w') else: errWarn = sys.stderr diag = open(diagFilename, 'w') def genHeaders(): # Loop over targets, building each generated = 0 for genOpts in buildList: if (genOpts == None): break if (target and target != genOpts.filename): # write('*** Skipping', genOpts.filename) continue write('*** Building', genOpts.filename) generated = generated + 1 startTimer() gen = COutputGenerator(errFile=errWarn, warnFile=errWarn, diagFile=diag) reg.setGenerator(gen) reg.apiGen(genOpts) write('** Generated', genOpts.filename) endTimer('Time to generate ' + genOpts.filename + ' =') if (target and generated == 0): write('Failed to generate target:', target) if (debug): pdb.run('genHeaders()') elif (profile): import cProfile, pstats cProfile.run('genHeaders()', 'profile.txt') p = pstats.Stats('profile.txt') p.strip_dirs().sort_stats('time').print_stats(50) else: genHeaders() opengl/tools/glgen2/registry/gl.xml0100755 0000000 0000000 00011465175 13077405420 016434 0ustar000000000 0000000 Copyright (c) 2013-2015 The Khronos Group Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and/or associated documentation files (the "Materials"), to deal in the Materials without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials, and to permit persons to whom the Materials are furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Materials. THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ------------------------------------------------------------------------ This file, gl.xml, is the OpenGL and OpenGL API Registry. The older ".spec" file format has been retired and will no longer be updated with new extensions and API versions. The canonical version of the registry, together with documentation, schema, and Python generator scripts used to generate C header files for OpenGL and OpenGL ES, can always be found in the Khronos Registry at http://www.opengl.org/registry/ #include <stddef.h> #include <KHR/khrplatform.h> #ifndef GLEXT_64_TYPES_DEFINED /* This code block is duplicated in glxext.h, so must be protected */ #define GLEXT_64_TYPES_DEFINED /* Define int32_t, int64_t, and uint64_t types for UST/MSC */ /* (as used in the GL_EXT_timer_query extension). */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include <inttypes.h> #elif defined(__sun__) || defined(__digital__) #include <inttypes.h> #if defined(__STDC__) #if defined(__arch64__) || defined(_LP64) typedef long int int64_t; typedef unsigned long int uint64_t; #else typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif /* __arch64__ */ #endif /* __STDC__ */ #elif defined( __VMS ) || defined(__sgi) #include <inttypes.h> #elif defined(__SCO__) || defined(__USLC__) #include <stdint.h> #elif defined(__UNIXOS2__) || defined(__SOL64__) typedef long int int32_t; typedef long long int int64_t; typedef unsigned long long int uint64_t; #elif defined(_WIN32) && defined(__GNUC__) #include <stdint.h> #elif defined(_WIN32) typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else /* Fallback if nothing above works */ #include <inttypes.h> #endif #endif typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef void GLvoid; typedef signed char GLbyte; typedef short GLshort; typedef int GLint; typedef int GLclampx; typedef unsigned char GLubyte; typedef unsigned short GLushort; typedef unsigned int GLuint; typedef int GLsizei; typedef float GLfloat; typedef float GLclampf; typedef double GLdouble; typedef double GLclampd; typedef void *GLeglImageOES; typedef char GLchar; typedef char GLcharARB; #ifdef __APPLE__ typedef void *GLhandleARB; #else typedef unsigned int GLhandleARB; #endif typedef unsigned short GLhalfARB; typedef unsigned short GLhalf; typedef GLint GLfixed; typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; typedef int64_t GLint64; typedef uint64_t GLuint64; typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; typedef int64_t GLint64EXT; typedef uint64_t GLuint64EXT; typedef struct __GLsync *GLsync; struct _cl_context; struct _cl_event; typedef void ( *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void ( *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void ( *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef khronos_int32_t GLclampx; typedef khronos_int8_t GLbyte; typedef khronos_uint8_t GLubyte; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef khronos_intptr_t GLintptr; typedef khronos_ssize_t GLsizeiptr; typedef khronos_int8_t GLbyte; typedef khronos_uint8_t GLubyte; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef khronos_int32_t GLfixed; typedef khronos_int64_t GLint64; typedef khronos_uint64_t GLuint64; typedef khronos_int64_t GLint64EXT; typedef khronos_uint64_t GLuint64EXT; typedef khronos_intptr_t GLintptr; typedef khronos_ssize_t GLsizeiptr; typedef void ( *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); typedef unsigned short GLhalfNV; typedef GLintptr GLvdpauSurfaceNV; void glAccum GLenum op GLfloat value void glAccumxOES GLenum op GLfixed value void glActiveProgramEXT GLuint program void glActiveShaderProgram GLuint pipeline GLuint program void glActiveShaderProgramEXT GLuint pipeline GLuint program void glActiveStencilFaceEXT GLenum face void glActiveTexture GLenum texture void glActiveTextureARB GLenum texture void glActiveVaryingNV GLuint program const GLchar *name void glAlphaFragmentOp1ATI GLenum op GLuint dst GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod void glAlphaFragmentOp2ATI GLenum op GLuint dst GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod GLuint arg2 GLuint arg2Rep GLuint arg2Mod void glAlphaFragmentOp3ATI GLenum op GLuint dst GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod GLuint arg2 GLuint arg2Rep GLuint arg2Mod GLuint arg3 GLuint arg3Rep GLuint arg3Mod void glAlphaFunc GLenum func GLfloat ref void glAlphaFuncQCOM GLenum func GLclampf ref void glAlphaFuncx GLenum func GLfixed ref void glAlphaFuncxOES GLenum func GLfixed ref void glApplyFramebufferAttachmentCMAAINTEL void glApplyTextureEXT GLenum mode GLboolean glAreProgramsResidentNV GLsizei n const GLuint *programs GLboolean *residences GLboolean glAreTexturesResident GLsizei n const GLuint *textures GLboolean *residences GLboolean glAreTexturesResidentEXT GLsizei n const GLuint *textures GLboolean *residences void glArrayElement GLint i void glArrayElementEXT GLint i void glArrayObjectATI GLenum array GLint size GLenum type GLsizei stride GLuint buffer GLuint offset void glAsyncMarkerSGIX GLuint marker void glAttachObjectARB GLhandleARB containerObj GLhandleARB obj void glAttachShader GLuint program GLuint shader void glBegin GLenum mode void glBeginConditionalRender GLuint id GLenum mode void glBeginConditionalRenderNV GLuint id GLenum mode void glBeginConditionalRenderNVX GLuint id void glBeginFragmentShaderATI void glBeginOcclusionQueryNV GLuint id void glBeginPerfMonitorAMD GLuint monitor void glBeginPerfQueryINTEL GLuint queryHandle void glBeginQuery GLenum target GLuint id void glBeginQueryARB GLenum target GLuint id void glBeginQueryEXT GLenum target GLuint id void glBeginQueryIndexed GLenum target GLuint index GLuint id void glBeginTransformFeedback GLenum primitiveMode void glBeginTransformFeedbackEXT GLenum primitiveMode void glBeginTransformFeedbackNV GLenum primitiveMode void glBeginVertexShaderEXT void glBeginVideoCaptureNV GLuint video_capture_slot void glBindAttribLocation GLuint program GLuint index const GLchar *name void glBindAttribLocationARB GLhandleARB programObj GLuint index const GLcharARB *name void glBindBuffer GLenum target GLuint buffer void glBindBufferARB GLenum target GLuint buffer void glBindBufferBase GLenum target GLuint index GLuint buffer void glBindBufferBaseEXT GLenum target GLuint index GLuint buffer void glBindBufferBaseNV GLenum target GLuint index GLuint buffer void glBindBufferOffsetEXT GLenum target GLuint index GLuint buffer GLintptr offset void glBindBufferOffsetNV GLenum target GLuint index GLuint buffer GLintptr offset void glBindBufferRange GLenum target GLuint index GLuint buffer GLintptr offset GLsizeiptr size void glBindBufferRangeEXT GLenum target GLuint index GLuint buffer GLintptr offset GLsizeiptr size void glBindBufferRangeNV GLenum target GLuint index GLuint buffer GLintptr offset GLsizeiptr size void glBindBuffersBase GLenum target GLuint first GLsizei count const GLuint *buffers void glBindBuffersRange GLenum target GLuint first GLsizei count const GLuint *buffers const GLintptr *offsets const GLsizeiptr *sizes void glBindFragDataLocation GLuint program GLuint color const GLchar *name void glBindFragDataLocationEXT GLuint program GLuint color const GLchar *name void glBindFragDataLocationIndexed GLuint program GLuint colorNumber GLuint index const GLchar *name void glBindFragDataLocationIndexedEXT GLuint program GLuint colorNumber GLuint index const GLchar *name void glBindFragmentShaderATI GLuint id void glBindFramebuffer GLenum target GLuint framebuffer void glBindFramebufferEXT GLenum target GLuint framebuffer void glBindFramebufferOES GLenum target GLuint framebuffer void glBindImageTexture GLuint unit GLuint texture GLint level GLboolean layered GLint layer GLenum access GLenum format void glBindImageTextureEXT GLuint index GLuint texture GLint level GLboolean layered GLint layer GLenum access GLint format void glBindImageTextures GLuint first GLsizei count const GLuint *textures GLuint glBindLightParameterEXT GLenum light GLenum value GLuint glBindMaterialParameterEXT GLenum face GLenum value void glBindMultiTextureEXT GLenum texunit GLenum target GLuint texture GLuint glBindParameterEXT GLenum value void glBindProgramARB GLenum target GLuint program void glBindProgramNV GLenum target GLuint id void glBindProgramPipeline GLuint pipeline void glBindProgramPipelineEXT GLuint pipeline void glBindRenderbuffer GLenum target GLuint renderbuffer void glBindRenderbufferEXT GLenum target GLuint renderbuffer void glBindRenderbufferOES GLenum target GLuint renderbuffer void glBindSampler GLuint unit GLuint sampler void glBindSamplers GLuint first GLsizei count const GLuint *samplers GLuint glBindTexGenParameterEXT GLenum unit GLenum coord GLenum value void glBindTexture GLenum target GLuint texture void glBindTextureEXT GLenum target GLuint texture void glBindTextureUnit GLuint unit GLuint texture GLuint glBindTextureUnitParameterEXT GLenum unit GLenum value void glBindTextures GLuint first GLsizei count const GLuint *textures void glBindTransformFeedback GLenum target GLuint id void glBindTransformFeedbackNV GLenum target GLuint id void glBindVertexArray GLuint array void glBindVertexArrayAPPLE GLuint array void glBindVertexArrayOES GLuint array void glBindVertexBuffer GLuint bindingindex GLuint buffer GLintptr offset GLsizei stride void glBindVertexBuffers GLuint first GLsizei count const GLuint *buffers const GLintptr *offsets const GLsizei *strides void glBindVertexShaderEXT GLuint id void glBindVideoCaptureStreamBufferNV GLuint video_capture_slot GLuint stream GLenum frame_region GLintptrARB offset void glBindVideoCaptureStreamTextureNV GLuint video_capture_slot GLuint stream GLenum frame_region GLenum target GLuint texture void glBinormal3bEXT GLbyte bx GLbyte by GLbyte bz void glBinormal3bvEXT const GLbyte *v void glBinormal3dEXT GLdouble bx GLdouble by GLdouble bz void glBinormal3dvEXT const GLdouble *v void glBinormal3fEXT GLfloat bx GLfloat by GLfloat bz void glBinormal3fvEXT const GLfloat *v void glBinormal3iEXT GLint bx GLint by GLint bz void glBinormal3ivEXT const GLint *v void glBinormal3sEXT GLshort bx GLshort by GLshort bz void glBinormal3svEXT const GLshort *v void glBinormalPointerEXT GLenum type GLsizei stride const void *pointer void glBitmap GLsizei width GLsizei height GLfloat xorig GLfloat yorig GLfloat xmove GLfloat ymove const GLubyte *bitmap void glBitmapxOES GLsizei width GLsizei height GLfixed xorig GLfixed yorig GLfixed xmove GLfixed ymove const GLubyte *bitmap void glBlendBarrier void glBlendBarrierKHR void glBlendBarrierNV void glBlendColor GLfloat red GLfloat green GLfloat blue GLfloat alpha void glBlendColorEXT GLfloat red GLfloat green GLfloat blue GLfloat alpha void glBlendColorxOES GLfixed red GLfixed green GLfixed blue GLfixed alpha void glBlendEquation GLenum mode void glBlendEquationEXT GLenum mode void glBlendEquationIndexedAMD GLuint buf GLenum mode void glBlendEquationOES GLenum mode void glBlendEquationSeparate GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateEXT GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateIndexedAMD GLuint buf GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateOES GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparatei GLuint buf GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateiARB GLuint buf GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateiEXT GLuint buf GLenum modeRGB GLenum modeAlpha void glBlendEquationSeparateiOES GLuint buf GLenum modeRGB GLenum modeAlpha void glBlendEquationi GLuint buf GLenum mode void glBlendEquationiARB GLuint buf GLenum mode void glBlendEquationiEXT GLuint buf GLenum mode void glBlendEquationiOES GLuint buf GLenum mode void glBlendFunc GLenum sfactor GLenum dfactor void glBlendFuncIndexedAMD GLuint buf GLenum src GLenum dst void glBlendFuncSeparate GLenum sfactorRGB GLenum dfactorRGB GLenum sfactorAlpha GLenum dfactorAlpha void glBlendFuncSeparateEXT GLenum sfactorRGB GLenum dfactorRGB GLenum sfactorAlpha GLenum dfactorAlpha void glBlendFuncSeparateINGR GLenum sfactorRGB GLenum dfactorRGB GLenum sfactorAlpha GLenum dfactorAlpha void glBlendFuncSeparateIndexedAMD GLuint buf GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFuncSeparateOES GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFuncSeparatei GLuint buf GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFuncSeparateiARB GLuint buf GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFuncSeparateiEXT GLuint buf GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFuncSeparateiOES GLuint buf GLenum srcRGB GLenum dstRGB GLenum srcAlpha GLenum dstAlpha void glBlendFunci GLuint buf GLenum src GLenum dst void glBlendFunciARB GLuint buf GLenum src GLenum dst void glBlendFunciEXT GLuint buf GLenum src GLenum dst void glBlendFunciOES GLuint buf GLenum src GLenum dst void glBlendParameteriNV GLenum pname GLint value void glBlitFramebuffer GLint srcX0 GLint srcY0 GLint srcX1 GLint srcY1 GLint dstX0 GLint dstY0 GLint dstX1 GLint dstY1 GLbitfield mask GLenum filter void glBlitFramebufferANGLE GLint srcX0 GLint srcY0 GLint srcX1 GLint srcY1 GLint dstX0 GLint dstY0 GLint dstX1 GLint dstY1 GLbitfield mask GLenum filter void glBlitFramebufferEXT GLint srcX0 GLint srcY0 GLint srcX1 GLint srcY1 GLint dstX0 GLint dstY0 GLint dstX1 GLint dstY1 GLbitfield mask GLenum filter void glBlitFramebufferNV GLint srcX0 GLint srcY0 GLint srcX1 GLint srcY1 GLint dstX0 GLint dstY0 GLint dstX1 GLint dstY1 GLbitfield mask GLenum filter void glBlitNamedFramebuffer GLuint readFramebuffer GLuint drawFramebuffer GLint srcX0 GLint srcY0 GLint srcX1 GLint srcY1 GLint dstX0 GLint dstY0 GLint dstX1 GLint dstY1 GLbitfield mask GLenum filter void glBufferAddressRangeNV GLenum pname GLuint index GLuint64EXT address GLsizeiptr length void glBufferData GLenum target GLsizeiptr size const void *data GLenum usage void glBufferDataARB GLenum target GLsizeiptrARB size const void *data GLenum usage void glBufferPageCommitmentARB GLenum target GLintptr offset GLsizeiptr size GLboolean commit void glBufferParameteriAPPLE GLenum target GLenum pname GLint param void glBufferStorage GLenum target GLsizeiptr size const void *data GLbitfield flags void glBufferStorageEXT GLenum target GLsizeiptr size const void *data GLbitfield flags void glBufferSubData GLenum target GLintptr offset GLsizeiptr size const void *data void glBufferSubDataARB GLenum target GLintptrARB offset GLsizeiptrARB size const void *data void glCallCommandListNV GLuint list void glCallList GLuint list void glCallLists GLsizei n GLenum type const void *lists GLenum glCheckFramebufferStatus GLenum target GLenum glCheckFramebufferStatusEXT GLenum target GLenum glCheckFramebufferStatusOES GLenum target GLenum glCheckNamedFramebufferStatus GLuint framebuffer GLenum target GLenum glCheckNamedFramebufferStatusEXT GLuint framebuffer GLenum target void glClampColor GLenum target GLenum clamp void glClampColorARB GLenum target GLenum clamp void glClear GLbitfield mask void glClearAccum GLfloat red GLfloat green GLfloat blue GLfloat alpha void glClearAccumxOES GLfixed red GLfixed green GLfixed blue GLfixed alpha void glClearBufferData GLenum target GLenum internalformat GLenum format GLenum type const void *data void glClearBufferSubData GLenum target GLenum internalformat GLintptr offset GLsizeiptr size GLenum format GLenum type const void *data void glClearBufferfi GLenum buffer GLint drawbuffer GLfloat depth GLint stencil void glClearBufferfv GLenum buffer GLint drawbuffer const GLfloat *value void glClearBufferiv GLenum buffer GLint drawbuffer const GLint *value void glClearBufferuiv GLenum buffer GLint drawbuffer const GLuint *value void glClearColor GLfloat red GLfloat green GLfloat blue GLfloat alpha void glClearColorIiEXT GLint red GLint green GLint blue GLint alpha void glClearColorIuiEXT GLuint red GLuint green GLuint blue GLuint alpha void glClearColorx GLfixed red GLfixed green GLfixed blue GLfixed alpha void glClearColorxOES GLfixed red GLfixed green GLfixed blue GLfixed alpha void glClearDepth GLdouble depth void glClearDepthdNV GLdouble depth void glClearDepthf GLfloat d void glClearDepthfOES GLclampf depth void glClearDepthx GLfixed depth void glClearDepthxOES GLfixed depth void glClearIndex GLfloat c void glClearNamedBufferData GLuint buffer GLenum internalformat GLenum format GLenum type const void *data void glClearNamedBufferDataEXT GLuint buffer GLenum internalformat GLenum format GLenum type const void *data void glClearNamedBufferSubData GLuint buffer GLenum internalformat GLintptr offset GLsizeiptr size GLenum format GLenum type const void *data void glClearNamedBufferSubDataEXT GLuint buffer GLenum internalformat GLsizeiptr offset GLsizeiptr size GLenum format GLenum type const void *data void glClearNamedFramebufferfi GLuint framebuffer GLenum buffer GLint drawbuffer GLfloat depth GLint stencil void glClearNamedFramebufferfv GLuint framebuffer GLenum buffer GLint drawbuffer const GLfloat *value void glClearNamedFramebufferiv GLuint framebuffer GLenum buffer GLint drawbuffer const GLint *value void glClearNamedFramebufferuiv GLuint framebuffer GLenum buffer GLint drawbuffer const GLuint *value void glClearStencil GLint s void glClearTexImage GLuint texture GLint level GLenum format GLenum type const void *data void glClearTexSubImage GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *data void glClientActiveTexture GLenum texture void glClientActiveTextureARB GLenum texture void glClientActiveVertexStreamATI GLenum stream void glClientAttribDefaultEXT GLbitfield mask GLenum glClientWaitSync GLsync sync GLbitfield flags GLuint64 timeout GLenum glClientWaitSyncAPPLE GLsync sync GLbitfield flags GLuint64 timeout void glClipControl GLenum origin GLenum depth void glClipPlane GLenum plane const GLdouble *equation void glClipPlanef GLenum p const GLfloat *eqn void glClipPlanefIMG GLenum p const GLfloat *eqn void glClipPlanefOES GLenum plane const GLfloat *equation void glClipPlanex GLenum plane const GLfixed *equation void glClipPlanexIMG GLenum p const GLfixed *eqn void glClipPlanexOES GLenum plane const GLfixed *equation void glColor3b GLbyte red GLbyte green GLbyte blue void glColor3bv const GLbyte *v void glColor3d GLdouble red GLdouble green GLdouble blue void glColor3dv const GLdouble *v void glColor3f GLfloat red GLfloat green GLfloat blue void glColor3fVertex3fSUN GLfloat r GLfloat g GLfloat b GLfloat x GLfloat y GLfloat z void glColor3fVertex3fvSUN const GLfloat *c const GLfloat *v void glColor3fv const GLfloat *v void glColor3hNV GLhalfNV red GLhalfNV green GLhalfNV blue void glColor3hvNV const GLhalfNV *v void glColor3i GLint red GLint green GLint blue void glColor3iv const GLint *v void glColor3s GLshort red GLshort green GLshort blue void glColor3sv const GLshort *v void glColor3ub GLubyte red GLubyte green GLubyte blue void glColor3ubv const GLubyte *v void glColor3ui GLuint red GLuint green GLuint blue void glColor3uiv const GLuint *v void glColor3us GLushort red GLushort green GLushort blue void glColor3usv const GLushort *v void glColor3xOES GLfixed red GLfixed green GLfixed blue void glColor3xvOES const GLfixed *components void glColor4b GLbyte red GLbyte green GLbyte blue GLbyte alpha void glColor4bv const GLbyte *v void glColor4d GLdouble red GLdouble green GLdouble blue GLdouble alpha void glColor4dv const GLdouble *v void glColor4f GLfloat red GLfloat green GLfloat blue GLfloat alpha void glColor4fNormal3fVertex3fSUN GLfloat r GLfloat g GLfloat b GLfloat a GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glColor4fNormal3fVertex3fvSUN const GLfloat *c const GLfloat *n const GLfloat *v void glColor4fv const GLfloat *v void glColor4hNV GLhalfNV red GLhalfNV green GLhalfNV blue GLhalfNV alpha void glColor4hvNV const GLhalfNV *v void glColor4i GLint red GLint green GLint blue GLint alpha void glColor4iv const GLint *v void glColor4s GLshort red GLshort green GLshort blue GLshort alpha void glColor4sv const GLshort *v void glColor4ub GLubyte red GLubyte green GLubyte blue GLubyte alpha void glColor4ubVertex2fSUN GLubyte r GLubyte g GLubyte b GLubyte a GLfloat x GLfloat y void glColor4ubVertex2fvSUN const GLubyte *c const GLfloat *v void glColor4ubVertex3fSUN GLubyte r GLubyte g GLubyte b GLubyte a GLfloat x GLfloat y GLfloat z void glColor4ubVertex3fvSUN const GLubyte *c const GLfloat *v void glColor4ubv const GLubyte *v void glColor4ui GLuint red GLuint green GLuint blue GLuint alpha void glColor4uiv const GLuint *v void glColor4us GLushort red GLushort green GLushort blue GLushort alpha void glColor4usv const GLushort *v void glColor4x GLfixed red GLfixed green GLfixed blue GLfixed alpha void glColor4xOES GLfixed red GLfixed green GLfixed blue GLfixed alpha void glColor4xvOES const GLfixed *components void glColorFormatNV GLint size GLenum type GLsizei stride void glColorFragmentOp1ATI GLenum op GLuint dst GLuint dstMask GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod void glColorFragmentOp2ATI GLenum op GLuint dst GLuint dstMask GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod GLuint arg2 GLuint arg2Rep GLuint arg2Mod void glColorFragmentOp3ATI GLenum op GLuint dst GLuint dstMask GLuint dstMod GLuint arg1 GLuint arg1Rep GLuint arg1Mod GLuint arg2 GLuint arg2Rep GLuint arg2Mod GLuint arg3 GLuint arg3Rep GLuint arg3Mod void glColorMask GLboolean red GLboolean green GLboolean blue GLboolean alpha void glColorMaskIndexedEXT GLuint index GLboolean r GLboolean g GLboolean b GLboolean a void glColorMaski GLuint index GLboolean r GLboolean g GLboolean b GLboolean a void glColorMaskiEXT GLuint index GLboolean r GLboolean g GLboolean b GLboolean a void glColorMaskiOES GLuint index GLboolean r GLboolean g GLboolean b GLboolean a void glColorMaterial GLenum face GLenum mode void glColorP3ui GLenum type GLuint color void glColorP3uiv GLenum type const GLuint *color void glColorP4ui GLenum type GLuint color void glColorP4uiv GLenum type const GLuint *color void glColorPointer GLint size GLenum type GLsizei stride const void *pointer void glColorPointerEXT GLint size GLenum type GLsizei stride GLsizei count const void *pointer void glColorPointerListIBM GLint size GLenum type GLint stride const void **pointer GLint ptrstride void glColorPointervINTEL GLint size GLenum type const void **pointer void glColorSubTable GLenum target GLsizei start GLsizei count GLenum format GLenum type const void *data void glColorSubTableEXT GLenum target GLsizei start GLsizei count GLenum format GLenum type const void *data void glColorTable GLenum target GLenum internalformat GLsizei width GLenum format GLenum type const void *table void glColorTableEXT GLenum target GLenum internalFormat GLsizei width GLenum format GLenum type const void *table void glColorTableParameterfv GLenum target GLenum pname const GLfloat *params void glColorTableParameterfvSGI GLenum target GLenum pname const GLfloat *params void glColorTableParameteriv GLenum target GLenum pname const GLint *params void glColorTableParameterivSGI GLenum target GLenum pname const GLint *params void glColorTableSGI GLenum target GLenum internalformat GLsizei width GLenum format GLenum type const void *table void glCombinerInputNV GLenum stage GLenum portion GLenum variable GLenum input GLenum mapping GLenum componentUsage void glCombinerOutputNV GLenum stage GLenum portion GLenum abOutput GLenum cdOutput GLenum sumOutput GLenum scale GLenum bias GLboolean abDotProduct GLboolean cdDotProduct GLboolean muxSum void glCombinerParameterfNV GLenum pname GLfloat param void glCombinerParameterfvNV GLenum pname const GLfloat *params void glCombinerParameteriNV GLenum pname GLint param void glCombinerParameterivNV GLenum pname const GLint *params void glCombinerStageParameterfvNV GLenum stage GLenum pname const GLfloat *params void glCommandListSegmentsNV GLuint list GLuint segments void glCompileCommandListNV GLuint list void glCompileShader GLuint shader void glCompileShaderARB GLhandleARB shaderObj void glCompileShaderIncludeARB GLuint shader GLsizei count const GLchar *const*path const GLint *length void glCompressedMultiTexImage1DEXT GLenum texunit GLenum target GLint level GLenum internalformat GLsizei width GLint border GLsizei imageSize const void *bits void glCompressedMultiTexImage2DEXT GLenum texunit GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLint border GLsizei imageSize const void *bits void glCompressedMultiTexImage3DEXT GLenum texunit GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLsizei imageSize const void *bits void glCompressedMultiTexSubImage1DEXT GLenum texunit GLenum target GLint level GLint xoffset GLsizei width GLenum format GLsizei imageSize const void *bits void glCompressedMultiTexSubImage2DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLsizei imageSize const void *bits void glCompressedMultiTexSubImage3DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *bits void glCompressedTexImage1D GLenum target GLint level GLenum internalformat GLsizei width GLint border GLsizei imageSize const void *data void glCompressedTexImage1DARB GLenum target GLint level GLenum internalformat GLsizei width GLint border GLsizei imageSize const void *data void glCompressedTexImage2D GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLint border GLsizei imageSize const void *data void glCompressedTexImage2DARB GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLint border GLsizei imageSize const void *data void glCompressedTexImage3D GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLsizei imageSize const void *data void glCompressedTexImage3DARB GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLsizei imageSize const void *data void glCompressedTexImage3DOES GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLsizei imageSize const void *data void glCompressedTexSubImage1D GLenum target GLint level GLint xoffset GLsizei width GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage1DARB GLenum target GLint level GLint xoffset GLsizei width GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage2D GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage2DARB GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage3D GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage3DARB GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *data void glCompressedTexSubImage3DOES GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *data void glCompressedTextureImage1DEXT GLuint texture GLenum target GLint level GLenum internalformat GLsizei width GLint border GLsizei imageSize const void *bits void glCompressedTextureImage2DEXT GLuint texture GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLint border GLsizei imageSize const void *bits void glCompressedTextureImage3DEXT GLuint texture GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLsizei imageSize const void *bits void glCompressedTextureSubImage1D GLuint texture GLint level GLint xoffset GLsizei width GLenum format GLsizei imageSize const void *data void glCompressedTextureSubImage1DEXT GLuint texture GLenum target GLint level GLint xoffset GLsizei width GLenum format GLsizei imageSize const void *bits void glCompressedTextureSubImage2D GLuint texture GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLsizei imageSize const void *data void glCompressedTextureSubImage2DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLsizei imageSize const void *bits void glCompressedTextureSubImage3D GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *data void glCompressedTextureSubImage3DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLsizei imageSize const void *bits void glConservativeRasterParameterfNV GLenum pname GLfloat value void glConvolutionFilter1D GLenum target GLenum internalformat GLsizei width GLenum format GLenum type const void *image void glConvolutionFilter1DEXT GLenum target GLenum internalformat GLsizei width GLenum format GLenum type const void *image void glConvolutionFilter2D GLenum target GLenum internalformat GLsizei width GLsizei height GLenum format GLenum type const void *image void glConvolutionFilter2DEXT GLenum target GLenum internalformat GLsizei width GLsizei height GLenum format GLenum type const void *image void glConvolutionParameterf GLenum target GLenum pname GLfloat params void glConvolutionParameterfEXT GLenum target GLenum pname GLfloat params void glConvolutionParameterfv GLenum target GLenum pname const GLfloat *params void glConvolutionParameterfvEXT GLenum target GLenum pname const GLfloat *params void glConvolutionParameteri GLenum target GLenum pname GLint params void glConvolutionParameteriEXT GLenum target GLenum pname GLint params void glConvolutionParameteriv GLenum target GLenum pname const GLint *params void glConvolutionParameterivEXT GLenum target GLenum pname const GLint *params void glConvolutionParameterxOES GLenum target GLenum pname GLfixed param void glConvolutionParameterxvOES GLenum target GLenum pname const GLfixed *params void glCopyBufferSubData GLenum readTarget GLenum writeTarget GLintptr readOffset GLintptr writeOffset GLsizeiptr size void glCopyBufferSubDataNV GLenum readTarget GLenum writeTarget GLintptr readOffset GLintptr writeOffset GLsizeiptr size void glCopyColorSubTable GLenum target GLsizei start GLint x GLint y GLsizei width void glCopyColorSubTableEXT GLenum target GLsizei start GLint x GLint y GLsizei width void glCopyColorTable GLenum target GLenum internalformat GLint x GLint y GLsizei width void glCopyColorTableSGI GLenum target GLenum internalformat GLint x GLint y GLsizei width void glCopyConvolutionFilter1D GLenum target GLenum internalformat GLint x GLint y GLsizei width void glCopyConvolutionFilter1DEXT GLenum target GLenum internalformat GLint x GLint y GLsizei width void glCopyConvolutionFilter2D GLenum target GLenum internalformat GLint x GLint y GLsizei width GLsizei height void glCopyConvolutionFilter2DEXT GLenum target GLenum internalformat GLint x GLint y GLsizei width GLsizei height void glCopyImageSubData GLuint srcName GLenum srcTarget GLint srcLevel GLint srcX GLint srcY GLint srcZ GLuint dstName GLenum dstTarget GLint dstLevel GLint dstX GLint dstY GLint dstZ GLsizei srcWidth GLsizei srcHeight GLsizei srcDepth void glCopyImageSubDataEXT GLuint srcName GLenum srcTarget GLint srcLevel GLint srcX GLint srcY GLint srcZ GLuint dstName GLenum dstTarget GLint dstLevel GLint dstX GLint dstY GLint dstZ GLsizei srcWidth GLsizei srcHeight GLsizei srcDepth void glCopyImageSubDataNV GLuint srcName GLenum srcTarget GLint srcLevel GLint srcX GLint srcY GLint srcZ GLuint dstName GLenum dstTarget GLint dstLevel GLint dstX GLint dstY GLint dstZ GLsizei width GLsizei height GLsizei depth void glCopyImageSubDataOES GLuint srcName GLenum srcTarget GLint srcLevel GLint srcX GLint srcY GLint srcZ GLuint dstName GLenum dstTarget GLint dstLevel GLint dstX GLint dstY GLint dstZ GLsizei srcWidth GLsizei srcHeight GLsizei srcDepth void glCopyMultiTexImage1DEXT GLenum texunit GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLint border void glCopyMultiTexImage2DEXT GLenum texunit GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLsizei height GLint border void glCopyMultiTexSubImage1DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint x GLint y GLsizei width void glCopyMultiTexSubImage2DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLint x GLint y GLsizei width GLsizei height void glCopyMultiTexSubImage3DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCopyNamedBufferSubData GLuint readBuffer GLuint writeBuffer GLintptr readOffset GLintptr writeOffset GLsizeiptr size void glCopyPathNV GLuint resultPath GLuint srcPath void glCopyPixels GLint x GLint y GLsizei width GLsizei height GLenum type void glCopyTexImage1D GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLint border void glCopyTexImage1DEXT GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLint border void glCopyTexImage2D GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLsizei height GLint border void glCopyTexImage2DEXT GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLsizei height GLint border void glCopyTexSubImage1D GLenum target GLint level GLint xoffset GLint x GLint y GLsizei width void glCopyTexSubImage1DEXT GLenum target GLint level GLint xoffset GLint x GLint y GLsizei width void glCopyTexSubImage2D GLenum target GLint level GLint xoffset GLint yoffset GLint x GLint y GLsizei width GLsizei height void glCopyTexSubImage2DEXT GLenum target GLint level GLint xoffset GLint yoffset GLint x GLint y GLsizei width GLsizei height void glCopyTexSubImage3D GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCopyTexSubImage3DEXT GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCopyTexSubImage3DOES GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCopyTextureImage1DEXT GLuint texture GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLint border void glCopyTextureImage2DEXT GLuint texture GLenum target GLint level GLenum internalformat GLint x GLint y GLsizei width GLsizei height GLint border void glCopyTextureLevelsAPPLE GLuint destinationTexture GLuint sourceTexture GLint sourceBaseLevel GLsizei sourceLevelCount void glCopyTextureSubImage1D GLuint texture GLint level GLint xoffset GLint x GLint y GLsizei width void glCopyTextureSubImage1DEXT GLuint texture GLenum target GLint level GLint xoffset GLint x GLint y GLsizei width void glCopyTextureSubImage2D GLuint texture GLint level GLint xoffset GLint yoffset GLint x GLint y GLsizei width GLsizei height void glCopyTextureSubImage2DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLint x GLint y GLsizei width GLsizei height void glCopyTextureSubImage3D GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCopyTextureSubImage3DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint x GLint y GLsizei width GLsizei height void glCoverFillPathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLenum coverMode GLenum transformType const GLfloat *transformValues void glCoverFillPathNV GLuint path GLenum coverMode void glCoverStrokePathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLenum coverMode GLenum transformType const GLfloat *transformValues void glCoverStrokePathNV GLuint path GLenum coverMode void glCoverageMaskNV GLboolean mask void glCoverageModulationNV GLenum components void glCoverageModulationTableNV GLsizei n const GLfloat *v void glCoverageOperationNV GLenum operation void glCreateBuffers GLsizei n GLuint *buffers void glCreateCommandListsNV GLsizei n GLuint *lists void glCreateFramebuffers GLsizei n GLuint *framebuffers void glCreatePerfQueryINTEL GLuint queryId GLuint *queryHandle GLuint glCreateProgram GLhandleARB glCreateProgramObjectARB void glCreateProgramPipelines GLsizei n GLuint *pipelines void glCreateQueries GLenum target GLsizei n GLuint *ids void glCreateRenderbuffers GLsizei n GLuint *renderbuffers void glCreateSamplers GLsizei n GLuint *samplers GLuint glCreateShader GLenum type GLhandleARB glCreateShaderObjectARB GLenum shaderType GLuint glCreateShaderProgramEXT GLenum type const GLchar *string GLuint glCreateShaderProgramv GLenum type GLsizei count const GLchar *const*strings GLuint glCreateShaderProgramvEXT GLenum type GLsizei count const GLchar **strings void glCreateStatesNV GLsizei n GLuint *states GLsync glCreateSyncFromCLeventARB struct _cl_context *context struct _cl_event *event GLbitfield flags void glCreateTextures GLenum target GLsizei n GLuint *textures void glCreateTransformFeedbacks GLsizei n GLuint *ids void glCreateVertexArrays GLsizei n GLuint *arrays void glCullFace GLenum mode void glCullParameterdvEXT GLenum pname GLdouble *params void glCullParameterfvEXT GLenum pname GLfloat *params void glCurrentPaletteMatrixARB GLint index void glCurrentPaletteMatrixOES GLuint matrixpaletteindex void glDebugMessageCallback GLDEBUGPROC callback const void *userParam void glDebugMessageCallbackAMD GLDEBUGPROCAMD callback void *userParam void glDebugMessageCallbackARB GLDEBUGPROCARB callback const void *userParam void glDebugMessageCallbackKHR GLDEBUGPROCKHR callback const void *userParam void glDebugMessageControl GLenum source GLenum type GLenum severity GLsizei count const GLuint *ids GLboolean enabled void glDebugMessageControlARB GLenum source GLenum type GLenum severity GLsizei count const GLuint *ids GLboolean enabled void glDebugMessageControlKHR GLenum source GLenum type GLenum severity GLsizei count const GLuint *ids GLboolean enabled void glDebugMessageEnableAMD GLenum category GLenum severity GLsizei count const GLuint *ids GLboolean enabled void glDebugMessageInsert GLenum source GLenum type GLuint id GLenum severity GLsizei length const GLchar *buf void glDebugMessageInsertAMD GLenum category GLenum severity GLuint id GLsizei length const GLchar *buf void glDebugMessageInsertARB GLenum source GLenum type GLuint id GLenum severity GLsizei length const GLchar *buf void glDebugMessageInsertKHR GLenum source GLenum type GLuint id GLenum severity GLsizei length const GLchar *buf void glDeformSGIX GLbitfield mask void glDeformationMap3dSGIX GLenum target GLdouble u1 GLdouble u2 GLint ustride GLint uorder GLdouble v1 GLdouble v2 GLint vstride GLint vorder GLdouble w1 GLdouble w2 GLint wstride GLint worder const GLdouble *points void glDeformationMap3fSGIX GLenum target GLfloat u1 GLfloat u2 GLint ustride GLint uorder GLfloat v1 GLfloat v2 GLint vstride GLint vorder GLfloat w1 GLfloat w2 GLint wstride GLint worder const GLfloat *points void glDeleteAsyncMarkersSGIX GLuint marker GLsizei range void glDeleteBuffers GLsizei n const GLuint *buffers void glDeleteBuffersARB GLsizei n const GLuint *buffers void glDeleteCommandListsNV GLsizei n const GLuint *lists void glDeleteFencesAPPLE GLsizei n const GLuint *fences void glDeleteFencesNV GLsizei n const GLuint *fences void glDeleteFragmentShaderATI GLuint id void glDeleteFramebuffers GLsizei n const GLuint *framebuffers void glDeleteFramebuffersEXT GLsizei n const GLuint *framebuffers void glDeleteFramebuffersOES GLsizei n const GLuint *framebuffers void glDeleteLists GLuint list GLsizei range void glDeleteNamedStringARB GLint namelen const GLchar *name void glDeleteNamesAMD GLenum identifier GLuint num const GLuint *names void glDeleteObjectARB GLhandleARB obj void glDeleteOcclusionQueriesNV GLsizei n const GLuint *ids void glDeletePathsNV GLuint path GLsizei range void glDeletePerfMonitorsAMD GLsizei n GLuint *monitors void glDeletePerfQueryINTEL GLuint queryHandle void glDeleteProgram GLuint program void glDeleteProgramPipelines GLsizei n const GLuint *pipelines void glDeleteProgramPipelinesEXT GLsizei n const GLuint *pipelines void glDeleteProgramsARB GLsizei n const GLuint *programs void glDeleteProgramsNV GLsizei n const GLuint *programs void glDeleteQueries GLsizei n const GLuint *ids void glDeleteQueriesARB GLsizei n const GLuint *ids void glDeleteQueriesEXT GLsizei n const GLuint *ids void glDeleteRenderbuffers GLsizei n const GLuint *renderbuffers void glDeleteRenderbuffersEXT GLsizei n const GLuint *renderbuffers void glDeleteRenderbuffersOES GLsizei n const GLuint *renderbuffers void glDeleteSamplers GLsizei count const GLuint *samplers void glDeleteShader GLuint shader void glDeleteStatesNV GLsizei n const GLuint *states void glDeleteSync GLsync sync void glDeleteSyncAPPLE GLsync sync void glDeleteTextures GLsizei n const GLuint *textures void glDeleteTexturesEXT GLsizei n const GLuint *textures void glDeleteTransformFeedbacks GLsizei n const GLuint *ids void glDeleteTransformFeedbacksNV GLsizei n const GLuint *ids void glDeleteVertexArrays GLsizei n const GLuint *arrays void glDeleteVertexArraysAPPLE GLsizei n const GLuint *arrays void glDeleteVertexArraysOES GLsizei n const GLuint *arrays void glDeleteVertexShaderEXT GLuint id void glDepthBoundsEXT GLclampd zmin GLclampd zmax void glDepthBoundsdNV GLdouble zmin GLdouble zmax void glDepthFunc GLenum func void glDepthMask GLboolean flag void glDepthRange GLdouble near GLdouble far void glDepthRangeArrayfvNV GLuint first GLsizei count const GLfloat *v void glDepthRangeArrayv GLuint first GLsizei count const GLdouble *v void glDepthRangeIndexed GLuint index GLdouble n GLdouble f void glDepthRangeIndexedfNV GLuint index GLfloat n GLfloat f void glDepthRangedNV GLdouble zNear GLdouble zFar void glDepthRangef GLfloat n GLfloat f void glDepthRangefOES GLclampf n GLclampf f void glDepthRangex GLfixed n GLfixed f void glDepthRangexOES GLfixed n GLfixed f void glDetachObjectARB GLhandleARB containerObj GLhandleARB attachedObj void glDetachShader GLuint program GLuint shader void glDetailTexFuncSGIS GLenum target GLsizei n const GLfloat *points void glDisable GLenum cap void glDisableClientState GLenum array void glDisableClientStateIndexedEXT GLenum array GLuint index void glDisableClientStateiEXT GLenum array GLuint index void glDisableDriverControlQCOM GLuint driverControl void glDisableIndexedEXT GLenum target GLuint index void glDisableVariantClientStateEXT GLuint id void glDisableVertexArrayAttrib GLuint vaobj GLuint index void glDisableVertexArrayAttribEXT GLuint vaobj GLuint index void glDisableVertexArrayEXT GLuint vaobj GLenum array void glDisableVertexAttribAPPLE GLuint index GLenum pname void glDisableVertexAttribArray GLuint index void glDisableVertexAttribArrayARB GLuint index void glDisablei GLenum target GLuint index void glDisableiEXT GLenum target GLuint index void glDisableiNV GLenum target GLuint index void glDisableiOES GLenum target GLuint index void glDiscardFramebufferEXT GLenum target GLsizei numAttachments const GLenum *attachments void glDispatchCompute GLuint num_groups_x GLuint num_groups_y GLuint num_groups_z void glDispatchComputeGroupSizeARB GLuint num_groups_x GLuint num_groups_y GLuint num_groups_z GLuint group_size_x GLuint group_size_y GLuint group_size_z void glDispatchComputeIndirect GLintptr indirect void glDrawArrays GLenum mode GLint first GLsizei count void glDrawArraysEXT GLenum mode GLint first GLsizei count void glDrawArraysIndirect GLenum mode const void *indirect void glDrawArraysInstanced GLenum mode GLint first GLsizei count GLsizei instancecount void glDrawArraysInstancedANGLE GLenum mode GLint first GLsizei count GLsizei primcount void glDrawArraysInstancedARB GLenum mode GLint first GLsizei count GLsizei primcount void glDrawArraysInstancedBaseInstance GLenum mode GLint first GLsizei count GLsizei instancecount GLuint baseinstance void glDrawArraysInstancedBaseInstanceEXT GLenum mode GLint first GLsizei count GLsizei instancecount GLuint baseinstance void glDrawArraysInstancedEXT GLenum mode GLint start GLsizei count GLsizei primcount void glDrawArraysInstancedNV GLenum mode GLint first GLsizei count GLsizei primcount void glDrawBuffer GLenum buf void glDrawBuffers GLsizei n const GLenum *bufs void glDrawBuffersARB GLsizei n const GLenum *bufs void glDrawBuffersATI GLsizei n const GLenum *bufs void glDrawBuffersEXT GLsizei n const GLenum *bufs void glDrawBuffersIndexedEXT GLint n const GLenum *location const GLint *indices void glDrawBuffersNV GLsizei n const GLenum *bufs void glDrawCommandsAddressNV GLenum primitiveMode const GLuint64 *indirects const GLsizei *sizes GLuint count void glDrawCommandsNV GLenum primitiveMode GLuint buffer const GLintptr *indirects const GLsizei *sizes GLuint count void glDrawCommandsStatesAddressNV const GLuint64 *indirects const GLsizei *sizes const GLuint *states const GLuint *fbos GLuint count void glDrawCommandsStatesNV GLuint buffer const GLintptr *indirects const GLsizei *sizes const GLuint *states const GLuint *fbos GLuint count void glDrawElementArrayAPPLE GLenum mode GLint first GLsizei count void glDrawElementArrayATI GLenum mode GLsizei count void glDrawElements GLenum mode GLsizei count GLenum type const void *indices void glDrawElementsBaseVertex GLenum mode GLsizei count GLenum type const void *indices GLint basevertex void glDrawElementsBaseVertexEXT GLenum mode GLsizei count GLenum type const void *indices GLint basevertex void glDrawElementsBaseVertexOES GLenum mode GLsizei count GLenum type const void *indices GLint basevertex void glDrawElementsIndirect GLenum mode GLenum type const void *indirect void glDrawElementsInstanced GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount void glDrawElementsInstancedANGLE GLenum mode GLsizei count GLenum type const void *indices GLsizei primcount void glDrawElementsInstancedARB GLenum mode GLsizei count GLenum type const void *indices GLsizei primcount void glDrawElementsInstancedBaseInstance GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLuint baseinstance void glDrawElementsInstancedBaseInstanceEXT GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLuint baseinstance void glDrawElementsInstancedBaseVertex GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLint basevertex void glDrawElementsInstancedBaseVertexBaseInstance GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLint basevertex GLuint baseinstance void glDrawElementsInstancedBaseVertexBaseInstanceEXT GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLint basevertex GLuint baseinstance void glDrawElementsInstancedBaseVertexEXT GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLint basevertex void glDrawElementsInstancedBaseVertexOES GLenum mode GLsizei count GLenum type const void *indices GLsizei instancecount GLint basevertex void glDrawElementsInstancedEXT GLenum mode GLsizei count GLenum type const void *indices GLsizei primcount void glDrawElementsInstancedNV GLenum mode GLsizei count GLenum type const void *indices GLsizei primcount void glDrawMeshArraysSUN GLenum mode GLint first GLsizei count GLsizei width void glDrawPixels GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glDrawRangeElementArrayAPPLE GLenum mode GLuint start GLuint end GLint first GLsizei count void glDrawRangeElementArrayATI GLenum mode GLuint start GLuint end GLsizei count void glDrawRangeElements GLenum mode GLuint start GLuint end GLsizei count GLenum type const void *indices void glDrawRangeElementsBaseVertex GLenum mode GLuint start GLuint end GLsizei count GLenum type const void *indices GLint basevertex void glDrawRangeElementsBaseVertexEXT GLenum mode GLuint start GLuint end GLsizei count GLenum type const void *indices GLint basevertex void glDrawRangeElementsBaseVertexOES GLenum mode GLuint start GLuint end GLsizei count GLenum type const void *indices GLint basevertex void glDrawRangeElementsEXT GLenum mode GLuint start GLuint end GLsizei count GLenum type const void *indices void glDrawTexfOES GLfloat x GLfloat y GLfloat z GLfloat width GLfloat height void glDrawTexfvOES const GLfloat *coords void glDrawTexiOES GLint x GLint y GLint z GLint width GLint height void glDrawTexivOES const GLint *coords void glDrawTexsOES GLshort x GLshort y GLshort z GLshort width GLshort height void glDrawTexsvOES const GLshort *coords void glDrawTextureNV GLuint texture GLuint sampler GLfloat x0 GLfloat y0 GLfloat x1 GLfloat y1 GLfloat z GLfloat s0 GLfloat t0 GLfloat s1 GLfloat t1 void glDrawTexxOES GLfixed x GLfixed y GLfixed z GLfixed width GLfixed height void glDrawTexxvOES const GLfixed *coords void glDrawTransformFeedback GLenum mode GLuint id void glDrawTransformFeedbackInstanced GLenum mode GLuint id GLsizei instancecount void glDrawTransformFeedbackNV GLenum mode GLuint id void glDrawTransformFeedbackStream GLenum mode GLuint id GLuint stream void glDrawTransformFeedbackStreamInstanced GLenum mode GLuint id GLuint stream GLsizei instancecount void glEGLImageTargetRenderbufferStorageOES GLenum target GLeglImageOES image void glEGLImageTargetTexture2DOES GLenum target GLeglImageOES image void glEdgeFlag GLboolean flag void glEdgeFlagFormatNV GLsizei stride void glEdgeFlagPointer GLsizei stride const void *pointer void glEdgeFlagPointerEXT GLsizei stride GLsizei count const GLboolean *pointer void glEdgeFlagPointerListIBM GLint stride const GLboolean **pointer GLint ptrstride void glEdgeFlagv const GLboolean *flag void glElementPointerAPPLE GLenum type const void *pointer void glElementPointerATI GLenum type const void *pointer void glEnable GLenum cap void glEnableClientState GLenum array void glEnableClientStateIndexedEXT GLenum array GLuint index void glEnableClientStateiEXT GLenum array GLuint index void glEnableDriverControlQCOM GLuint driverControl void glEnableIndexedEXT GLenum target GLuint index void glEnableVariantClientStateEXT GLuint id void glEnableVertexArrayAttrib GLuint vaobj GLuint index void glEnableVertexArrayAttribEXT GLuint vaobj GLuint index void glEnableVertexArrayEXT GLuint vaobj GLenum array void glEnableVertexAttribAPPLE GLuint index GLenum pname void glEnableVertexAttribArray GLuint index void glEnableVertexAttribArrayARB GLuint index void glEnablei GLenum target GLuint index void glEnableiEXT GLenum target GLuint index void glEnableiNV GLenum target GLuint index void glEnableiOES GLenum target GLuint index void glEnd void glEndConditionalRender void glEndConditionalRenderNV void glEndConditionalRenderNVX void glEndFragmentShaderATI void glEndList void glEndOcclusionQueryNV void glEndPerfMonitorAMD GLuint monitor void glEndPerfQueryINTEL GLuint queryHandle void glEndQuery GLenum target void glEndQueryARB GLenum target void glEndQueryEXT GLenum target void glEndQueryIndexed GLenum target GLuint index void glEndTilingQCOM GLbitfield preserveMask void glEndTransformFeedback void glEndTransformFeedbackEXT void glEndTransformFeedbackNV void glEndVertexShaderEXT void glEndVideoCaptureNV GLuint video_capture_slot void glEvalCoord1d GLdouble u void glEvalCoord1dv const GLdouble *u void glEvalCoord1f GLfloat u void glEvalCoord1fv const GLfloat *u void glEvalCoord1xOES GLfixed u void glEvalCoord1xvOES const GLfixed *coords void glEvalCoord2d GLdouble u GLdouble v void glEvalCoord2dv const GLdouble *u void glEvalCoord2f GLfloat u GLfloat v void glEvalCoord2fv const GLfloat *u void glEvalCoord2xOES GLfixed u GLfixed v void glEvalCoord2xvOES const GLfixed *coords void glEvalMapsNV GLenum target GLenum mode void glEvalMesh1 GLenum mode GLint i1 GLint i2 void glEvalMesh2 GLenum mode GLint i1 GLint i2 GLint j1 GLint j2 void glEvalPoint1 GLint i void glEvalPoint2 GLint i GLint j void glEvaluateDepthValuesARB void glExecuteProgramNV GLenum target GLuint id const GLfloat *params void glExtGetBufferPointervQCOM GLenum target void **params void glExtGetBuffersQCOM GLuint *buffers GLint maxBuffers GLint *numBuffers void glExtGetFramebuffersQCOM GLuint *framebuffers GLint maxFramebuffers GLint *numFramebuffers void glExtGetProgramBinarySourceQCOM GLuint program GLenum shadertype GLchar *source GLint *length void glExtGetProgramsQCOM GLuint *programs GLint maxPrograms GLint *numPrograms void glExtGetRenderbuffersQCOM GLuint *renderbuffers GLint maxRenderbuffers GLint *numRenderbuffers void glExtGetShadersQCOM GLuint *shaders GLint maxShaders GLint *numShaders void glExtGetTexLevelParameterivQCOM GLuint texture GLenum face GLint level GLenum pname GLint *params void glExtGetTexSubImageQCOM GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type void *texels void glExtGetTexturesQCOM GLuint *textures GLint maxTextures GLint *numTextures GLboolean glExtIsProgramBinaryQCOM GLuint program void glExtTexObjectStateOverrideiQCOM GLenum target GLenum pname GLint param void glExtractComponentEXT GLuint res GLuint src GLuint num void glFeedbackBuffer GLsizei size GLenum type GLfloat *buffer void glFeedbackBufferxOES GLsizei n GLenum type const GLfixed *buffer GLsync glFenceSync GLenum condition GLbitfield flags GLsync glFenceSyncAPPLE GLenum condition GLbitfield flags void glFinalCombinerInputNV GLenum variable GLenum input GLenum mapping GLenum componentUsage void glFinish GLint glFinishAsyncSGIX GLuint *markerp void glFinishFenceAPPLE GLuint fence void glFinishFenceNV GLuint fence void glFinishObjectAPPLE GLenum object GLint name void glFinishTextureSUNX void glFlush void glFlushMappedBufferRange GLenum target GLintptr offset GLsizeiptr length void glFlushMappedBufferRangeAPPLE GLenum target GLintptr offset GLsizeiptr size void glFlushMappedBufferRangeEXT GLenum target GLintptr offset GLsizeiptr length void glFlushMappedNamedBufferRange GLuint buffer GLintptr offset GLsizeiptr length void glFlushMappedNamedBufferRangeEXT GLuint buffer GLintptr offset GLsizeiptr length void glFlushPixelDataRangeNV GLenum target void glFlushRasterSGIX void glFlushStaticDataIBM GLenum target void glFlushVertexArrayRangeAPPLE GLsizei length void *pointer void glFlushVertexArrayRangeNV void glFogCoordFormatNV GLenum type GLsizei stride void glFogCoordPointer GLenum type GLsizei stride const void *pointer void glFogCoordPointerEXT GLenum type GLsizei stride const void *pointer void glFogCoordPointerListIBM GLenum type GLint stride const void **pointer GLint ptrstride void glFogCoordd GLdouble coord void glFogCoorddEXT GLdouble coord void glFogCoorddv const GLdouble *coord void glFogCoorddvEXT const GLdouble *coord void glFogCoordf GLfloat coord void glFogCoordfEXT GLfloat coord void glFogCoordfv const GLfloat *coord void glFogCoordfvEXT const GLfloat *coord void glFogCoordhNV GLhalfNV fog void glFogCoordhvNV const GLhalfNV *fog void glFogFuncSGIS GLsizei n const GLfloat *points void glFogf GLenum pname GLfloat param void glFogfv GLenum pname const GLfloat *params void glFogi GLenum pname GLint param void glFogiv GLenum pname const GLint *params void glFogx GLenum pname GLfixed param void glFogxOES GLenum pname GLfixed param void glFogxv GLenum pname const GLfixed *param void glFogxvOES GLenum pname const GLfixed *param void glFragmentColorMaterialSGIX GLenum face GLenum mode void glFragmentCoverageColorNV GLuint color void glFragmentLightModelfSGIX GLenum pname GLfloat param void glFragmentLightModelfvSGIX GLenum pname const GLfloat *params void glFragmentLightModeliSGIX GLenum pname GLint param void glFragmentLightModelivSGIX GLenum pname const GLint *params void glFragmentLightfSGIX GLenum light GLenum pname GLfloat param void glFragmentLightfvSGIX GLenum light GLenum pname const GLfloat *params void glFragmentLightiSGIX GLenum light GLenum pname GLint param void glFragmentLightivSGIX GLenum light GLenum pname const GLint *params void glFragmentMaterialfSGIX GLenum face GLenum pname GLfloat param void glFragmentMaterialfvSGIX GLenum face GLenum pname const GLfloat *params void glFragmentMaterialiSGIX GLenum face GLenum pname GLint param void glFragmentMaterialivSGIX GLenum face GLenum pname const GLint *params void glFrameTerminatorGREMEDY void glFrameZoomSGIX GLint factor void glFramebufferDrawBufferEXT GLuint framebuffer GLenum mode void glFramebufferDrawBuffersEXT GLuint framebuffer GLsizei n const GLenum *bufs void glFramebufferParameteri GLenum target GLenum pname GLint param void glFramebufferReadBufferEXT GLuint framebuffer GLenum mode void glFramebufferRenderbuffer GLenum target GLenum attachment GLenum renderbuffertarget GLuint renderbuffer void glFramebufferRenderbufferEXT GLenum target GLenum attachment GLenum renderbuffertarget GLuint renderbuffer void glFramebufferRenderbufferOES GLenum target GLenum attachment GLenum renderbuffertarget GLuint renderbuffer void glFramebufferSampleLocationsfvARB GLenum target GLuint start GLsizei count const GLfloat *v void glFramebufferSampleLocationsfvNV GLenum target GLuint start GLsizei count const GLfloat *v void glFramebufferTexture GLenum target GLenum attachment GLuint texture GLint level void glFramebufferTexture1D GLenum target GLenum attachment GLenum textarget GLuint texture GLint level void glFramebufferTexture1DEXT GLenum target GLenum attachment GLenum textarget GLuint texture GLint level void glFramebufferTexture2D GLenum target GLenum attachment GLenum textarget GLuint texture GLint level void glFramebufferTexture2DEXT GLenum target GLenum attachment GLenum textarget GLuint texture GLint level void glFramebufferTexture2DMultisampleEXT GLenum target GLenum attachment GLenum textarget GLuint texture GLint level GLsizei samples void glFramebufferTexture2DMultisampleIMG GLenum target GLenum attachment GLenum textarget GLuint texture GLint level GLsizei samples void glFramebufferTexture2DOES GLenum target GLenum attachment GLenum textarget GLuint texture GLint level void glFramebufferTexture3D GLenum target GLenum attachment GLenum textarget GLuint texture GLint level GLint zoffset void glFramebufferTexture3DEXT GLenum target GLenum attachment GLenum textarget GLuint texture GLint level GLint zoffset void glFramebufferTexture3DOES GLenum target GLenum attachment GLenum textarget GLuint texture GLint level GLint zoffset void glFramebufferTextureARB GLenum target GLenum attachment GLuint texture GLint level void glFramebufferTextureEXT GLenum target GLenum attachment GLuint texture GLint level void glFramebufferTextureFaceARB GLenum target GLenum attachment GLuint texture GLint level GLenum face void glFramebufferTextureFaceEXT GLenum target GLenum attachment GLuint texture GLint level GLenum face void glFramebufferTextureLayer GLenum target GLenum attachment GLuint texture GLint level GLint layer void glFramebufferTextureLayerARB GLenum target GLenum attachment GLuint texture GLint level GLint layer void glFramebufferTextureLayerEXT GLenum target GLenum attachment GLuint texture GLint level GLint layer void glFramebufferTextureMultisampleMultiviewOVR GLenum target GLenum attachment GLuint texture GLint level GLsizei samples GLint baseViewIndex GLsizei numViews void glFramebufferTextureMultiviewOVR GLenum target GLenum attachment GLuint texture GLint level GLint baseViewIndex GLsizei numViews void glFramebufferTextureOES GLenum target GLenum attachment GLuint texture GLint level void glFreeObjectBufferATI GLuint buffer void glFrontFace GLenum mode void glFrustum GLdouble left GLdouble right GLdouble bottom GLdouble top GLdouble zNear GLdouble zFar void glFrustumf GLfloat l GLfloat r GLfloat b GLfloat t GLfloat n GLfloat f void glFrustumfOES GLfloat l GLfloat r GLfloat b GLfloat t GLfloat n GLfloat f void glFrustumx GLfixed l GLfixed r GLfixed b GLfixed t GLfixed n GLfixed f void glFrustumxOES GLfixed l GLfixed r GLfixed b GLfixed t GLfixed n GLfixed f GLuint glGenAsyncMarkersSGIX GLsizei range void glGenBuffers GLsizei n GLuint *buffers void glGenBuffersARB GLsizei n GLuint *buffers void glGenFencesAPPLE GLsizei n GLuint *fences void glGenFencesNV GLsizei n GLuint *fences GLuint glGenFragmentShadersATI GLuint range void glGenFramebuffers GLsizei n GLuint *framebuffers void glGenFramebuffersEXT GLsizei n GLuint *framebuffers void glGenFramebuffersOES GLsizei n GLuint *framebuffers GLuint glGenLists GLsizei range void glGenNamesAMD GLenum identifier GLuint num GLuint *names void glGenOcclusionQueriesNV GLsizei n GLuint *ids GLuint glGenPathsNV GLsizei range void glGenPerfMonitorsAMD GLsizei n GLuint *monitors void glGenProgramPipelines GLsizei n GLuint *pipelines void glGenProgramPipelinesEXT GLsizei n GLuint *pipelines void glGenProgramsARB GLsizei n GLuint *programs void glGenProgramsNV GLsizei n GLuint *programs void glGenQueries GLsizei n GLuint *ids void glGenQueriesARB GLsizei n GLuint *ids void glGenQueriesEXT GLsizei n GLuint *ids void glGenRenderbuffers GLsizei n GLuint *renderbuffers void glGenRenderbuffersEXT GLsizei n GLuint *renderbuffers void glGenRenderbuffersOES GLsizei n GLuint *renderbuffers void glGenSamplers GLsizei count GLuint *samplers GLuint glGenSymbolsEXT GLenum datatype GLenum storagetype GLenum range GLuint components void glGenTextures GLsizei n GLuint *textures void glGenTexturesEXT GLsizei n GLuint *textures void glGenTransformFeedbacks GLsizei n GLuint *ids void glGenTransformFeedbacksNV GLsizei n GLuint *ids void glGenVertexArrays GLsizei n GLuint *arrays void glGenVertexArraysAPPLE GLsizei n GLuint *arrays void glGenVertexArraysOES GLsizei n GLuint *arrays GLuint glGenVertexShadersEXT GLuint range void glGenerateMipmap GLenum target void glGenerateMipmapEXT GLenum target void glGenerateMipmapOES GLenum target void glGenerateMultiTexMipmapEXT GLenum texunit GLenum target void glGenerateTextureMipmap GLuint texture void glGenerateTextureMipmapEXT GLuint texture GLenum target void glGetActiveAtomicCounterBufferiv GLuint program GLuint bufferIndex GLenum pname GLint *params void glGetActiveAttrib GLuint program GLuint index GLsizei bufSize GLsizei *length GLint *size GLenum *type GLchar *name void glGetActiveAttribARB GLhandleARB programObj GLuint index GLsizei maxLength GLsizei *length GLint *size GLenum *type GLcharARB *name void glGetActiveSubroutineName GLuint program GLenum shadertype GLuint index GLsizei bufsize GLsizei *length GLchar *name void glGetActiveSubroutineUniformName GLuint program GLenum shadertype GLuint index GLsizei bufsize GLsizei *length GLchar *name void glGetActiveSubroutineUniformiv GLuint program GLenum shadertype GLuint index GLenum pname GLint *values void glGetActiveUniform GLuint program GLuint index GLsizei bufSize GLsizei *length GLint *size GLenum *type GLchar *name void glGetActiveUniformARB GLhandleARB programObj GLuint index GLsizei maxLength GLsizei *length GLint *size GLenum *type GLcharARB *name void glGetActiveUniformBlockName GLuint program GLuint uniformBlockIndex GLsizei bufSize GLsizei *length GLchar *uniformBlockName void glGetActiveUniformBlockiv GLuint program GLuint uniformBlockIndex GLenum pname GLint *params void glGetActiveUniformName GLuint program GLuint uniformIndex GLsizei bufSize GLsizei *length GLchar *uniformName void glGetActiveUniformsiv GLuint program GLsizei uniformCount const GLuint *uniformIndices GLenum pname GLint *params void glGetActiveVaryingNV GLuint program GLuint index GLsizei bufSize GLsizei *length GLsizei *size GLenum *type GLchar *name void glGetArrayObjectfvATI GLenum array GLenum pname GLfloat *params void glGetArrayObjectivATI GLenum array GLenum pname GLint *params void glGetAttachedObjectsARB GLhandleARB containerObj GLsizei maxCount GLsizei *count GLhandleARB *obj void glGetAttachedShaders GLuint program GLsizei maxCount GLsizei *count GLuint *shaders GLint glGetAttribLocation GLuint program const GLchar *name GLint glGetAttribLocationARB GLhandleARB programObj const GLcharARB *name void glGetBooleanIndexedvEXT GLenum target GLuint index GLboolean *data void glGetBooleani_v GLenum target GLuint index GLboolean *data void glGetBooleanv GLenum pname GLboolean *data void glGetBufferParameteri64v GLenum target GLenum pname GLint64 *params void glGetBufferParameteriv GLenum target GLenum pname GLint *params void glGetBufferParameterivARB GLenum target GLenum pname GLint *params void glGetBufferParameterui64vNV GLenum target GLenum pname GLuint64EXT *params void glGetBufferPointerv GLenum target GLenum pname void **params void glGetBufferPointervARB GLenum target GLenum pname void **params void glGetBufferPointervOES GLenum target GLenum pname void **params void glGetBufferSubData GLenum target GLintptr offset GLsizeiptr size void *data void glGetBufferSubDataARB GLenum target GLintptrARB offset GLsizeiptrARB size void *data void glGetClipPlane GLenum plane GLdouble *equation void glGetClipPlanef GLenum plane GLfloat *equation void glGetClipPlanefOES GLenum plane GLfloat *equation void glGetClipPlanex GLenum plane GLfixed *equation void glGetClipPlanexOES GLenum plane GLfixed *equation void glGetColorTable GLenum target GLenum format GLenum type void *table void glGetColorTableEXT GLenum target GLenum format GLenum type void *data void glGetColorTableParameterfv GLenum target GLenum pname GLfloat *params void glGetColorTableParameterfvEXT GLenum target GLenum pname GLfloat *params void glGetColorTableParameterfvSGI GLenum target GLenum pname GLfloat *params void glGetColorTableParameteriv GLenum target GLenum pname GLint *params void glGetColorTableParameterivEXT GLenum target GLenum pname GLint *params void glGetColorTableParameterivSGI GLenum target GLenum pname GLint *params void glGetColorTableSGI GLenum target GLenum format GLenum type void *table void glGetCombinerInputParameterfvNV GLenum stage GLenum portion GLenum variable GLenum pname GLfloat *params void glGetCombinerInputParameterivNV GLenum stage GLenum portion GLenum variable GLenum pname GLint *params void glGetCombinerOutputParameterfvNV GLenum stage GLenum portion GLenum pname GLfloat *params void glGetCombinerOutputParameterivNV GLenum stage GLenum portion GLenum pname GLint *params void glGetCombinerStageParameterfvNV GLenum stage GLenum pname GLfloat *params GLuint glGetCommandHeaderNV GLenum tokenID GLuint size void glGetCompressedMultiTexImageEXT GLenum texunit GLenum target GLint lod void *img void glGetCompressedTexImage GLenum target GLint level void *img void glGetCompressedTexImageARB GLenum target GLint level void *img void glGetCompressedTextureImage GLuint texture GLint level GLsizei bufSize void *pixels void glGetCompressedTextureImageEXT GLuint texture GLenum target GLint lod void *img void glGetCompressedTextureSubImage GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLsizei bufSize void *pixels void glGetConvolutionFilter GLenum target GLenum format GLenum type void *image void glGetConvolutionFilterEXT GLenum target GLenum format GLenum type void *image void glGetConvolutionParameterfv GLenum target GLenum pname GLfloat *params void glGetConvolutionParameterfvEXT GLenum target GLenum pname GLfloat *params void glGetConvolutionParameteriv GLenum target GLenum pname GLint *params void glGetConvolutionParameterivEXT GLenum target GLenum pname GLint *params void glGetConvolutionParameterxvOES GLenum target GLenum pname GLfixed *params void glGetCoverageModulationTableNV GLsizei bufsize GLfloat *v GLuint glGetDebugMessageLog GLuint count GLsizei bufSize GLenum *sources GLenum *types GLuint *ids GLenum *severities GLsizei *lengths GLchar *messageLog GLuint glGetDebugMessageLogAMD GLuint count GLsizei bufsize GLenum *categories GLuint *severities GLuint *ids GLsizei *lengths GLchar *message GLuint glGetDebugMessageLogARB GLuint count GLsizei bufSize GLenum *sources GLenum *types GLuint *ids GLenum *severities GLsizei *lengths GLchar *messageLog GLuint glGetDebugMessageLogKHR GLuint count GLsizei bufSize GLenum *sources GLenum *types GLuint *ids GLenum *severities GLsizei *lengths GLchar *messageLog void glGetDetailTexFuncSGIS GLenum target GLfloat *points void glGetDoubleIndexedvEXT GLenum target GLuint index GLdouble *data void glGetDoublei_v GLenum target GLuint index GLdouble *data void glGetDoublei_vEXT GLenum pname GLuint index GLdouble *params void glGetDoublev GLenum pname GLdouble *data void glGetDriverControlStringQCOM GLuint driverControl GLsizei bufSize GLsizei *length GLchar *driverControlString void glGetDriverControlsQCOM GLint *num GLsizei size GLuint *driverControls GLenum glGetError void glGetFenceivNV GLuint fence GLenum pname GLint *params void glGetFinalCombinerInputParameterfvNV GLenum variable GLenum pname GLfloat *params void glGetFinalCombinerInputParameterivNV GLenum variable GLenum pname GLint *params void glGetFirstPerfQueryIdINTEL GLuint *queryId void glGetFixedv GLenum pname GLfixed *params void glGetFixedvOES GLenum pname GLfixed *params void glGetFloatIndexedvEXT GLenum target GLuint index GLfloat *data void glGetFloati_v GLenum target GLuint index GLfloat *data void glGetFloati_vEXT GLenum pname GLuint index GLfloat *params void glGetFloati_vNV GLenum target GLuint index GLfloat *data void glGetFloatv GLenum pname GLfloat *data void glGetFogFuncSGIS GLfloat *points GLint glGetFragDataIndex GLuint program const GLchar *name GLint glGetFragDataIndexEXT GLuint program const GLchar *name GLint glGetFragDataLocation GLuint program const GLchar *name GLint glGetFragDataLocationEXT GLuint program const GLchar *name void glGetFragmentLightfvSGIX GLenum light GLenum pname GLfloat *params void glGetFragmentLightivSGIX GLenum light GLenum pname GLint *params void glGetFragmentMaterialfvSGIX GLenum face GLenum pname GLfloat *params void glGetFragmentMaterialivSGIX GLenum face GLenum pname GLint *params void glGetFramebufferAttachmentParameteriv GLenum target GLenum attachment GLenum pname GLint *params void glGetFramebufferAttachmentParameterivEXT GLenum target GLenum attachment GLenum pname GLint *params void glGetFramebufferAttachmentParameterivOES GLenum target GLenum attachment GLenum pname GLint *params void glGetFramebufferParameteriv GLenum target GLenum pname GLint *params void glGetFramebufferParameterivEXT GLuint framebuffer GLenum pname GLint *params GLenum glGetGraphicsResetStatus GLenum glGetGraphicsResetStatusARB GLenum glGetGraphicsResetStatusEXT GLenum glGetGraphicsResetStatusKHR GLhandleARB glGetHandleARB GLenum pname void glGetHistogram GLenum target GLboolean reset GLenum format GLenum type void *values void glGetHistogramEXT GLenum target GLboolean reset GLenum format GLenum type void *values void glGetHistogramParameterfv GLenum target GLenum pname GLfloat *params void glGetHistogramParameterfvEXT GLenum target GLenum pname GLfloat *params void glGetHistogramParameteriv GLenum target GLenum pname GLint *params void glGetHistogramParameterivEXT GLenum target GLenum pname GLint *params void glGetHistogramParameterxvOES GLenum target GLenum pname GLfixed *params GLuint64 glGetImageHandleARB GLuint texture GLint level GLboolean layered GLint layer GLenum format GLuint64 glGetImageHandleNV GLuint texture GLint level GLboolean layered GLint layer GLenum format void glGetImageTransformParameterfvHP GLenum target GLenum pname GLfloat *params void glGetImageTransformParameterivHP GLenum target GLenum pname GLint *params void glGetInfoLogARB GLhandleARB obj GLsizei maxLength GLsizei *length GLcharARB *infoLog GLint glGetInstrumentsSGIX void glGetInteger64i_v GLenum target GLuint index GLint64 *data void glGetInteger64v GLenum pname GLint64 *data void glGetInteger64vAPPLE GLenum pname GLint64 *params void glGetIntegerIndexedvEXT GLenum target GLuint index GLint *data void glGetIntegeri_v GLenum target GLuint index GLint *data void glGetIntegeri_vEXT GLenum target GLuint index GLint *data void glGetIntegerui64i_vNV GLenum value GLuint index GLuint64EXT *result void glGetIntegerui64vNV GLenum value GLuint64EXT *result void glGetIntegerv GLenum pname GLint *data void glGetInternalformatSampleivNV GLenum target GLenum internalformat GLsizei samples GLenum pname GLsizei bufSize GLint *params void glGetInternalformati64v GLenum target GLenum internalformat GLenum pname GLsizei bufSize GLint64 *params void glGetInternalformativ GLenum target GLenum internalformat GLenum pname GLsizei bufSize GLint *params void glGetInvariantBooleanvEXT GLuint id GLenum value GLboolean *data void glGetInvariantFloatvEXT GLuint id GLenum value GLfloat *data void glGetInvariantIntegervEXT GLuint id GLenum value GLint *data void glGetLightfv GLenum light GLenum pname GLfloat *params void glGetLightiv GLenum light GLenum pname GLint *params void glGetLightxOES GLenum light GLenum pname GLfixed *params void glGetLightxv GLenum light GLenum pname GLfixed *params void glGetLightxvOES GLenum light GLenum pname GLfixed *params void glGetListParameterfvSGIX GLuint list GLenum pname GLfloat *params void glGetListParameterivSGIX GLuint list GLenum pname GLint *params void glGetLocalConstantBooleanvEXT GLuint id GLenum value GLboolean *data void glGetLocalConstantFloatvEXT GLuint id GLenum value GLfloat *data void glGetLocalConstantIntegervEXT GLuint id GLenum value GLint *data void glGetMapAttribParameterfvNV GLenum target GLuint index GLenum pname GLfloat *params void glGetMapAttribParameterivNV GLenum target GLuint index GLenum pname GLint *params void glGetMapControlPointsNV GLenum target GLuint index GLenum type GLsizei ustride GLsizei vstride GLboolean packed void *points void glGetMapParameterfvNV GLenum target GLenum pname GLfloat *params void glGetMapParameterivNV GLenum target GLenum pname GLint *params void glGetMapdv GLenum target GLenum query GLdouble *v void glGetMapfv GLenum target GLenum query GLfloat *v void glGetMapiv GLenum target GLenum query GLint *v void glGetMapxvOES GLenum target GLenum query GLfixed *v void glGetMaterialfv GLenum face GLenum pname GLfloat *params void glGetMaterialiv GLenum face GLenum pname GLint *params void glGetMaterialxOES GLenum face GLenum pname GLfixed param void glGetMaterialxv GLenum face GLenum pname GLfixed *params void glGetMaterialxvOES GLenum face GLenum pname GLfixed *params void glGetMinmax GLenum target GLboolean reset GLenum format GLenum type void *values void glGetMinmaxEXT GLenum target GLboolean reset GLenum format GLenum type void *values void glGetMinmaxParameterfv GLenum target GLenum pname GLfloat *params void glGetMinmaxParameterfvEXT GLenum target GLenum pname GLfloat *params void glGetMinmaxParameteriv GLenum target GLenum pname GLint *params void glGetMinmaxParameterivEXT GLenum target GLenum pname GLint *params void glGetMultiTexEnvfvEXT GLenum texunit GLenum target GLenum pname GLfloat *params void glGetMultiTexEnvivEXT GLenum texunit GLenum target GLenum pname GLint *params void glGetMultiTexGendvEXT GLenum texunit GLenum coord GLenum pname GLdouble *params void glGetMultiTexGenfvEXT GLenum texunit GLenum coord GLenum pname GLfloat *params void glGetMultiTexGenivEXT GLenum texunit GLenum coord GLenum pname GLint *params void glGetMultiTexImageEXT GLenum texunit GLenum target GLint level GLenum format GLenum type void *pixels void glGetMultiTexLevelParameterfvEXT GLenum texunit GLenum target GLint level GLenum pname GLfloat *params void glGetMultiTexLevelParameterivEXT GLenum texunit GLenum target GLint level GLenum pname GLint *params void glGetMultiTexParameterIivEXT GLenum texunit GLenum target GLenum pname GLint *params void glGetMultiTexParameterIuivEXT GLenum texunit GLenum target GLenum pname GLuint *params void glGetMultiTexParameterfvEXT GLenum texunit GLenum target GLenum pname GLfloat *params void glGetMultiTexParameterivEXT GLenum texunit GLenum target GLenum pname GLint *params void glGetMultisamplefv GLenum pname GLuint index GLfloat *val void glGetMultisamplefvNV GLenum pname GLuint index GLfloat *val void glGetNamedBufferParameteri64v GLuint buffer GLenum pname GLint64 *params void glGetNamedBufferParameteriv GLuint buffer GLenum pname GLint *params void glGetNamedBufferParameterivEXT GLuint buffer GLenum pname GLint *params void glGetNamedBufferParameterui64vNV GLuint buffer GLenum pname GLuint64EXT *params void glGetNamedBufferPointerv GLuint buffer GLenum pname void **params void glGetNamedBufferPointervEXT GLuint buffer GLenum pname void **params void glGetNamedBufferSubData GLuint buffer GLintptr offset GLsizeiptr size void *data void glGetNamedBufferSubDataEXT GLuint buffer GLintptr offset GLsizeiptr size void *data void glGetNamedFramebufferAttachmentParameteriv GLuint framebuffer GLenum attachment GLenum pname GLint *params void glGetNamedFramebufferAttachmentParameterivEXT GLuint framebuffer GLenum attachment GLenum pname GLint *params void glGetNamedFramebufferParameteriv GLuint framebuffer GLenum pname GLint *param void glGetNamedFramebufferParameterivEXT GLuint framebuffer GLenum pname GLint *params void glGetNamedProgramLocalParameterIivEXT GLuint program GLenum target GLuint index GLint *params void glGetNamedProgramLocalParameterIuivEXT GLuint program GLenum target GLuint index GLuint *params void glGetNamedProgramLocalParameterdvEXT GLuint program GLenum target GLuint index GLdouble *params void glGetNamedProgramLocalParameterfvEXT GLuint program GLenum target GLuint index GLfloat *params void glGetNamedProgramStringEXT GLuint program GLenum target GLenum pname void *string void glGetNamedProgramivEXT GLuint program GLenum target GLenum pname GLint *params void glGetNamedRenderbufferParameteriv GLuint renderbuffer GLenum pname GLint *params void glGetNamedRenderbufferParameterivEXT GLuint renderbuffer GLenum pname GLint *params void glGetNamedStringARB GLint namelen const GLchar *name GLsizei bufSize GLint *stringlen GLchar *string void glGetNamedStringivARB GLint namelen const GLchar *name GLenum pname GLint *params void glGetNextPerfQueryIdINTEL GLuint queryId GLuint *nextQueryId void glGetObjectBufferfvATI GLuint buffer GLenum pname GLfloat *params void glGetObjectBufferivATI GLuint buffer GLenum pname GLint *params void glGetObjectLabel GLenum identifier GLuint name GLsizei bufSize GLsizei *length GLchar *label void glGetObjectLabelEXT GLenum type GLuint object GLsizei bufSize GLsizei *length GLchar *label void glGetObjectLabelKHR GLenum identifier GLuint name GLsizei bufSize GLsizei *length GLchar *label void glGetObjectParameterfvARB GLhandleARB obj GLenum pname GLfloat *params void glGetObjectParameterivAPPLE GLenum objectType GLuint name GLenum pname GLint *params void glGetObjectParameterivARB GLhandleARB obj GLenum pname GLint *params void glGetObjectPtrLabel const void *ptr GLsizei bufSize GLsizei *length GLchar *label void glGetObjectPtrLabelKHR const void *ptr GLsizei bufSize GLsizei *length GLchar *label void glGetOcclusionQueryivNV GLuint id GLenum pname GLint *params void glGetOcclusionQueryuivNV GLuint id GLenum pname GLuint *params void glGetPathColorGenfvNV GLenum color GLenum pname GLfloat *value void glGetPathColorGenivNV GLenum color GLenum pname GLint *value void glGetPathCommandsNV GLuint path GLubyte *commands void glGetPathCoordsNV GLuint path GLfloat *coords void glGetPathDashArrayNV GLuint path GLfloat *dashArray GLfloat glGetPathLengthNV GLuint path GLsizei startSegment GLsizei numSegments void glGetPathMetricRangeNV GLbitfield metricQueryMask GLuint firstPathName GLsizei numPaths GLsizei stride GLfloat *metrics void glGetPathMetricsNV GLbitfield metricQueryMask GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLsizei stride GLfloat *metrics void glGetPathParameterfvNV GLuint path GLenum pname GLfloat *value void glGetPathParameterivNV GLuint path GLenum pname GLint *value void glGetPathSpacingNV GLenum pathListMode GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLfloat advanceScale GLfloat kerningScale GLenum transformType GLfloat *returnedSpacing void glGetPathTexGenfvNV GLenum texCoordSet GLenum pname GLfloat *value void glGetPathTexGenivNV GLenum texCoordSet GLenum pname GLint *value void glGetPerfCounterInfoINTEL GLuint queryId GLuint counterId GLuint counterNameLength GLchar *counterName GLuint counterDescLength GLchar *counterDesc GLuint *counterOffset GLuint *counterDataSize GLuint *counterTypeEnum GLuint *counterDataTypeEnum GLuint64 *rawCounterMaxValue void glGetPerfMonitorCounterDataAMD GLuint monitor GLenum pname GLsizei dataSize GLuint *data GLint *bytesWritten void glGetPerfMonitorCounterInfoAMD GLuint group GLuint counter GLenum pname void *data void glGetPerfMonitorCounterStringAMD GLuint group GLuint counter GLsizei bufSize GLsizei *length GLchar *counterString void glGetPerfMonitorCountersAMD GLuint group GLint *numCounters GLint *maxActiveCounters GLsizei counterSize GLuint *counters void glGetPerfMonitorGroupStringAMD GLuint group GLsizei bufSize GLsizei *length GLchar *groupString void glGetPerfMonitorGroupsAMD GLint *numGroups GLsizei groupsSize GLuint *groups void glGetPerfQueryDataINTEL GLuint queryHandle GLuint flags GLsizei dataSize GLvoid *data GLuint *bytesWritten void glGetPerfQueryIdByNameINTEL GLchar *queryName GLuint *queryId void glGetPerfQueryInfoINTEL GLuint queryId GLuint queryNameLength GLchar *queryName GLuint *dataSize GLuint *noCounters GLuint *noInstances GLuint *capsMask void glGetPixelMapfv GLenum map GLfloat *values void glGetPixelMapuiv GLenum map GLuint *values void glGetPixelMapusv GLenum map GLushort *values void glGetPixelMapxv GLenum map GLint size GLfixed *values void glGetPixelTexGenParameterfvSGIS GLenum pname GLfloat *params void glGetPixelTexGenParameterivSGIS GLenum pname GLint *params void glGetPixelTransformParameterfvEXT GLenum target GLenum pname GLfloat *params void glGetPixelTransformParameterivEXT GLenum target GLenum pname GLint *params void glGetPointerIndexedvEXT GLenum target GLuint index void **data void glGetPointeri_vEXT GLenum pname GLuint index void **params void glGetPointerv GLenum pname void **params void glGetPointervEXT GLenum pname void **params void glGetPointervKHR GLenum pname void **params void glGetPolygonStipple GLubyte *mask void glGetProgramBinary GLuint program GLsizei bufSize GLsizei *length GLenum *binaryFormat void *binary void glGetProgramBinaryOES GLuint program GLsizei bufSize GLsizei *length GLenum *binaryFormat void *binary void glGetProgramEnvParameterIivNV GLenum target GLuint index GLint *params void glGetProgramEnvParameterIuivNV GLenum target GLuint index GLuint *params void glGetProgramEnvParameterdvARB GLenum target GLuint index GLdouble *params void glGetProgramEnvParameterfvARB GLenum target GLuint index GLfloat *params void glGetProgramInfoLog GLuint program GLsizei bufSize GLsizei *length GLchar *infoLog void glGetProgramInterfaceiv GLuint program GLenum programInterface GLenum pname GLint *params void glGetProgramLocalParameterIivNV GLenum target GLuint index GLint *params void glGetProgramLocalParameterIuivNV GLenum target GLuint index GLuint *params void glGetProgramLocalParameterdvARB GLenum target GLuint index GLdouble *params void glGetProgramLocalParameterfvARB GLenum target GLuint index GLfloat *params void glGetProgramNamedParameterdvNV GLuint id GLsizei len const GLubyte *name GLdouble *params void glGetProgramNamedParameterfvNV GLuint id GLsizei len const GLubyte *name GLfloat *params void glGetProgramParameterdvNV GLenum target GLuint index GLenum pname GLdouble *params void glGetProgramParameterfvNV GLenum target GLuint index GLenum pname GLfloat *params void glGetProgramPipelineInfoLog GLuint pipeline GLsizei bufSize GLsizei *length GLchar *infoLog void glGetProgramPipelineInfoLogEXT GLuint pipeline GLsizei bufSize GLsizei *length GLchar *infoLog void glGetProgramPipelineiv GLuint pipeline GLenum pname GLint *params void glGetProgramPipelineivEXT GLuint pipeline GLenum pname GLint *params GLuint glGetProgramResourceIndex GLuint program GLenum programInterface const GLchar *name GLint glGetProgramResourceLocation GLuint program GLenum programInterface const GLchar *name GLint glGetProgramResourceLocationIndex GLuint program GLenum programInterface const GLchar *name GLint glGetProgramResourceLocationIndexEXT GLuint program GLenum programInterface const GLchar *name void glGetProgramResourceName GLuint program GLenum programInterface GLuint index GLsizei bufSize GLsizei *length GLchar *name void glGetProgramResourcefvNV GLuint program GLenum programInterface GLuint index GLsizei propCount const GLenum *props GLsizei bufSize GLsizei *length GLfloat *params void glGetProgramResourceiv GLuint program GLenum programInterface GLuint index GLsizei propCount const GLenum *props GLsizei bufSize GLsizei *length GLint *params void glGetProgramStageiv GLuint program GLenum shadertype GLenum pname GLint *values void glGetProgramStringARB GLenum target GLenum pname void *string void glGetProgramStringNV GLuint id GLenum pname GLubyte *program void glGetProgramSubroutineParameteruivNV GLenum target GLuint index GLuint *param void glGetProgramiv GLuint program GLenum pname GLint *params void glGetProgramivARB GLenum target GLenum pname GLint *params void glGetProgramivNV GLuint id GLenum pname GLint *params void glGetQueryBufferObjecti64v GLuint id GLuint buffer GLenum pname GLintptr offset void glGetQueryBufferObjectiv GLuint id GLuint buffer GLenum pname GLintptr offset void glGetQueryBufferObjectui64v GLuint id GLuint buffer GLenum pname GLintptr offset void glGetQueryBufferObjectuiv GLuint id GLuint buffer GLenum pname GLintptr offset void glGetQueryIndexediv GLenum target GLuint index GLenum pname GLint *params void glGetQueryObjecti64v GLuint id GLenum pname GLint64 *params void glGetQueryObjecti64vEXT GLuint id GLenum pname GLint64 *params void glGetQueryObjectiv GLuint id GLenum pname GLint *params void glGetQueryObjectivARB GLuint id GLenum pname GLint *params void glGetQueryObjectivEXT GLuint id GLenum pname GLint *params void glGetQueryObjectui64v GLuint id GLenum pname GLuint64 *params void glGetQueryObjectui64vEXT GLuint id GLenum pname GLuint64 *params void glGetQueryObjectuiv GLuint id GLenum pname GLuint *params void glGetQueryObjectuivARB GLuint id GLenum pname GLuint *params void glGetQueryObjectuivEXT GLuint id GLenum pname GLuint *params void glGetQueryiv GLenum target GLenum pname GLint *params void glGetQueryivARB GLenum target GLenum pname GLint *params void glGetQueryivEXT GLenum target GLenum pname GLint *params void glGetRenderbufferParameteriv GLenum target GLenum pname GLint *params void glGetRenderbufferParameterivEXT GLenum target GLenum pname GLint *params void glGetRenderbufferParameterivOES GLenum target GLenum pname GLint *params void glGetSamplerParameterIiv GLuint sampler GLenum pname GLint *params void glGetSamplerParameterIivEXT GLuint sampler GLenum pname GLint *params void glGetSamplerParameterIivOES GLuint sampler GLenum pname GLint *params void glGetSamplerParameterIuiv GLuint sampler GLenum pname GLuint *params void glGetSamplerParameterIuivEXT GLuint sampler GLenum pname GLuint *params void glGetSamplerParameterIuivOES GLuint sampler GLenum pname GLuint *params void glGetSamplerParameterfv GLuint sampler GLenum pname GLfloat *params void glGetSamplerParameteriv GLuint sampler GLenum pname GLint *params void glGetSeparableFilter GLenum target GLenum format GLenum type void *row void *column void *span void glGetSeparableFilterEXT GLenum target GLenum format GLenum type void *row void *column void *span void glGetShaderInfoLog GLuint shader GLsizei bufSize GLsizei *length GLchar *infoLog void glGetShaderPrecisionFormat GLenum shadertype GLenum precisiontype GLint *range GLint *precision void glGetShaderSource GLuint shader GLsizei bufSize GLsizei *length GLchar *source void glGetShaderSourceARB GLhandleARB obj GLsizei maxLength GLsizei *length GLcharARB *source void glGetShaderiv GLuint shader GLenum pname GLint *params void glGetSharpenTexFuncSGIS GLenum target GLfloat *points GLushort glGetStageIndexNV GLenum shadertype const GLubyte *glGetString GLenum name const GLubyte *glGetStringi GLenum name GLuint index GLuint glGetSubroutineIndex GLuint program GLenum shadertype const GLchar *name GLint glGetSubroutineUniformLocation GLuint program GLenum shadertype const GLchar *name void glGetSynciv GLsync sync GLenum pname GLsizei bufSize GLsizei *length GLint *values void glGetSyncivAPPLE GLsync sync GLenum pname GLsizei bufSize GLsizei *length GLint *values void glGetTexBumpParameterfvATI GLenum pname GLfloat *param void glGetTexBumpParameterivATI GLenum pname GLint *param void glGetTexEnvfv GLenum target GLenum pname GLfloat *params void glGetTexEnviv GLenum target GLenum pname GLint *params void glGetTexEnvxv GLenum target GLenum pname GLfixed *params void glGetTexEnvxvOES GLenum target GLenum pname GLfixed *params void glGetTexFilterFuncSGIS GLenum target GLenum filter GLfloat *weights void glGetTexGendv GLenum coord GLenum pname GLdouble *params void glGetTexGenfv GLenum coord GLenum pname GLfloat *params void glGetTexGenfvOES GLenum coord GLenum pname GLfloat *params void glGetTexGeniv GLenum coord GLenum pname GLint *params void glGetTexGenivOES GLenum coord GLenum pname GLint *params void glGetTexGenxvOES GLenum coord GLenum pname GLfixed *params void glGetTexImage GLenum target GLint level GLenum format GLenum type void *pixels void glGetTexLevelParameterfv GLenum target GLint level GLenum pname GLfloat *params void glGetTexLevelParameteriv GLenum target GLint level GLenum pname GLint *params void glGetTexLevelParameterxvOES GLenum target GLint level GLenum pname GLfixed *params void glGetTexParameterIiv GLenum target GLenum pname GLint *params void glGetTexParameterIivEXT GLenum target GLenum pname GLint *params void glGetTexParameterIivOES GLenum target GLenum pname GLint *params void glGetTexParameterIuiv GLenum target GLenum pname GLuint *params void glGetTexParameterIuivEXT GLenum target GLenum pname GLuint *params void glGetTexParameterIuivOES GLenum target GLenum pname GLuint *params void glGetTexParameterPointervAPPLE GLenum target GLenum pname void **params void glGetTexParameterfv GLenum target GLenum pname GLfloat *params void glGetTexParameteriv GLenum target GLenum pname GLint *params void glGetTexParameterxv GLenum target GLenum pname GLfixed *params void glGetTexParameterxvOES GLenum target GLenum pname GLfixed *params GLuint64 glGetTextureHandleARB GLuint texture GLuint64 glGetTextureHandleNV GLuint texture void glGetTextureImage GLuint texture GLint level GLenum format GLenum type GLsizei bufSize void *pixels void glGetTextureImageEXT GLuint texture GLenum target GLint level GLenum format GLenum type void *pixels void glGetTextureLevelParameterfv GLuint texture GLint level GLenum pname GLfloat *params void glGetTextureLevelParameterfvEXT GLuint texture GLenum target GLint level GLenum pname GLfloat *params void glGetTextureLevelParameteriv GLuint texture GLint level GLenum pname GLint *params void glGetTextureLevelParameterivEXT GLuint texture GLenum target GLint level GLenum pname GLint *params void glGetTextureParameterIiv GLuint texture GLenum pname GLint *params void glGetTextureParameterIivEXT GLuint texture GLenum target GLenum pname GLint *params void glGetTextureParameterIuiv GLuint texture GLenum pname GLuint *params void glGetTextureParameterIuivEXT GLuint texture GLenum target GLenum pname GLuint *params void glGetTextureParameterfv GLuint texture GLenum pname GLfloat *params void glGetTextureParameterfvEXT GLuint texture GLenum target GLenum pname GLfloat *params void glGetTextureParameteriv GLuint texture GLenum pname GLint *params void glGetTextureParameterivEXT GLuint texture GLenum target GLenum pname GLint *params GLuint64 glGetTextureSamplerHandleARB GLuint texture GLuint sampler GLuint64 glGetTextureSamplerHandleNV GLuint texture GLuint sampler void glGetTextureSubImage GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type GLsizei bufSize void *pixels void glGetTrackMatrixivNV GLenum target GLuint address GLenum pname GLint *params void glGetTransformFeedbackVarying GLuint program GLuint index GLsizei bufSize GLsizei *length GLsizei *size GLenum *type GLchar *name void glGetTransformFeedbackVaryingEXT GLuint program GLuint index GLsizei bufSize GLsizei *length GLsizei *size GLenum *type GLchar *name void glGetTransformFeedbackVaryingNV GLuint program GLuint index GLint *location void glGetTransformFeedbacki64_v GLuint xfb GLenum pname GLuint index GLint64 *param void glGetTransformFeedbacki_v GLuint xfb GLenum pname GLuint index GLint *param void glGetTransformFeedbackiv GLuint xfb GLenum pname GLint *param void glGetTranslatedShaderSourceANGLE GLuint shader GLsizei bufsize GLsizei *length GLchar *source GLuint glGetUniformBlockIndex GLuint program const GLchar *uniformBlockName GLint glGetUniformBufferSizeEXT GLuint program GLint location void glGetUniformIndices GLuint program GLsizei uniformCount const GLchar *const*uniformNames GLuint *uniformIndices GLint glGetUniformLocation GLuint program const GLchar *name GLint glGetUniformLocationARB GLhandleARB programObj const GLcharARB *name GLintptr glGetUniformOffsetEXT GLuint program GLint location void glGetUniformSubroutineuiv GLenum shadertype GLint location GLuint *params void glGetUniformdv GLuint program GLint location GLdouble *params void glGetUniformfv GLuint program GLint location GLfloat *params void glGetUniformfvARB GLhandleARB programObj GLint location GLfloat *params void glGetUniformi64vARB GLuint program GLint location GLint64 *params void glGetUniformi64vNV GLuint program GLint location GLint64EXT *params void glGetUniformiv GLuint program GLint location GLint *params void glGetUniformivARB GLhandleARB programObj GLint location GLint *params void glGetUniformui64vARB GLuint program GLint location GLuint64 *params void glGetUniformui64vNV GLuint program GLint location GLuint64EXT *params void glGetUniformuiv GLuint program GLint location GLuint *params void glGetUniformuivEXT GLuint program GLint location GLuint *params void glGetVariantArrayObjectfvATI GLuint id GLenum pname GLfloat *params void glGetVariantArrayObjectivATI GLuint id GLenum pname GLint *params void glGetVariantBooleanvEXT GLuint id GLenum value GLboolean *data void glGetVariantFloatvEXT GLuint id GLenum value GLfloat *data void glGetVariantIntegervEXT GLuint id GLenum value GLint *data void glGetVariantPointervEXT GLuint id GLenum value void **data GLint glGetVaryingLocationNV GLuint program const GLchar *name void glGetVertexArrayIndexed64iv GLuint vaobj GLuint index GLenum pname GLint64 *param void glGetVertexArrayIndexediv GLuint vaobj GLuint index GLenum pname GLint *param void glGetVertexArrayIntegeri_vEXT GLuint vaobj GLuint index GLenum pname GLint *param void glGetVertexArrayIntegervEXT GLuint vaobj GLenum pname GLint *param void glGetVertexArrayPointeri_vEXT GLuint vaobj GLuint index GLenum pname void **param void glGetVertexArrayPointervEXT GLuint vaobj GLenum pname void **param void glGetVertexArrayiv GLuint vaobj GLenum pname GLint *param void glGetVertexAttribArrayObjectfvATI GLuint index GLenum pname GLfloat *params void glGetVertexAttribArrayObjectivATI GLuint index GLenum pname GLint *params void glGetVertexAttribIiv GLuint index GLenum pname GLint *params void glGetVertexAttribIivEXT GLuint index GLenum pname GLint *params void glGetVertexAttribIuiv GLuint index GLenum pname GLuint *params void glGetVertexAttribIuivEXT GLuint index GLenum pname GLuint *params void glGetVertexAttribLdv GLuint index GLenum pname GLdouble *params void glGetVertexAttribLdvEXT GLuint index GLenum pname GLdouble *params void glGetVertexAttribLi64vNV GLuint index GLenum pname GLint64EXT *params void glGetVertexAttribLui64vARB GLuint index GLenum pname GLuint64EXT *params void glGetVertexAttribLui64vNV GLuint index GLenum pname GLuint64EXT *params void glGetVertexAttribPointerv GLuint index GLenum pname void **pointer void glGetVertexAttribPointervARB GLuint index GLenum pname void **pointer void glGetVertexAttribPointervNV GLuint index GLenum pname void **pointer void glGetVertexAttribdv GLuint index GLenum pname GLdouble *params void glGetVertexAttribdvARB GLuint index GLenum pname GLdouble *params void glGetVertexAttribdvNV GLuint index GLenum pname GLdouble *params void glGetVertexAttribfv GLuint index GLenum pname GLfloat *params void glGetVertexAttribfvARB GLuint index GLenum pname GLfloat *params void glGetVertexAttribfvNV GLuint index GLenum pname GLfloat *params void glGetVertexAttribiv GLuint index GLenum pname GLint *params void glGetVertexAttribivARB GLuint index GLenum pname GLint *params void glGetVertexAttribivNV GLuint index GLenum pname GLint *params void glGetVideoCaptureStreamdvNV GLuint video_capture_slot GLuint stream GLenum pname GLdouble *params void glGetVideoCaptureStreamfvNV GLuint video_capture_slot GLuint stream GLenum pname GLfloat *params void glGetVideoCaptureStreamivNV GLuint video_capture_slot GLuint stream GLenum pname GLint *params void glGetVideoCaptureivNV GLuint video_capture_slot GLenum pname GLint *params void glGetVideoi64vNV GLuint video_slot GLenum pname GLint64EXT *params void glGetVideoivNV GLuint video_slot GLenum pname GLint *params void glGetVideoui64vNV GLuint video_slot GLenum pname GLuint64EXT *params void glGetVideouivNV GLuint video_slot GLenum pname GLuint *params void glGetnColorTable GLenum target GLenum format GLenum type GLsizei bufSize void *table void glGetnColorTableARB GLenum target GLenum format GLenum type GLsizei bufSize void *table void glGetnCompressedTexImage GLenum target GLint lod GLsizei bufSize void *pixels void glGetnCompressedTexImageARB GLenum target GLint lod GLsizei bufSize void *img void glGetnConvolutionFilter GLenum target GLenum format GLenum type GLsizei bufSize void *image void glGetnConvolutionFilterARB GLenum target GLenum format GLenum type GLsizei bufSize void *image void glGetnHistogram GLenum target GLboolean reset GLenum format GLenum type GLsizei bufSize void *values void glGetnHistogramARB GLenum target GLboolean reset GLenum format GLenum type GLsizei bufSize void *values void glGetnMapdv GLenum target GLenum query GLsizei bufSize GLdouble *v void glGetnMapdvARB GLenum target GLenum query GLsizei bufSize GLdouble *v void glGetnMapfv GLenum target GLenum query GLsizei bufSize GLfloat *v void glGetnMapfvARB GLenum target GLenum query GLsizei bufSize GLfloat *v void glGetnMapiv GLenum target GLenum query GLsizei bufSize GLint *v void glGetnMapivARB GLenum target GLenum query GLsizei bufSize GLint *v void glGetnMinmax GLenum target GLboolean reset GLenum format GLenum type GLsizei bufSize void *values void glGetnMinmaxARB GLenum target GLboolean reset GLenum format GLenum type GLsizei bufSize void *values void glGetnPixelMapfv GLenum map GLsizei bufSize GLfloat *values void glGetnPixelMapfvARB GLenum map GLsizei bufSize GLfloat *values void glGetnPixelMapuiv GLenum map GLsizei bufSize GLuint *values void glGetnPixelMapuivARB GLenum map GLsizei bufSize GLuint *values void glGetnPixelMapusv GLenum map GLsizei bufSize GLushort *values void glGetnPixelMapusvARB GLenum map GLsizei bufSize GLushort *values void glGetnPolygonStipple GLsizei bufSize GLubyte *pattern void glGetnPolygonStippleARB GLsizei bufSize GLubyte *pattern void glGetnSeparableFilter GLenum target GLenum format GLenum type GLsizei rowBufSize void *row GLsizei columnBufSize void *column void *span void glGetnSeparableFilterARB GLenum target GLenum format GLenum type GLsizei rowBufSize void *row GLsizei columnBufSize void *column void *span void glGetnTexImage GLenum target GLint level GLenum format GLenum type GLsizei bufSize void *pixels void glGetnTexImageARB GLenum target GLint level GLenum format GLenum type GLsizei bufSize void *img void glGetnUniformdv GLuint program GLint location GLsizei bufSize GLdouble *params void glGetnUniformdvARB GLuint program GLint location GLsizei bufSize GLdouble *params void glGetnUniformfv GLuint program GLint location GLsizei bufSize GLfloat *params void glGetnUniformfvARB GLuint program GLint location GLsizei bufSize GLfloat *params void glGetnUniformfvEXT GLuint program GLint location GLsizei bufSize GLfloat *params void glGetnUniformfvKHR GLuint program GLint location GLsizei bufSize GLfloat *params void glGetnUniformi64vARB GLuint program GLint location GLsizei bufSize GLint64 *params void glGetnUniformiv GLuint program GLint location GLsizei bufSize GLint *params void glGetnUniformivARB GLuint program GLint location GLsizei bufSize GLint *params void glGetnUniformivEXT GLuint program GLint location GLsizei bufSize GLint *params void glGetnUniformivKHR GLuint program GLint location GLsizei bufSize GLint *params void glGetnUniformui64vARB GLuint program GLint location GLsizei bufSize GLuint64 *params void glGetnUniformuiv GLuint program GLint location GLsizei bufSize GLuint *params void glGetnUniformuivARB GLuint program GLint location GLsizei bufSize GLuint *params void glGetnUniformuivKHR GLuint program GLint location GLsizei bufSize GLuint *params void glGlobalAlphaFactorbSUN GLbyte factor void glGlobalAlphaFactordSUN GLdouble factor void glGlobalAlphaFactorfSUN GLfloat factor void glGlobalAlphaFactoriSUN GLint factor void glGlobalAlphaFactorsSUN GLshort factor void glGlobalAlphaFactorubSUN GLubyte factor void glGlobalAlphaFactoruiSUN GLuint factor void glGlobalAlphaFactorusSUN GLushort factor void glHint GLenum target GLenum mode void glHintPGI GLenum target GLint mode void glHistogram GLenum target GLsizei width GLenum internalformat GLboolean sink void glHistogramEXT GLenum target GLsizei width GLenum internalformat GLboolean sink void glIglooInterfaceSGIX GLenum pname const void *params void glImageTransformParameterfHP GLenum target GLenum pname GLfloat param void glImageTransformParameterfvHP GLenum target GLenum pname const GLfloat *params void glImageTransformParameteriHP GLenum target GLenum pname GLint param void glImageTransformParameterivHP GLenum target GLenum pname const GLint *params GLsync glImportSyncEXT GLenum external_sync_type GLintptr external_sync GLbitfield flags void glIndexFormatNV GLenum type GLsizei stride void glIndexFuncEXT GLenum func GLclampf ref void glIndexMask GLuint mask void glIndexMaterialEXT GLenum face GLenum mode void glIndexPointer GLenum type GLsizei stride const void *pointer void glIndexPointerEXT GLenum type GLsizei stride GLsizei count const void *pointer void glIndexPointerListIBM GLenum type GLint stride const void **pointer GLint ptrstride void glIndexd GLdouble c void glIndexdv const GLdouble *c void glIndexf GLfloat c void glIndexfv const GLfloat *c void glIndexi GLint c void glIndexiv const GLint *c void glIndexs GLshort c void glIndexsv const GLshort *c void glIndexub GLubyte c void glIndexubv const GLubyte *c void glIndexxOES GLfixed component void glIndexxvOES const GLfixed *component void glInitNames void glInsertComponentEXT GLuint res GLuint src GLuint num void glInsertEventMarkerEXT GLsizei length const GLchar *marker void glInstrumentsBufferSGIX GLsizei size GLint *buffer void glInterleavedArrays GLenum format GLsizei stride const void *pointer void glInterpolatePathsNV GLuint resultPath GLuint pathA GLuint pathB GLfloat weight void glInvalidateBufferData GLuint buffer void glInvalidateBufferSubData GLuint buffer GLintptr offset GLsizeiptr length void glInvalidateFramebuffer GLenum target GLsizei numAttachments const GLenum *attachments void glInvalidateNamedFramebufferData GLuint framebuffer GLsizei numAttachments const GLenum *attachments void glInvalidateNamedFramebufferSubData GLuint framebuffer GLsizei numAttachments const GLenum *attachments GLint x GLint y GLsizei width GLsizei height void glInvalidateSubFramebuffer GLenum target GLsizei numAttachments const GLenum *attachments GLint x GLint y GLsizei width GLsizei height void glInvalidateTexImage GLuint texture GLint level void glInvalidateTexSubImage GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLboolean glIsAsyncMarkerSGIX GLuint marker GLboolean glIsBuffer GLuint buffer GLboolean glIsBufferARB GLuint buffer GLboolean glIsBufferResidentNV GLenum target GLboolean glIsCommandListNV GLuint list GLboolean glIsEnabled GLenum cap GLboolean glIsEnabledIndexedEXT GLenum target GLuint index GLboolean glIsEnabledi GLenum target GLuint index GLboolean glIsEnablediEXT GLenum target GLuint index GLboolean glIsEnablediNV GLenum target GLuint index GLboolean glIsEnablediOES GLenum target GLuint index GLboolean glIsFenceAPPLE GLuint fence GLboolean glIsFenceNV GLuint fence GLboolean glIsFramebuffer GLuint framebuffer GLboolean glIsFramebufferEXT GLuint framebuffer GLboolean glIsFramebufferOES GLuint framebuffer GLboolean glIsImageHandleResidentARB GLuint64 handle GLboolean glIsImageHandleResidentNV GLuint64 handle GLboolean glIsList GLuint list GLboolean glIsNameAMD GLenum identifier GLuint name GLboolean glIsNamedBufferResidentNV GLuint buffer GLboolean glIsNamedStringARB GLint namelen const GLchar *name GLboolean glIsObjectBufferATI GLuint buffer GLboolean glIsOcclusionQueryNV GLuint id GLboolean glIsPathNV GLuint path GLboolean glIsPointInFillPathNV GLuint path GLuint mask GLfloat x GLfloat y GLboolean glIsPointInStrokePathNV GLuint path GLfloat x GLfloat y GLboolean glIsProgram GLuint program GLboolean glIsProgramARB GLuint program GLboolean glIsProgramNV GLuint id GLboolean glIsProgramPipeline GLuint pipeline GLboolean glIsProgramPipelineEXT GLuint pipeline GLboolean glIsQuery GLuint id GLboolean glIsQueryARB GLuint id GLboolean glIsQueryEXT GLuint id GLboolean glIsRenderbuffer GLuint renderbuffer GLboolean glIsRenderbufferEXT GLuint renderbuffer GLboolean glIsRenderbufferOES GLuint renderbuffer GLboolean glIsSampler GLuint sampler GLboolean glIsShader GLuint shader GLboolean glIsStateNV GLuint state GLboolean glIsSync GLsync sync GLboolean glIsSyncAPPLE GLsync sync GLboolean glIsTexture GLuint texture GLboolean glIsTextureEXT GLuint texture GLboolean glIsTextureHandleResidentARB GLuint64 handle GLboolean glIsTextureHandleResidentNV GLuint64 handle GLboolean glIsTransformFeedback GLuint id GLboolean glIsTransformFeedbackNV GLuint id GLboolean glIsVariantEnabledEXT GLuint id GLenum cap GLboolean glIsVertexArray GLuint array GLboolean glIsVertexArrayAPPLE GLuint array GLboolean glIsVertexArrayOES GLuint array GLboolean glIsVertexAttribEnabledAPPLE GLuint index GLenum pname void glLabelObjectEXT GLenum type GLuint object GLsizei length const GLchar *label void glLightEnviSGIX GLenum pname GLint param void glLightModelf GLenum pname GLfloat param void glLightModelfv GLenum pname const GLfloat *params void glLightModeli GLenum pname GLint param void glLightModeliv GLenum pname const GLint *params void glLightModelx GLenum pname GLfixed param void glLightModelxOES GLenum pname GLfixed param void glLightModelxv GLenum pname const GLfixed *param void glLightModelxvOES GLenum pname const GLfixed *param void glLightf GLenum light GLenum pname GLfloat param void glLightfv GLenum light GLenum pname const GLfloat *params void glLighti GLenum light GLenum pname GLint param void glLightiv GLenum light GLenum pname const GLint *params void glLightx GLenum light GLenum pname GLfixed param void glLightxOES GLenum light GLenum pname GLfixed param void glLightxv GLenum light GLenum pname const GLfixed *params void glLightxvOES GLenum light GLenum pname const GLfixed *params void glLineStipple GLint factor GLushort pattern void glLineWidth GLfloat width void glLineWidthx GLfixed width void glLineWidthxOES GLfixed width void glLinkProgram GLuint program void glLinkProgramARB GLhandleARB programObj void glListBase GLuint base void glListDrawCommandsStatesClientNV GLuint list GLuint segment const void **indirects const GLsizei *sizes const GLuint *states const GLuint *fbos GLuint count void glListParameterfSGIX GLuint list GLenum pname GLfloat param void glListParameterfvSGIX GLuint list GLenum pname const GLfloat *params void glListParameteriSGIX GLuint list GLenum pname GLint param void glListParameterivSGIX GLuint list GLenum pname const GLint *params void glLoadIdentity void glLoadIdentityDeformationMapSGIX GLbitfield mask void glLoadMatrixd const GLdouble *m void glLoadMatrixf const GLfloat *m void glLoadMatrixx const GLfixed *m void glLoadMatrixxOES const GLfixed *m void glLoadName GLuint name void glLoadPaletteFromModelViewMatrixOES void glLoadProgramNV GLenum target GLuint id GLsizei len const GLubyte *program void glLoadTransposeMatrixd const GLdouble *m void glLoadTransposeMatrixdARB const GLdouble *m void glLoadTransposeMatrixf const GLfloat *m void glLoadTransposeMatrixfARB const GLfloat *m void glLoadTransposeMatrixxOES const GLfixed *m void glLockArraysEXT GLint first GLsizei count void glLogicOp GLenum opcode void glMakeBufferNonResidentNV GLenum target void glMakeBufferResidentNV GLenum target GLenum access void glMakeImageHandleNonResidentARB GLuint64 handle void glMakeImageHandleNonResidentNV GLuint64 handle void glMakeImageHandleResidentARB GLuint64 handle GLenum access void glMakeImageHandleResidentNV GLuint64 handle GLenum access void glMakeNamedBufferNonResidentNV GLuint buffer void glMakeNamedBufferResidentNV GLuint buffer GLenum access void glMakeTextureHandleNonResidentARB GLuint64 handle void glMakeTextureHandleNonResidentNV GLuint64 handle void glMakeTextureHandleResidentARB GLuint64 handle void glMakeTextureHandleResidentNV GLuint64 handle void glMap1d GLenum target GLdouble u1 GLdouble u2 GLint stride GLint order const GLdouble *points void glMap1f GLenum target GLfloat u1 GLfloat u2 GLint stride GLint order const GLfloat *points void glMap1xOES GLenum target GLfixed u1 GLfixed u2 GLint stride GLint order GLfixed points void glMap2d GLenum target GLdouble u1 GLdouble u2 GLint ustride GLint uorder GLdouble v1 GLdouble v2 GLint vstride GLint vorder const GLdouble *points void glMap2f GLenum target GLfloat u1 GLfloat u2 GLint ustride GLint uorder GLfloat v1 GLfloat v2 GLint vstride GLint vorder const GLfloat *points void glMap2xOES GLenum target GLfixed u1 GLfixed u2 GLint ustride GLint uorder GLfixed v1 GLfixed v2 GLint vstride GLint vorder GLfixed points void *glMapBuffer GLenum target GLenum access void *glMapBufferARB GLenum target GLenum access void *glMapBufferOES GLenum target GLenum access void *glMapBufferRange GLenum target GLintptr offset GLsizeiptr length GLbitfield access void *glMapBufferRangeEXT GLenum target GLintptr offset GLsizeiptr length GLbitfield access void glMapControlPointsNV GLenum target GLuint index GLenum type GLsizei ustride GLsizei vstride GLint uorder GLint vorder GLboolean packed const void *points void glMapGrid1d GLint un GLdouble u1 GLdouble u2 void glMapGrid1f GLint un GLfloat u1 GLfloat u2 void glMapGrid1xOES GLint n GLfixed u1 GLfixed u2 void glMapGrid2d GLint un GLdouble u1 GLdouble u2 GLint vn GLdouble v1 GLdouble v2 void glMapGrid2f GLint un GLfloat u1 GLfloat u2 GLint vn GLfloat v1 GLfloat v2 void glMapGrid2xOES GLint n GLfixed u1 GLfixed u2 GLfixed v1 GLfixed v2 void *glMapNamedBuffer GLuint buffer GLenum access void *glMapNamedBufferEXT GLuint buffer GLenum access void *glMapNamedBufferRange GLuint buffer GLintptr offset GLsizeiptr length GLbitfield access void *glMapNamedBufferRangeEXT GLuint buffer GLintptr offset GLsizeiptr length GLbitfield access void *glMapObjectBufferATI GLuint buffer void glMapParameterfvNV GLenum target GLenum pname const GLfloat *params void glMapParameterivNV GLenum target GLenum pname const GLint *params void *glMapTexture2DINTEL GLuint texture GLint level GLbitfield access GLint *stride GLenum *layout void glMapVertexAttrib1dAPPLE GLuint index GLuint size GLdouble u1 GLdouble u2 GLint stride GLint order const GLdouble *points void glMapVertexAttrib1fAPPLE GLuint index GLuint size GLfloat u1 GLfloat u2 GLint stride GLint order const GLfloat *points void glMapVertexAttrib2dAPPLE GLuint index GLuint size GLdouble u1 GLdouble u2 GLint ustride GLint uorder GLdouble v1 GLdouble v2 GLint vstride GLint vorder const GLdouble *points void glMapVertexAttrib2fAPPLE GLuint index GLuint size GLfloat u1 GLfloat u2 GLint ustride GLint uorder GLfloat v1 GLfloat v2 GLint vstride GLint vorder const GLfloat *points void glMaterialf GLenum face GLenum pname GLfloat param void glMaterialfv GLenum face GLenum pname const GLfloat *params void glMateriali GLenum face GLenum pname GLint param void glMaterialiv GLenum face GLenum pname const GLint *params void glMaterialx GLenum face GLenum pname GLfixed param void glMaterialxOES GLenum face GLenum pname GLfixed param void glMaterialxv GLenum face GLenum pname const GLfixed *param void glMaterialxvOES GLenum face GLenum pname const GLfixed *param void glMatrixFrustumEXT GLenum mode GLdouble left GLdouble right GLdouble bottom GLdouble top GLdouble zNear GLdouble zFar void glMatrixIndexPointerARB GLint size GLenum type GLsizei stride const void *pointer void glMatrixIndexPointerOES GLint size GLenum type GLsizei stride const void *pointer void glMatrixIndexubvARB GLint size const GLubyte *indices void glMatrixIndexuivARB GLint size const GLuint *indices void glMatrixIndexusvARB GLint size const GLushort *indices void glMatrixLoad3x2fNV GLenum matrixMode const GLfloat *m void glMatrixLoad3x3fNV GLenum matrixMode const GLfloat *m void glMatrixLoadIdentityEXT GLenum mode void glMatrixLoadTranspose3x3fNV GLenum matrixMode const GLfloat *m void glMatrixLoadTransposedEXT GLenum mode const GLdouble *m void glMatrixLoadTransposefEXT GLenum mode const GLfloat *m void glMatrixLoaddEXT GLenum mode const GLdouble *m void glMatrixLoadfEXT GLenum mode const GLfloat *m void glMatrixMode GLenum mode void glMatrixMult3x2fNV GLenum matrixMode const GLfloat *m void glMatrixMult3x3fNV GLenum matrixMode const GLfloat *m void glMatrixMultTranspose3x3fNV GLenum matrixMode const GLfloat *m void glMatrixMultTransposedEXT GLenum mode const GLdouble *m void glMatrixMultTransposefEXT GLenum mode const GLfloat *m void glMatrixMultdEXT GLenum mode const GLdouble *m void glMatrixMultfEXT GLenum mode const GLfloat *m void glMatrixOrthoEXT GLenum mode GLdouble left GLdouble right GLdouble bottom GLdouble top GLdouble zNear GLdouble zFar void glMatrixPopEXT GLenum mode void glMatrixPushEXT GLenum mode void glMatrixRotatedEXT GLenum mode GLdouble angle GLdouble x GLdouble y GLdouble z void glMatrixRotatefEXT GLenum mode GLfloat angle GLfloat x GLfloat y GLfloat z void glMatrixScaledEXT GLenum mode GLdouble x GLdouble y GLdouble z void glMatrixScalefEXT GLenum mode GLfloat x GLfloat y GLfloat z void glMatrixTranslatedEXT GLenum mode GLdouble x GLdouble y GLdouble z void glMatrixTranslatefEXT GLenum mode GLfloat x GLfloat y GLfloat z void glMaxShaderCompilerThreadsARB GLuint count void glMemoryBarrier GLbitfield barriers void glMemoryBarrierByRegion GLbitfield barriers void glMemoryBarrierEXT GLbitfield barriers void glMinSampleShading GLfloat value void glMinSampleShadingARB GLfloat value void glMinSampleShadingOES GLfloat value void glMinmax GLenum target GLenum internalformat GLboolean sink void glMinmaxEXT GLenum target GLenum internalformat GLboolean sink void glMultMatrixd const GLdouble *m void glMultMatrixf const GLfloat *m void glMultMatrixx const GLfixed *m void glMultMatrixxOES const GLfixed *m void glMultTransposeMatrixd const GLdouble *m void glMultTransposeMatrixdARB const GLdouble *m void glMultTransposeMatrixf const GLfloat *m void glMultTransposeMatrixfARB const GLfloat *m void glMultTransposeMatrixxOES const GLfixed *m void glMultiDrawArrays GLenum mode const GLint *first const GLsizei *count GLsizei drawcount void glMultiDrawArraysEXT GLenum mode const GLint *first const GLsizei *count GLsizei primcount void glMultiDrawArraysIndirect GLenum mode const void *indirect GLsizei drawcount GLsizei stride void glMultiDrawArraysIndirectAMD GLenum mode const void *indirect GLsizei primcount GLsizei stride void glMultiDrawArraysIndirectBindlessCountNV GLenum mode const void *indirect GLsizei drawCount GLsizei maxDrawCount GLsizei stride GLint vertexBufferCount void glMultiDrawArraysIndirectBindlessNV GLenum mode const void *indirect GLsizei drawCount GLsizei stride GLint vertexBufferCount void glMultiDrawArraysIndirectCountARB GLenum mode GLintptr indirect GLintptr drawcount GLsizei maxdrawcount GLsizei stride void glMultiDrawArraysIndirectEXT GLenum mode const void *indirect GLsizei drawcount GLsizei stride void glMultiDrawElementArrayAPPLE GLenum mode const GLint *first const GLsizei *count GLsizei primcount void glMultiDrawElements GLenum mode const GLsizei *count GLenum type const void *const*indices GLsizei drawcount void glMultiDrawElementsBaseVertex GLenum mode const GLsizei *count GLenum type const void *const*indices GLsizei drawcount const GLint *basevertex void glMultiDrawElementsBaseVertexEXT GLenum mode const GLsizei *count GLenum type const void *const*indices GLsizei primcount const GLint *basevertex void glMultiDrawElementsBaseVertexOES GLenum mode const GLsizei *count GLenum type const void *const*indices GLsizei primcount const GLint *basevertex void glMultiDrawElementsEXT GLenum mode const GLsizei *count GLenum type const void *const*indices GLsizei primcount void glMultiDrawElementsIndirect GLenum mode GLenum type const void *indirect GLsizei drawcount GLsizei stride void glMultiDrawElementsIndirectAMD GLenum mode GLenum type const void *indirect GLsizei primcount GLsizei stride void glMultiDrawElementsIndirectBindlessCountNV GLenum mode GLenum type const void *indirect GLsizei drawCount GLsizei maxDrawCount GLsizei stride GLint vertexBufferCount void glMultiDrawElementsIndirectBindlessNV GLenum mode GLenum type const void *indirect GLsizei drawCount GLsizei stride GLint vertexBufferCount void glMultiDrawElementsIndirectCountARB GLenum mode GLenum type GLintptr indirect GLintptr drawcount GLsizei maxdrawcount GLsizei stride void glMultiDrawElementsIndirectEXT GLenum mode GLenum type const void *indirect GLsizei drawcount GLsizei stride void glMultiDrawRangeElementArrayAPPLE GLenum mode GLuint start GLuint end const GLint *first const GLsizei *count GLsizei primcount void glMultiModeDrawArraysIBM const GLenum *mode const GLint *first const GLsizei *count GLsizei primcount GLint modestride void glMultiModeDrawElementsIBM const GLenum *mode const GLsizei *count GLenum type const void *const*indices GLsizei primcount GLint modestride void glMultiTexBufferEXT GLenum texunit GLenum target GLenum internalformat GLuint buffer void glMultiTexCoord1bOES GLenum texture GLbyte s void glMultiTexCoord1bvOES GLenum texture const GLbyte *coords void glMultiTexCoord1d GLenum target GLdouble s void glMultiTexCoord1dARB GLenum target GLdouble s void glMultiTexCoord1dv GLenum target const GLdouble *v void glMultiTexCoord1dvARB GLenum target const GLdouble *v void glMultiTexCoord1f GLenum target GLfloat s void glMultiTexCoord1fARB GLenum target GLfloat s void glMultiTexCoord1fv GLenum target const GLfloat *v void glMultiTexCoord1fvARB GLenum target const GLfloat *v void glMultiTexCoord1hNV GLenum target GLhalfNV s void glMultiTexCoord1hvNV GLenum target const GLhalfNV *v void glMultiTexCoord1i GLenum target GLint s void glMultiTexCoord1iARB GLenum target GLint s void glMultiTexCoord1iv GLenum target const GLint *v void glMultiTexCoord1ivARB GLenum target const GLint *v void glMultiTexCoord1s GLenum target GLshort s void glMultiTexCoord1sARB GLenum target GLshort s void glMultiTexCoord1sv GLenum target const GLshort *v void glMultiTexCoord1svARB GLenum target const GLshort *v void glMultiTexCoord1xOES GLenum texture GLfixed s void glMultiTexCoord1xvOES GLenum texture const GLfixed *coords void glMultiTexCoord2bOES GLenum texture GLbyte s GLbyte t void glMultiTexCoord2bvOES GLenum texture const GLbyte *coords void glMultiTexCoord2d GLenum target GLdouble s GLdouble t void glMultiTexCoord2dARB GLenum target GLdouble s GLdouble t void glMultiTexCoord2dv GLenum target const GLdouble *v void glMultiTexCoord2dvARB GLenum target const GLdouble *v void glMultiTexCoord2f GLenum target GLfloat s GLfloat t void glMultiTexCoord2fARB GLenum target GLfloat s GLfloat t void glMultiTexCoord2fv GLenum target const GLfloat *v void glMultiTexCoord2fvARB GLenum target const GLfloat *v void glMultiTexCoord2hNV GLenum target GLhalfNV s GLhalfNV t void glMultiTexCoord2hvNV GLenum target const GLhalfNV *v void glMultiTexCoord2i GLenum target GLint s GLint t void glMultiTexCoord2iARB GLenum target GLint s GLint t void glMultiTexCoord2iv GLenum target const GLint *v void glMultiTexCoord2ivARB GLenum target const GLint *v void glMultiTexCoord2s GLenum target GLshort s GLshort t void glMultiTexCoord2sARB GLenum target GLshort s GLshort t void glMultiTexCoord2sv GLenum target const GLshort *v void glMultiTexCoord2svARB GLenum target const GLshort *v void glMultiTexCoord2xOES GLenum texture GLfixed s GLfixed t void glMultiTexCoord2xvOES GLenum texture const GLfixed *coords void glMultiTexCoord3bOES GLenum texture GLbyte s GLbyte t GLbyte r void glMultiTexCoord3bvOES GLenum texture const GLbyte *coords void glMultiTexCoord3d GLenum target GLdouble s GLdouble t GLdouble r void glMultiTexCoord3dARB GLenum target GLdouble s GLdouble t GLdouble r void glMultiTexCoord3dv GLenum target const GLdouble *v void glMultiTexCoord3dvARB GLenum target const GLdouble *v void glMultiTexCoord3f GLenum target GLfloat s GLfloat t GLfloat r void glMultiTexCoord3fARB GLenum target GLfloat s GLfloat t GLfloat r void glMultiTexCoord3fv GLenum target const GLfloat *v void glMultiTexCoord3fvARB GLenum target const GLfloat *v void glMultiTexCoord3hNV GLenum target GLhalfNV s GLhalfNV t GLhalfNV r void glMultiTexCoord3hvNV GLenum target const GLhalfNV *v void glMultiTexCoord3i GLenum target GLint s GLint t GLint r void glMultiTexCoord3iARB GLenum target GLint s GLint t GLint r void glMultiTexCoord3iv GLenum target const GLint *v void glMultiTexCoord3ivARB GLenum target const GLint *v void glMultiTexCoord3s GLenum target GLshort s GLshort t GLshort r void glMultiTexCoord3sARB GLenum target GLshort s GLshort t GLshort r void glMultiTexCoord3sv GLenum target const GLshort *v void glMultiTexCoord3svARB GLenum target const GLshort *v void glMultiTexCoord3xOES GLenum texture GLfixed s GLfixed t GLfixed r void glMultiTexCoord3xvOES GLenum texture const GLfixed *coords void glMultiTexCoord4bOES GLenum texture GLbyte s GLbyte t GLbyte r GLbyte q void glMultiTexCoord4bvOES GLenum texture const GLbyte *coords void glMultiTexCoord4d GLenum target GLdouble s GLdouble t GLdouble r GLdouble q void glMultiTexCoord4dARB GLenum target GLdouble s GLdouble t GLdouble r GLdouble q void glMultiTexCoord4dv GLenum target const GLdouble *v void glMultiTexCoord4dvARB GLenum target const GLdouble *v void glMultiTexCoord4f GLenum target GLfloat s GLfloat t GLfloat r GLfloat q void glMultiTexCoord4fARB GLenum target GLfloat s GLfloat t GLfloat r GLfloat q void glMultiTexCoord4fv GLenum target const GLfloat *v void glMultiTexCoord4fvARB GLenum target const GLfloat *v void glMultiTexCoord4hNV GLenum target GLhalfNV s GLhalfNV t GLhalfNV r GLhalfNV q void glMultiTexCoord4hvNV GLenum target const GLhalfNV *v void glMultiTexCoord4i GLenum target GLint s GLint t GLint r GLint q void glMultiTexCoord4iARB GLenum target GLint s GLint t GLint r GLint q void glMultiTexCoord4iv GLenum target const GLint *v void glMultiTexCoord4ivARB GLenum target const GLint *v void glMultiTexCoord4s GLenum target GLshort s GLshort t GLshort r GLshort q void glMultiTexCoord4sARB GLenum target GLshort s GLshort t GLshort r GLshort q void glMultiTexCoord4sv GLenum target const GLshort *v void glMultiTexCoord4svARB GLenum target const GLshort *v void glMultiTexCoord4x GLenum texture GLfixed s GLfixed t GLfixed r GLfixed q void glMultiTexCoord4xOES GLenum texture GLfixed s GLfixed t GLfixed r GLfixed q void glMultiTexCoord4xvOES GLenum texture const GLfixed *coords void glMultiTexCoordP1ui GLenum texture GLenum type GLuint coords void glMultiTexCoordP1uiv GLenum texture GLenum type const GLuint *coords void glMultiTexCoordP2ui GLenum texture GLenum type GLuint coords void glMultiTexCoordP2uiv GLenum texture GLenum type const GLuint *coords void glMultiTexCoordP3ui GLenum texture GLenum type GLuint coords void glMultiTexCoordP3uiv GLenum texture GLenum type const GLuint *coords void glMultiTexCoordP4ui GLenum texture GLenum type GLuint coords void glMultiTexCoordP4uiv GLenum texture GLenum type const GLuint *coords void glMultiTexCoordPointerEXT GLenum texunit GLint size GLenum type GLsizei stride const void *pointer void glMultiTexEnvfEXT GLenum texunit GLenum target GLenum pname GLfloat param void glMultiTexEnvfvEXT GLenum texunit GLenum target GLenum pname const GLfloat *params void glMultiTexEnviEXT GLenum texunit GLenum target GLenum pname GLint param void glMultiTexEnvivEXT GLenum texunit GLenum target GLenum pname const GLint *params void glMultiTexGendEXT GLenum texunit GLenum coord GLenum pname GLdouble param void glMultiTexGendvEXT GLenum texunit GLenum coord GLenum pname const GLdouble *params void glMultiTexGenfEXT GLenum texunit GLenum coord GLenum pname GLfloat param void glMultiTexGenfvEXT GLenum texunit GLenum coord GLenum pname const GLfloat *params void glMultiTexGeniEXT GLenum texunit GLenum coord GLenum pname GLint param void glMultiTexGenivEXT GLenum texunit GLenum coord GLenum pname const GLint *params void glMultiTexImage1DEXT GLenum texunit GLenum target GLint level GLint internalformat GLsizei width GLint border GLenum format GLenum type const void *pixels void glMultiTexImage2DEXT GLenum texunit GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLint border GLenum format GLenum type const void *pixels void glMultiTexImage3DEXT GLenum texunit GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLsizei depth GLint border GLenum format GLenum type const void *pixels void glMultiTexParameterIivEXT GLenum texunit GLenum target GLenum pname const GLint *params void glMultiTexParameterIuivEXT GLenum texunit GLenum target GLenum pname const GLuint *params void glMultiTexParameterfEXT GLenum texunit GLenum target GLenum pname GLfloat param void glMultiTexParameterfvEXT GLenum texunit GLenum target GLenum pname const GLfloat *params void glMultiTexParameteriEXT GLenum texunit GLenum target GLenum pname GLint param void glMultiTexParameterivEXT GLenum texunit GLenum target GLenum pname const GLint *params void glMultiTexRenderbufferEXT GLenum texunit GLenum target GLuint renderbuffer void glMultiTexSubImage1DEXT GLenum texunit GLenum target GLint level GLint xoffset GLsizei width GLenum format GLenum type const void *pixels void glMultiTexSubImage2DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glMultiTexSubImage3DEXT GLenum texunit GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glNamedBufferData GLuint buffer GLsizeiptr size const void *data GLenum usage void glNamedBufferDataEXT GLuint buffer GLsizeiptr size const void *data GLenum usage void glNamedBufferPageCommitmentARB GLuint buffer GLintptr offset GLsizeiptr size GLboolean commit void glNamedBufferPageCommitmentEXT GLuint buffer GLintptr offset GLsizeiptr size GLboolean commit void glNamedBufferStorage GLuint buffer GLsizeiptr size const void *data GLbitfield flags void glNamedBufferStorageEXT GLuint buffer GLsizeiptr size const void *data GLbitfield flags void glNamedBufferSubData GLuint buffer GLintptr offset GLsizeiptr size const void *data void glNamedBufferSubDataEXT GLuint buffer GLintptr offset GLsizeiptr size const void *data void glNamedCopyBufferSubDataEXT GLuint readBuffer GLuint writeBuffer GLintptr readOffset GLintptr writeOffset GLsizeiptr size void glNamedFramebufferDrawBuffer GLuint framebuffer GLenum buf void glNamedFramebufferDrawBuffers GLuint framebuffer GLsizei n const GLenum *bufs void glNamedFramebufferParameteri GLuint framebuffer GLenum pname GLint param void glNamedFramebufferParameteriEXT GLuint framebuffer GLenum pname GLint param void glNamedFramebufferReadBuffer GLuint framebuffer GLenum src void glNamedFramebufferRenderbuffer GLuint framebuffer GLenum attachment GLenum renderbuffertarget GLuint renderbuffer void glNamedFramebufferRenderbufferEXT GLuint framebuffer GLenum attachment GLenum renderbuffertarget GLuint renderbuffer void glNamedFramebufferSampleLocationsfvARB GLuint framebuffer GLuint start GLsizei count const GLfloat *v void glNamedFramebufferSampleLocationsfvNV GLuint framebuffer GLuint start GLsizei count const GLfloat *v void glNamedFramebufferTexture GLuint framebuffer GLenum attachment GLuint texture GLint level void glNamedFramebufferTexture1DEXT GLuint framebuffer GLenum attachment GLenum textarget GLuint texture GLint level void glNamedFramebufferTexture2DEXT GLuint framebuffer GLenum attachment GLenum textarget GLuint texture GLint level void glNamedFramebufferTexture3DEXT GLuint framebuffer GLenum attachment GLenum textarget GLuint texture GLint level GLint zoffset void glNamedFramebufferTextureEXT GLuint framebuffer GLenum attachment GLuint texture GLint level void glNamedFramebufferTextureFaceEXT GLuint framebuffer GLenum attachment GLuint texture GLint level GLenum face void glNamedFramebufferTextureLayer GLuint framebuffer GLenum attachment GLuint texture GLint level GLint layer void glNamedFramebufferTextureLayerEXT GLuint framebuffer GLenum attachment GLuint texture GLint level GLint layer void glNamedProgramLocalParameter4dEXT GLuint program GLenum target GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glNamedProgramLocalParameter4dvEXT GLuint program GLenum target GLuint index const GLdouble *params void glNamedProgramLocalParameter4fEXT GLuint program GLenum target GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glNamedProgramLocalParameter4fvEXT GLuint program GLenum target GLuint index const GLfloat *params void glNamedProgramLocalParameterI4iEXT GLuint program GLenum target GLuint index GLint x GLint y GLint z GLint w void glNamedProgramLocalParameterI4ivEXT GLuint program GLenum target GLuint index const GLint *params void glNamedProgramLocalParameterI4uiEXT GLuint program GLenum target GLuint index GLuint x GLuint y GLuint z GLuint w void glNamedProgramLocalParameterI4uivEXT GLuint program GLenum target GLuint index const GLuint *params void glNamedProgramLocalParameters4fvEXT GLuint program GLenum target GLuint index GLsizei count const GLfloat *params void glNamedProgramLocalParametersI4ivEXT GLuint program GLenum target GLuint index GLsizei count const GLint *params void glNamedProgramLocalParametersI4uivEXT GLuint program GLenum target GLuint index GLsizei count const GLuint *params void glNamedProgramStringEXT GLuint program GLenum target GLenum format GLsizei len const void *string void glNamedRenderbufferStorage GLuint renderbuffer GLenum internalformat GLsizei width GLsizei height void glNamedRenderbufferStorageEXT GLuint renderbuffer GLenum internalformat GLsizei width GLsizei height void glNamedRenderbufferStorageMultisample GLuint renderbuffer GLsizei samples GLenum internalformat GLsizei width GLsizei height void glNamedRenderbufferStorageMultisampleCoverageEXT GLuint renderbuffer GLsizei coverageSamples GLsizei colorSamples GLenum internalformat GLsizei width GLsizei height void glNamedRenderbufferStorageMultisampleEXT GLuint renderbuffer GLsizei samples GLenum internalformat GLsizei width GLsizei height void glNamedStringARB GLenum type GLint namelen const GLchar *name GLint stringlen const GLchar *string void glNewList GLuint list GLenum mode GLuint glNewObjectBufferATI GLsizei size const void *pointer GLenum usage void glNormal3b GLbyte nx GLbyte ny GLbyte nz void glNormal3bv const GLbyte *v void glNormal3d GLdouble nx GLdouble ny GLdouble nz void glNormal3dv const GLdouble *v void glNormal3f GLfloat nx GLfloat ny GLfloat nz void glNormal3fVertex3fSUN GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glNormal3fVertex3fvSUN const GLfloat *n const GLfloat *v void glNormal3fv const GLfloat *v void glNormal3hNV GLhalfNV nx GLhalfNV ny GLhalfNV nz void glNormal3hvNV const GLhalfNV *v void glNormal3i GLint nx GLint ny GLint nz void glNormal3iv const GLint *v void glNormal3s GLshort nx GLshort ny GLshort nz void glNormal3sv const GLshort *v void glNormal3x GLfixed nx GLfixed ny GLfixed nz void glNormal3xOES GLfixed nx GLfixed ny GLfixed nz void glNormal3xvOES const GLfixed *coords void glNormalFormatNV GLenum type GLsizei stride void glNormalP3ui GLenum type GLuint coords void glNormalP3uiv GLenum type const GLuint *coords void glNormalPointer GLenum type GLsizei stride const void *pointer void glNormalPointerEXT GLenum type GLsizei stride GLsizei count const void *pointer void glNormalPointerListIBM GLenum type GLint stride const void **pointer GLint ptrstride void glNormalPointervINTEL GLenum type const void **pointer void glNormalStream3bATI GLenum stream GLbyte nx GLbyte ny GLbyte nz void glNormalStream3bvATI GLenum stream const GLbyte *coords void glNormalStream3dATI GLenum stream GLdouble nx GLdouble ny GLdouble nz void glNormalStream3dvATI GLenum stream const GLdouble *coords void glNormalStream3fATI GLenum stream GLfloat nx GLfloat ny GLfloat nz void glNormalStream3fvATI GLenum stream const GLfloat *coords void glNormalStream3iATI GLenum stream GLint nx GLint ny GLint nz void glNormalStream3ivATI GLenum stream const GLint *coords void glNormalStream3sATI GLenum stream GLshort nx GLshort ny GLshort nz void glNormalStream3svATI GLenum stream const GLshort *coords void glObjectLabel GLenum identifier GLuint name GLsizei length const GLchar *label void glObjectLabelKHR GLenum identifier GLuint name GLsizei length const GLchar *label void glObjectPtrLabel const void *ptr GLsizei length const GLchar *label void glObjectPtrLabelKHR const void *ptr GLsizei length const GLchar *label GLenum glObjectPurgeableAPPLE GLenum objectType GLuint name GLenum option GLenum glObjectUnpurgeableAPPLE GLenum objectType GLuint name GLenum option void glOrtho GLdouble left GLdouble right GLdouble bottom GLdouble top GLdouble zNear GLdouble zFar void glOrthof GLfloat l GLfloat r GLfloat b GLfloat t GLfloat n GLfloat f void glOrthofOES GLfloat l GLfloat r GLfloat b GLfloat t GLfloat n GLfloat f void glOrthox GLfixed l GLfixed r GLfixed b GLfixed t GLfixed n GLfixed f void glOrthoxOES GLfixed l GLfixed r GLfixed b GLfixed t GLfixed n GLfixed f void glPNTrianglesfATI GLenum pname GLfloat param void glPNTrianglesiATI GLenum pname GLint param void glPassTexCoordATI GLuint dst GLuint coord GLenum swizzle void glPassThrough GLfloat token void glPassThroughxOES GLfixed token void glPatchParameterfv GLenum pname const GLfloat *values void glPatchParameteri GLenum pname GLint value void glPatchParameteriEXT GLenum pname GLint value void glPatchParameteriOES GLenum pname GLint value void glPathColorGenNV GLenum color GLenum genMode GLenum colorFormat const GLfloat *coeffs void glPathCommandsNV GLuint path GLsizei numCommands const GLubyte *commands GLsizei numCoords GLenum coordType const void *coords void glPathCoordsNV GLuint path GLsizei numCoords GLenum coordType const void *coords void glPathCoverDepthFuncNV GLenum func void glPathDashArrayNV GLuint path GLsizei dashCount const GLfloat *dashArray void glPathFogGenNV GLenum genMode GLenum glPathGlyphIndexArrayNV GLuint firstPathName GLenum fontTarget const void *fontName GLbitfield fontStyle GLuint firstGlyphIndex GLsizei numGlyphs GLuint pathParameterTemplate GLfloat emScale GLenum glPathGlyphIndexRangeNV GLenum fontTarget const void *fontName GLbitfield fontStyle GLuint pathParameterTemplate GLfloat emScale GLuint baseAndCount[2] void glPathGlyphRangeNV GLuint firstPathName GLenum fontTarget const void *fontName GLbitfield fontStyle GLuint firstGlyph GLsizei numGlyphs GLenum handleMissingGlyphs GLuint pathParameterTemplate GLfloat emScale void glPathGlyphsNV GLuint firstPathName GLenum fontTarget const void *fontName GLbitfield fontStyle GLsizei numGlyphs GLenum type const void *charcodes GLenum handleMissingGlyphs GLuint pathParameterTemplate GLfloat emScale GLenum glPathMemoryGlyphIndexArrayNV GLuint firstPathName GLenum fontTarget GLsizeiptr fontSize const void *fontData GLsizei faceIndex GLuint firstGlyphIndex GLsizei numGlyphs GLuint pathParameterTemplate GLfloat emScale void glPathParameterfNV GLuint path GLenum pname GLfloat value void glPathParameterfvNV GLuint path GLenum pname const GLfloat *value void glPathParameteriNV GLuint path GLenum pname GLint value void glPathParameterivNV GLuint path GLenum pname const GLint *value void glPathStencilDepthOffsetNV GLfloat factor GLfloat units void glPathStencilFuncNV GLenum func GLint ref GLuint mask void glPathStringNV GLuint path GLenum format GLsizei length const void *pathString void glPathSubCommandsNV GLuint path GLsizei commandStart GLsizei commandsToDelete GLsizei numCommands const GLubyte *commands GLsizei numCoords GLenum coordType const void *coords void glPathSubCoordsNV GLuint path GLsizei coordStart GLsizei numCoords GLenum coordType const void *coords void glPathTexGenNV GLenum texCoordSet GLenum genMode GLint components const GLfloat *coeffs void glPauseTransformFeedback void glPauseTransformFeedbackNV void glPixelDataRangeNV GLenum target GLsizei length const void *pointer void glPixelMapfv GLenum map GLsizei mapsize const GLfloat *values void glPixelMapuiv GLenum map GLsizei mapsize const GLuint *values void glPixelMapusv GLenum map GLsizei mapsize const GLushort *values void glPixelMapx GLenum map GLint size const GLfixed *values void glPixelStoref GLenum pname GLfloat param void glPixelStorei GLenum pname GLint param void glPixelStorex GLenum pname GLfixed param void glPixelTexGenParameterfSGIS GLenum pname GLfloat param void glPixelTexGenParameterfvSGIS GLenum pname const GLfloat *params void glPixelTexGenParameteriSGIS GLenum pname GLint param void glPixelTexGenParameterivSGIS GLenum pname const GLint *params void glPixelTexGenSGIX GLenum mode void glPixelTransferf GLenum pname GLfloat param void glPixelTransferi GLenum pname GLint param void glPixelTransferxOES GLenum pname GLfixed param void glPixelTransformParameterfEXT GLenum target GLenum pname GLfloat param void glPixelTransformParameterfvEXT GLenum target GLenum pname const GLfloat *params void glPixelTransformParameteriEXT GLenum target GLenum pname GLint param void glPixelTransformParameterivEXT GLenum target GLenum pname const GLint *params void glPixelZoom GLfloat xfactor GLfloat yfactor void glPixelZoomxOES GLfixed xfactor GLfixed yfactor GLboolean glPointAlongPathNV GLuint path GLsizei startSegment GLsizei numSegments GLfloat distance GLfloat *x GLfloat *y GLfloat *tangentX GLfloat *tangentY void glPointParameterf GLenum pname GLfloat param void glPointParameterfARB GLenum pname GLfloat param void glPointParameterfEXT GLenum pname GLfloat param void glPointParameterfSGIS GLenum pname GLfloat param void glPointParameterfv GLenum pname const GLfloat *params void glPointParameterfvARB GLenum pname const GLfloat *params void glPointParameterfvEXT GLenum pname const GLfloat *params void glPointParameterfvSGIS GLenum pname const GLfloat *params void glPointParameteri GLenum pname GLint param void glPointParameteriNV GLenum pname GLint param void glPointParameteriv GLenum pname const GLint *params void glPointParameterivNV GLenum pname const GLint *params void glPointParameterx GLenum pname GLfixed param void glPointParameterxOES GLenum pname GLfixed param void glPointParameterxv GLenum pname const GLfixed *params void glPointParameterxvOES GLenum pname const GLfixed *params void glPointSize GLfloat size void glPointSizePointerOES GLenum type GLsizei stride const void *pointer void glPointSizex GLfixed size void glPointSizexOES GLfixed size GLint glPollAsyncSGIX GLuint *markerp GLint glPollInstrumentsSGIX GLint *marker_p void glPolygonMode GLenum face GLenum mode void glPolygonModeNV GLenum face GLenum mode void glPolygonOffset GLfloat factor GLfloat units void glPolygonOffsetClampEXT GLfloat factor GLfloat units GLfloat clamp void glPolygonOffsetEXT GLfloat factor GLfloat bias void glPolygonOffsetx GLfixed factor GLfixed units void glPolygonOffsetxOES GLfixed factor GLfixed units void glPolygonStipple const GLubyte *mask void glPopAttrib void glPopClientAttrib void glPopDebugGroup void glPopDebugGroupKHR void glPopGroupMarkerEXT void glPopMatrix void glPopName void glPresentFrameDualFillNV GLuint video_slot GLuint64EXT minPresentTime GLuint beginPresentTimeId GLuint presentDurationId GLenum type GLenum target0 GLuint fill0 GLenum target1 GLuint fill1 GLenum target2 GLuint fill2 GLenum target3 GLuint fill3 void glPresentFrameKeyedNV GLuint video_slot GLuint64EXT minPresentTime GLuint beginPresentTimeId GLuint presentDurationId GLenum type GLenum target0 GLuint fill0 GLuint key0 GLenum target1 GLuint fill1 GLuint key1 void glPrimitiveBoundingBox GLfloat minX GLfloat minY GLfloat minZ GLfloat minW GLfloat maxX GLfloat maxY GLfloat maxZ GLfloat maxW void glPrimitiveBoundingBoxARB GLfloat minX GLfloat minY GLfloat minZ GLfloat minW GLfloat maxX GLfloat maxY GLfloat maxZ GLfloat maxW void glPrimitiveBoundingBoxEXT GLfloat minX GLfloat minY GLfloat minZ GLfloat minW GLfloat maxX GLfloat maxY GLfloat maxZ GLfloat maxW void glPrimitiveBoundingBoxOES GLfloat minX GLfloat minY GLfloat minZ GLfloat minW GLfloat maxX GLfloat maxY GLfloat maxZ GLfloat maxW void glPrimitiveRestartIndex GLuint index void glPrimitiveRestartIndexNV GLuint index void glPrimitiveRestartNV void glPrioritizeTextures GLsizei n const GLuint *textures const GLfloat *priorities void glPrioritizeTexturesEXT GLsizei n const GLuint *textures const GLclampf *priorities void glPrioritizeTexturesxOES GLsizei n const GLuint *textures const GLfixed *priorities void glProgramBinary GLuint program GLenum binaryFormat const void *binary GLsizei length void glProgramBinaryOES GLuint program GLenum binaryFormat const void *binary GLint length void glProgramBufferParametersIivNV GLenum target GLuint bindingIndex GLuint wordIndex GLsizei count const GLint *params void glProgramBufferParametersIuivNV GLenum target GLuint bindingIndex GLuint wordIndex GLsizei count const GLuint *params void glProgramBufferParametersfvNV GLenum target GLuint bindingIndex GLuint wordIndex GLsizei count const GLfloat *params void glProgramEnvParameter4dARB GLenum target GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glProgramEnvParameter4dvARB GLenum target GLuint index const GLdouble *params void glProgramEnvParameter4fARB GLenum target GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glProgramEnvParameter4fvARB GLenum target GLuint index const GLfloat *params void glProgramEnvParameterI4iNV GLenum target GLuint index GLint x GLint y GLint z GLint w void glProgramEnvParameterI4ivNV GLenum target GLuint index const GLint *params void glProgramEnvParameterI4uiNV GLenum target GLuint index GLuint x GLuint y GLuint z GLuint w void glProgramEnvParameterI4uivNV GLenum target GLuint index const GLuint *params void glProgramEnvParameters4fvEXT GLenum target GLuint index GLsizei count const GLfloat *params void glProgramEnvParametersI4ivNV GLenum target GLuint index GLsizei count const GLint *params void glProgramEnvParametersI4uivNV GLenum target GLuint index GLsizei count const GLuint *params void glProgramLocalParameter4dARB GLenum target GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glProgramLocalParameter4dvARB GLenum target GLuint index const GLdouble *params void glProgramLocalParameter4fARB GLenum target GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glProgramLocalParameter4fvARB GLenum target GLuint index const GLfloat *params void glProgramLocalParameterI4iNV GLenum target GLuint index GLint x GLint y GLint z GLint w void glProgramLocalParameterI4ivNV GLenum target GLuint index const GLint *params void glProgramLocalParameterI4uiNV GLenum target GLuint index GLuint x GLuint y GLuint z GLuint w void glProgramLocalParameterI4uivNV GLenum target GLuint index const GLuint *params void glProgramLocalParameters4fvEXT GLenum target GLuint index GLsizei count const GLfloat *params void glProgramLocalParametersI4ivNV GLenum target GLuint index GLsizei count const GLint *params void glProgramLocalParametersI4uivNV GLenum target GLuint index GLsizei count const GLuint *params void glProgramNamedParameter4dNV GLuint id GLsizei len const GLubyte *name GLdouble x GLdouble y GLdouble z GLdouble w void glProgramNamedParameter4dvNV GLuint id GLsizei len const GLubyte *name const GLdouble *v void glProgramNamedParameter4fNV GLuint id GLsizei len const GLubyte *name GLfloat x GLfloat y GLfloat z GLfloat w void glProgramNamedParameter4fvNV GLuint id GLsizei len const GLubyte *name const GLfloat *v void glProgramParameter4dNV GLenum target GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glProgramParameter4dvNV GLenum target GLuint index const GLdouble *v void glProgramParameter4fNV GLenum target GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glProgramParameter4fvNV GLenum target GLuint index const GLfloat *v void glProgramParameteri GLuint program GLenum pname GLint value void glProgramParameteriARB GLuint program GLenum pname GLint value void glProgramParameteriEXT GLuint program GLenum pname GLint value void glProgramParameters4dvNV GLenum target GLuint index GLsizei count const GLdouble *v void glProgramParameters4fvNV GLenum target GLuint index GLsizei count const GLfloat *v void glProgramPathFragmentInputGenNV GLuint program GLint location GLenum genMode GLint components const GLfloat *coeffs void glProgramStringARB GLenum target GLenum format GLsizei len const void *string void glProgramSubroutineParametersuivNV GLenum target GLsizei count const GLuint *params void glProgramUniform1d GLuint program GLint location GLdouble v0 void glProgramUniform1dEXT GLuint program GLint location GLdouble x void glProgramUniform1dv GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform1dvEXT GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform1f GLuint program GLint location GLfloat v0 void glProgramUniform1fEXT GLuint program GLint location GLfloat v0 void glProgramUniform1fv GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform1fvEXT GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform1i GLuint program GLint location GLint v0 void glProgramUniform1i64ARB GLuint program GLint location GLint64 x void glProgramUniform1i64NV GLuint program GLint location GLint64EXT x void glProgramUniform1i64vARB GLuint program GLint location GLsizei count const GLint64 *value void glProgramUniform1i64vNV GLuint program GLint location GLsizei count const GLint64EXT *value void glProgramUniform1iEXT GLuint program GLint location GLint v0 void glProgramUniform1iv GLuint program GLint location GLsizei count const GLint *value void glProgramUniform1ivEXT GLuint program GLint location GLsizei count const GLint *value void glProgramUniform1ui GLuint program GLint location GLuint v0 void glProgramUniform1ui64ARB GLuint program GLint location GLuint64 x void glProgramUniform1ui64NV GLuint program GLint location GLuint64EXT x void glProgramUniform1ui64vARB GLuint program GLint location GLsizei count const GLuint64 *value void glProgramUniform1ui64vNV GLuint program GLint location GLsizei count const GLuint64EXT *value void glProgramUniform1uiEXT GLuint program GLint location GLuint v0 void glProgramUniform1uiv GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform1uivEXT GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform2d GLuint program GLint location GLdouble v0 GLdouble v1 void glProgramUniform2dEXT GLuint program GLint location GLdouble x GLdouble y void glProgramUniform2dv GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform2dvEXT GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform2f GLuint program GLint location GLfloat v0 GLfloat v1 void glProgramUniform2fEXT GLuint program GLint location GLfloat v0 GLfloat v1 void glProgramUniform2fv GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform2fvEXT GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform2i GLuint program GLint location GLint v0 GLint v1 void glProgramUniform2i64ARB GLuint program GLint location GLint64 x GLint64 y void glProgramUniform2i64NV GLuint program GLint location GLint64EXT x GLint64EXT y void glProgramUniform2i64vARB GLuint program GLint location GLsizei count const GLint64 *value void glProgramUniform2i64vNV GLuint program GLint location GLsizei count const GLint64EXT *value void glProgramUniform2iEXT GLuint program GLint location GLint v0 GLint v1 void glProgramUniform2iv GLuint program GLint location GLsizei count const GLint *value void glProgramUniform2ivEXT GLuint program GLint location GLsizei count const GLint *value void glProgramUniform2ui GLuint program GLint location GLuint v0 GLuint v1 void glProgramUniform2ui64ARB GLuint program GLint location GLuint64 x GLuint64 y void glProgramUniform2ui64NV GLuint program GLint location GLuint64EXT x GLuint64EXT y void glProgramUniform2ui64vARB GLuint program GLint location GLsizei count const GLuint64 *value void glProgramUniform2ui64vNV GLuint program GLint location GLsizei count const GLuint64EXT *value void glProgramUniform2uiEXT GLuint program GLint location GLuint v0 GLuint v1 void glProgramUniform2uiv GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform2uivEXT GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform3d GLuint program GLint location GLdouble v0 GLdouble v1 GLdouble v2 void glProgramUniform3dEXT GLuint program GLint location GLdouble x GLdouble y GLdouble z void glProgramUniform3dv GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform3dvEXT GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform3f GLuint program GLint location GLfloat v0 GLfloat v1 GLfloat v2 void glProgramUniform3fEXT GLuint program GLint location GLfloat v0 GLfloat v1 GLfloat v2 void glProgramUniform3fv GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform3fvEXT GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform3i GLuint program GLint location GLint v0 GLint v1 GLint v2 void glProgramUniform3i64ARB GLuint program GLint location GLint64 x GLint64 y GLint64 z void glProgramUniform3i64NV GLuint program GLint location GLint64EXT x GLint64EXT y GLint64EXT z void glProgramUniform3i64vARB GLuint program GLint location GLsizei count const GLint64 *value void glProgramUniform3i64vNV GLuint program GLint location GLsizei count const GLint64EXT *value void glProgramUniform3iEXT GLuint program GLint location GLint v0 GLint v1 GLint v2 void glProgramUniform3iv GLuint program GLint location GLsizei count const GLint *value void glProgramUniform3ivEXT GLuint program GLint location GLsizei count const GLint *value void glProgramUniform3ui GLuint program GLint location GLuint v0 GLuint v1 GLuint v2 void glProgramUniform3ui64ARB GLuint program GLint location GLuint64 x GLuint64 y GLuint64 z void glProgramUniform3ui64NV GLuint program GLint location GLuint64EXT x GLuint64EXT y GLuint64EXT z void glProgramUniform3ui64vARB GLuint program GLint location GLsizei count const GLuint64 *value void glProgramUniform3ui64vNV GLuint program GLint location GLsizei count const GLuint64EXT *value void glProgramUniform3uiEXT GLuint program GLint location GLuint v0 GLuint v1 GLuint v2 void glProgramUniform3uiv GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform3uivEXT GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform4d GLuint program GLint location GLdouble v0 GLdouble v1 GLdouble v2 GLdouble v3 void glProgramUniform4dEXT GLuint program GLint location GLdouble x GLdouble y GLdouble z GLdouble w void glProgramUniform4dv GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform4dvEXT GLuint program GLint location GLsizei count const GLdouble *value void glProgramUniform4f GLuint program GLint location GLfloat v0 GLfloat v1 GLfloat v2 GLfloat v3 void glProgramUniform4fEXT GLuint program GLint location GLfloat v0 GLfloat v1 GLfloat v2 GLfloat v3 void glProgramUniform4fv GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform4fvEXT GLuint program GLint location GLsizei count const GLfloat *value void glProgramUniform4i GLuint program GLint location GLint v0 GLint v1 GLint v2 GLint v3 void glProgramUniform4i64ARB GLuint program GLint location GLint64 x GLint64 y GLint64 z GLint64 w void glProgramUniform4i64NV GLuint program GLint location GLint64EXT x GLint64EXT y GLint64EXT z GLint64EXT w void glProgramUniform4i64vARB GLuint program GLint location GLsizei count const GLint64 *value void glProgramUniform4i64vNV GLuint program GLint location GLsizei count const GLint64EXT *value void glProgramUniform4iEXT GLuint program GLint location GLint v0 GLint v1 GLint v2 GLint v3 void glProgramUniform4iv GLuint program GLint location GLsizei count const GLint *value void glProgramUniform4ivEXT GLuint program GLint location GLsizei count const GLint *value void glProgramUniform4ui GLuint program GLint location GLuint v0 GLuint v1 GLuint v2 GLuint v3 void glProgramUniform4ui64ARB GLuint program GLint location GLuint64 x GLuint64 y GLuint64 z GLuint64 w void glProgramUniform4ui64NV GLuint program GLint location GLuint64EXT x GLuint64EXT y GLuint64EXT z GLuint64EXT w void glProgramUniform4ui64vARB GLuint program GLint location GLsizei count const GLuint64 *value void glProgramUniform4ui64vNV GLuint program GLint location GLsizei count const GLuint64EXT *value void glProgramUniform4uiEXT GLuint program GLint location GLuint v0 GLuint v1 GLuint v2 GLuint v3 void glProgramUniform4uiv GLuint program GLint location GLsizei count const GLuint *value void glProgramUniform4uivEXT GLuint program GLint location GLsizei count const GLuint *value void glProgramUniformHandleui64ARB GLuint program GLint location GLuint64 value void glProgramUniformHandleui64NV GLuint program GLint location GLuint64 value void glProgramUniformHandleui64vARB GLuint program GLint location GLsizei count const GLuint64 *values void glProgramUniformHandleui64vNV GLuint program GLint location GLsizei count const GLuint64 *values void glProgramUniformMatrix2dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix2fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix2x3dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2x3dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2x3fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix2x3fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix2x4dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2x4dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix2x4fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix2x4fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3x2dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3x2dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3x2fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3x2fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3x4dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3x4dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix3x4fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix3x4fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4x2dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4x2dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4x2fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4x2fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4x3dv GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4x3dvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLdouble *value void glProgramUniformMatrix4x3fv GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformMatrix4x3fvEXT GLuint program GLint location GLsizei count GLboolean transpose const GLfloat *value void glProgramUniformui64NV GLuint program GLint location GLuint64EXT value void glProgramUniformui64vNV GLuint program GLint location GLsizei count const GLuint64EXT *value void glProgramVertexLimitNV GLenum target GLint limit void glProvokingVertex GLenum mode void glProvokingVertexEXT GLenum mode void glPushAttrib GLbitfield mask void glPushClientAttrib GLbitfield mask void glPushClientAttribDefaultEXT GLbitfield mask void glPushDebugGroup GLenum source GLuint id GLsizei length const GLchar *message void glPushDebugGroupKHR GLenum source GLuint id GLsizei length const GLchar *message void glPushGroupMarkerEXT GLsizei length const GLchar *marker void glPushMatrix void glPushName GLuint name void glQueryCounter GLuint id GLenum target void glQueryCounterEXT GLuint id GLenum target GLbitfield glQueryMatrixxOES GLfixed *mantissa GLint *exponent void glQueryObjectParameteruiAMD GLenum target GLuint id GLenum pname GLuint param void glRasterPos2d GLdouble x GLdouble y void glRasterPos2dv const GLdouble *v void glRasterPos2f GLfloat x GLfloat y void glRasterPos2fv const GLfloat *v void glRasterPos2i GLint x GLint y void glRasterPos2iv const GLint *v void glRasterPos2s GLshort x GLshort y void glRasterPos2sv const GLshort *v void glRasterPos2xOES GLfixed x GLfixed y void glRasterPos2xvOES const GLfixed *coords void glRasterPos3d GLdouble x GLdouble y GLdouble z void glRasterPos3dv const GLdouble *v void glRasterPos3f GLfloat x GLfloat y GLfloat z void glRasterPos3fv const GLfloat *v void glRasterPos3i GLint x GLint y GLint z void glRasterPos3iv const GLint *v void glRasterPos3s GLshort x GLshort y GLshort z void glRasterPos3sv const GLshort *v void glRasterPos3xOES GLfixed x GLfixed y GLfixed z void glRasterPos3xvOES const GLfixed *coords void glRasterPos4d GLdouble x GLdouble y GLdouble z GLdouble w void glRasterPos4dv const GLdouble *v void glRasterPos4f GLfloat x GLfloat y GLfloat z GLfloat w void glRasterPos4fv const GLfloat *v void glRasterPos4i GLint x GLint y GLint z GLint w void glRasterPos4iv const GLint *v void glRasterPos4s GLshort x GLshort y GLshort z GLshort w void glRasterPos4sv const GLshort *v void glRasterPos4xOES GLfixed x GLfixed y GLfixed z GLfixed w void glRasterPos4xvOES const GLfixed *coords void glRasterSamplesEXT GLuint samples GLboolean fixedsamplelocations void glReadBuffer GLenum src void glReadBufferIndexedEXT GLenum src GLint index void glReadBufferNV GLenum mode void glReadInstrumentsSGIX GLint marker void glReadPixels GLint x GLint y GLsizei width GLsizei height GLenum format GLenum type void *pixels void glReadnPixels GLint x GLint y GLsizei width GLsizei height GLenum format GLenum type GLsizei bufSize void *data void glReadnPixelsARB GLint x GLint y GLsizei width GLsizei height GLenum format GLenum type GLsizei bufSize void *data void glReadnPixelsEXT GLint x GLint y GLsizei width GLsizei height GLenum format GLenum type GLsizei bufSize void *data void glReadnPixelsKHR GLint x GLint y GLsizei width GLsizei height GLenum format GLenum type GLsizei bufSize void *data void glRectd GLdouble x1 GLdouble y1 GLdouble x2 GLdouble y2 void glRectdv const GLdouble *v1 const GLdouble *v2 void glRectf GLfloat x1 GLfloat y1 GLfloat x2 GLfloat y2 void glRectfv const GLfloat *v1 const GLfloat *v2 void glRecti GLint x1 GLint y1 GLint x2 GLint y2 void glRectiv const GLint *v1 const GLint *v2 void glRects GLshort x1 GLshort y1 GLshort x2 GLshort y2 void glRectsv const GLshort *v1 const GLshort *v2 void glRectxOES GLfixed x1 GLfixed y1 GLfixed x2 GLfixed y2 void glRectxvOES const GLfixed *v1 const GLfixed *v2 void glReferencePlaneSGIX const GLdouble *equation void glReleaseShaderCompiler GLint glRenderMode GLenum mode void glRenderbufferStorage GLenum target GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageEXT GLenum target GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisample GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleANGLE GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleAPPLE GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleCoverageNV GLenum target GLsizei coverageSamples GLsizei colorSamples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleEXT GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleIMG GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageMultisampleNV GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height void glRenderbufferStorageOES GLenum target GLenum internalformat GLsizei width GLsizei height void glReplacementCodePointerSUN GLenum type GLsizei stride const void **pointer void glReplacementCodeubSUN GLubyte code void glReplacementCodeubvSUN const GLubyte *code void glReplacementCodeuiColor3fVertex3fSUN GLuint rc GLfloat r GLfloat g GLfloat b GLfloat x GLfloat y GLfloat z void glReplacementCodeuiColor3fVertex3fvSUN const GLuint *rc const GLfloat *c const GLfloat *v void glReplacementCodeuiColor4fNormal3fVertex3fSUN GLuint rc GLfloat r GLfloat g GLfloat b GLfloat a GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glReplacementCodeuiColor4fNormal3fVertex3fvSUN const GLuint *rc const GLfloat *c const GLfloat *n const GLfloat *v void glReplacementCodeuiColor4ubVertex3fSUN GLuint rc GLubyte r GLubyte g GLubyte b GLubyte a GLfloat x GLfloat y GLfloat z void glReplacementCodeuiColor4ubVertex3fvSUN const GLuint *rc const GLubyte *c const GLfloat *v void glReplacementCodeuiNormal3fVertex3fSUN GLuint rc GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glReplacementCodeuiNormal3fVertex3fvSUN const GLuint *rc const GLfloat *n const GLfloat *v void glReplacementCodeuiSUN GLuint code void glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN GLuint rc GLfloat s GLfloat t GLfloat r GLfloat g GLfloat b GLfloat a GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN const GLuint *rc const GLfloat *tc const GLfloat *c const GLfloat *n const GLfloat *v void glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN GLuint rc GLfloat s GLfloat t GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN const GLuint *rc const GLfloat *tc const GLfloat *n const GLfloat *v void glReplacementCodeuiTexCoord2fVertex3fSUN GLuint rc GLfloat s GLfloat t GLfloat x GLfloat y GLfloat z void glReplacementCodeuiTexCoord2fVertex3fvSUN const GLuint *rc const GLfloat *tc const GLfloat *v void glReplacementCodeuiVertex3fSUN GLuint rc GLfloat x GLfloat y GLfloat z void glReplacementCodeuiVertex3fvSUN const GLuint *rc const GLfloat *v void glReplacementCodeuivSUN const GLuint *code void glReplacementCodeusSUN GLushort code void glReplacementCodeusvSUN const GLushort *code void glRequestResidentProgramsNV GLsizei n const GLuint *programs void glResetHistogram GLenum target void glResetHistogramEXT GLenum target void glResetMinmax GLenum target void glResetMinmaxEXT GLenum target void glResizeBuffersMESA void glResolveDepthValuesNV void glResolveMultisampleFramebufferAPPLE void glResumeTransformFeedback void glResumeTransformFeedbackNV void glRotated GLdouble angle GLdouble x GLdouble y GLdouble z void glRotatef GLfloat angle GLfloat x GLfloat y GLfloat z void glRotatex GLfixed angle GLfixed x GLfixed y GLfixed z void glRotatexOES GLfixed angle GLfixed x GLfixed y GLfixed z void glSampleCoverage GLfloat value GLboolean invert void glSampleCoverageARB GLfloat value GLboolean invert void glSampleCoveragex GLclampx value GLboolean invert void glSampleCoveragexOES GLclampx value GLboolean invert void glSampleMapATI GLuint dst GLuint interp GLenum swizzle void glSampleMaskEXT GLclampf value GLboolean invert void glSampleMaskIndexedNV GLuint index GLbitfield mask void glSampleMaskSGIS GLclampf value GLboolean invert void glSampleMaski GLuint maskNumber GLbitfield mask void glSamplePatternEXT GLenum pattern void glSamplePatternSGIS GLenum pattern void glSamplerParameterIiv GLuint sampler GLenum pname const GLint *param void glSamplerParameterIivEXT GLuint sampler GLenum pname const GLint *param void glSamplerParameterIivOES GLuint sampler GLenum pname const GLint *param void glSamplerParameterIuiv GLuint sampler GLenum pname const GLuint *param void glSamplerParameterIuivEXT GLuint sampler GLenum pname const GLuint *param void glSamplerParameterIuivOES GLuint sampler GLenum pname const GLuint *param void glSamplerParameterf GLuint sampler GLenum pname GLfloat param void glSamplerParameterfv GLuint sampler GLenum pname const GLfloat *param void glSamplerParameteri GLuint sampler GLenum pname GLint param void glSamplerParameteriv GLuint sampler GLenum pname const GLint *param void glScaled GLdouble x GLdouble y GLdouble z void glScalef GLfloat x GLfloat y GLfloat z void glScalex GLfixed x GLfixed y GLfixed z void glScalexOES GLfixed x GLfixed y GLfixed z void glScissor GLint x GLint y GLsizei width GLsizei height void glScissorArrayv GLuint first GLsizei count const GLint *v void glScissorArrayvNV GLuint first GLsizei count const GLint *v void glScissorIndexed GLuint index GLint left GLint bottom GLsizei width GLsizei height void glScissorIndexedNV GLuint index GLint left GLint bottom GLsizei width GLsizei height void glScissorIndexedv GLuint index const GLint *v void glScissorIndexedvNV GLuint index const GLint *v void glSecondaryColor3b GLbyte red GLbyte green GLbyte blue void glSecondaryColor3bEXT GLbyte red GLbyte green GLbyte blue void glSecondaryColor3bv const GLbyte *v void glSecondaryColor3bvEXT const GLbyte *v void glSecondaryColor3d GLdouble red GLdouble green GLdouble blue void glSecondaryColor3dEXT GLdouble red GLdouble green GLdouble blue void glSecondaryColor3dv const GLdouble *v void glSecondaryColor3dvEXT const GLdouble *v void glSecondaryColor3f GLfloat red GLfloat green GLfloat blue void glSecondaryColor3fEXT GLfloat red GLfloat green GLfloat blue void glSecondaryColor3fv const GLfloat *v void glSecondaryColor3fvEXT const GLfloat *v void glSecondaryColor3hNV GLhalfNV red GLhalfNV green GLhalfNV blue void glSecondaryColor3hvNV const GLhalfNV *v void glSecondaryColor3i GLint red GLint green GLint blue void glSecondaryColor3iEXT GLint red GLint green GLint blue void glSecondaryColor3iv const GLint *v void glSecondaryColor3ivEXT const GLint *v void glSecondaryColor3s GLshort red GLshort green GLshort blue void glSecondaryColor3sEXT GLshort red GLshort green GLshort blue void glSecondaryColor3sv const GLshort *v void glSecondaryColor3svEXT const GLshort *v void glSecondaryColor3ub GLubyte red GLubyte green GLubyte blue void glSecondaryColor3ubEXT GLubyte red GLubyte green GLubyte blue void glSecondaryColor3ubv const GLubyte *v void glSecondaryColor3ubvEXT const GLubyte *v void glSecondaryColor3ui GLuint red GLuint green GLuint blue void glSecondaryColor3uiEXT GLuint red GLuint green GLuint blue void glSecondaryColor3uiv const GLuint *v void glSecondaryColor3uivEXT const GLuint *v void glSecondaryColor3us GLushort red GLushort green GLushort blue void glSecondaryColor3usEXT GLushort red GLushort green GLushort blue void glSecondaryColor3usv const GLushort *v void glSecondaryColor3usvEXT const GLushort *v void glSecondaryColorFormatNV GLint size GLenum type GLsizei stride void glSecondaryColorP3ui GLenum type GLuint color void glSecondaryColorP3uiv GLenum type const GLuint *color void glSecondaryColorPointer GLint size GLenum type GLsizei stride const void *pointer void glSecondaryColorPointerEXT GLint size GLenum type GLsizei stride const void *pointer void glSecondaryColorPointerListIBM GLint size GLenum type GLint stride const void **pointer GLint ptrstride void glSelectBuffer GLsizei size GLuint *buffer void glSelectPerfMonitorCountersAMD GLuint monitor GLboolean enable GLuint group GLint numCounters GLuint *counterList void glSeparableFilter2D GLenum target GLenum internalformat GLsizei width GLsizei height GLenum format GLenum type const void *row const void *column void glSeparableFilter2DEXT GLenum target GLenum internalformat GLsizei width GLsizei height GLenum format GLenum type const void *row const void *column void glSetFenceAPPLE GLuint fence void glSetFenceNV GLuint fence GLenum condition void glSetFragmentShaderConstantATI GLuint dst const GLfloat *value void glSetInvariantEXT GLuint id GLenum type const void *addr void glSetLocalConstantEXT GLuint id GLenum type const void *addr void glSetMultisamplefvAMD GLenum pname GLuint index const GLfloat *val void glShadeModel GLenum mode void glShaderBinary GLsizei count const GLuint *shaders GLenum binaryformat const void *binary GLsizei length void glShaderOp1EXT GLenum op GLuint res GLuint arg1 void glShaderOp2EXT GLenum op GLuint res GLuint arg1 GLuint arg2 void glShaderOp3EXT GLenum op GLuint res GLuint arg1 GLuint arg2 GLuint arg3 void glShaderSource GLuint shader GLsizei count const GLchar *const*string const GLint *length void glShaderSourceARB GLhandleARB shaderObj GLsizei count const GLcharARB **string const GLint *length void glShaderStorageBlockBinding GLuint program GLuint storageBlockIndex GLuint storageBlockBinding void glSharpenTexFuncSGIS GLenum target GLsizei n const GLfloat *points void glSpriteParameterfSGIX GLenum pname GLfloat param void glSpriteParameterfvSGIX GLenum pname const GLfloat *params void glSpriteParameteriSGIX GLenum pname GLint param void glSpriteParameterivSGIX GLenum pname const GLint *params void glStartInstrumentsSGIX void glStartTilingQCOM GLuint x GLuint y GLuint width GLuint height GLbitfield preserveMask void glStateCaptureNV GLuint state GLenum mode void glStencilClearTagEXT GLsizei stencilTagBits GLuint stencilClearTag void glStencilFillPathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLenum fillMode GLuint mask GLenum transformType const GLfloat *transformValues void glStencilFillPathNV GLuint path GLenum fillMode GLuint mask void glStencilFunc GLenum func GLint ref GLuint mask void glStencilFuncSeparate GLenum face GLenum func GLint ref GLuint mask void glStencilFuncSeparateATI GLenum frontfunc GLenum backfunc GLint ref GLuint mask void glStencilMask GLuint mask void glStencilMaskSeparate GLenum face GLuint mask void glStencilOp GLenum fail GLenum zfail GLenum zpass void glStencilOpSeparate GLenum face GLenum sfail GLenum dpfail GLenum dppass void glStencilOpSeparateATI GLenum face GLenum sfail GLenum dpfail GLenum dppass void glStencilOpValueAMD GLenum face GLuint value void glStencilStrokePathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLint reference GLuint mask GLenum transformType const GLfloat *transformValues void glStencilStrokePathNV GLuint path GLint reference GLuint mask void glStencilThenCoverFillPathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLenum fillMode GLuint mask GLenum coverMode GLenum transformType const GLfloat *transformValues void glStencilThenCoverFillPathNV GLuint path GLenum fillMode GLuint mask GLenum coverMode void glStencilThenCoverStrokePathInstancedNV GLsizei numPaths GLenum pathNameType const void *paths GLuint pathBase GLint reference GLuint mask GLenum coverMode GLenum transformType const GLfloat *transformValues void glStencilThenCoverStrokePathNV GLuint path GLint reference GLuint mask GLenum coverMode void glStopInstrumentsSGIX GLint marker void glStringMarkerGREMEDY GLsizei len const void *string void glSubpixelPrecisionBiasNV GLuint xbits GLuint ybits void glSwizzleEXT GLuint res GLuint in GLenum outX GLenum outY GLenum outZ GLenum outW void glSyncTextureINTEL GLuint texture void glTagSampleBufferSGIX void glTangent3bEXT GLbyte tx GLbyte ty GLbyte tz void glTangent3bvEXT const GLbyte *v void glTangent3dEXT GLdouble tx GLdouble ty GLdouble tz void glTangent3dvEXT const GLdouble *v void glTangent3fEXT GLfloat tx GLfloat ty GLfloat tz void glTangent3fvEXT const GLfloat *v void glTangent3iEXT GLint tx GLint ty GLint tz void glTangent3ivEXT const GLint *v void glTangent3sEXT GLshort tx GLshort ty GLshort tz void glTangent3svEXT const GLshort *v void glTangentPointerEXT GLenum type GLsizei stride const void *pointer void glTbufferMask3DFX GLuint mask void glTessellationFactorAMD GLfloat factor void glTessellationModeAMD GLenum mode GLboolean glTestFenceAPPLE GLuint fence GLboolean glTestFenceNV GLuint fence GLboolean glTestObjectAPPLE GLenum object GLuint name void glTexBuffer GLenum target GLenum internalformat GLuint buffer void glTexBufferARB GLenum target GLenum internalformat GLuint buffer void glTexBufferEXT GLenum target GLenum internalformat GLuint buffer void glTexBufferOES GLenum target GLenum internalformat GLuint buffer void glTexBufferRange GLenum target GLenum internalformat GLuint buffer GLintptr offset GLsizeiptr size void glTexBufferRangeEXT GLenum target GLenum internalformat GLuint buffer GLintptr offset GLsizeiptr size void glTexBufferRangeOES GLenum target GLenum internalformat GLuint buffer GLintptr offset GLsizeiptr size void glTexBumpParameterfvATI GLenum pname const GLfloat *param void glTexBumpParameterivATI GLenum pname const GLint *param void glTexCoord1bOES GLbyte s void glTexCoord1bvOES const GLbyte *coords void glTexCoord1d GLdouble s void glTexCoord1dv const GLdouble *v void glTexCoord1f GLfloat s void glTexCoord1fv const GLfloat *v void glTexCoord1hNV GLhalfNV s void glTexCoord1hvNV const GLhalfNV *v void glTexCoord1i GLint s void glTexCoord1iv const GLint *v void glTexCoord1s GLshort s void glTexCoord1sv const GLshort *v void glTexCoord1xOES GLfixed s void glTexCoord1xvOES const GLfixed *coords void glTexCoord2bOES GLbyte s GLbyte t void glTexCoord2bvOES const GLbyte *coords void glTexCoord2d GLdouble s GLdouble t void glTexCoord2dv const GLdouble *v void glTexCoord2f GLfloat s GLfloat t void glTexCoord2fColor3fVertex3fSUN GLfloat s GLfloat t GLfloat r GLfloat g GLfloat b GLfloat x GLfloat y GLfloat z void glTexCoord2fColor3fVertex3fvSUN const GLfloat *tc const GLfloat *c const GLfloat *v void glTexCoord2fColor4fNormal3fVertex3fSUN GLfloat s GLfloat t GLfloat r GLfloat g GLfloat b GLfloat a GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glTexCoord2fColor4fNormal3fVertex3fvSUN const GLfloat *tc const GLfloat *c const GLfloat *n const GLfloat *v void glTexCoord2fColor4ubVertex3fSUN GLfloat s GLfloat t GLubyte r GLubyte g GLubyte b GLubyte a GLfloat x GLfloat y GLfloat z void glTexCoord2fColor4ubVertex3fvSUN const GLfloat *tc const GLubyte *c const GLfloat *v void glTexCoord2fNormal3fVertex3fSUN GLfloat s GLfloat t GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z void glTexCoord2fNormal3fVertex3fvSUN const GLfloat *tc const GLfloat *n const GLfloat *v void glTexCoord2fVertex3fSUN GLfloat s GLfloat t GLfloat x GLfloat y GLfloat z void glTexCoord2fVertex3fvSUN const GLfloat *tc const GLfloat *v void glTexCoord2fv const GLfloat *v void glTexCoord2hNV GLhalfNV s GLhalfNV t void glTexCoord2hvNV const GLhalfNV *v void glTexCoord2i GLint s GLint t void glTexCoord2iv const GLint *v void glTexCoord2s GLshort s GLshort t void glTexCoord2sv const GLshort *v void glTexCoord2xOES GLfixed s GLfixed t void glTexCoord2xvOES const GLfixed *coords void glTexCoord3bOES GLbyte s GLbyte t GLbyte r void glTexCoord3bvOES const GLbyte *coords void glTexCoord3d GLdouble s GLdouble t GLdouble r void glTexCoord3dv const GLdouble *v void glTexCoord3f GLfloat s GLfloat t GLfloat r void glTexCoord3fv const GLfloat *v void glTexCoord3hNV GLhalfNV s GLhalfNV t GLhalfNV r void glTexCoord3hvNV const GLhalfNV *v void glTexCoord3i GLint s GLint t GLint r void glTexCoord3iv const GLint *v void glTexCoord3s GLshort s GLshort t GLshort r void glTexCoord3sv const GLshort *v void glTexCoord3xOES GLfixed s GLfixed t GLfixed r void glTexCoord3xvOES const GLfixed *coords void glTexCoord4bOES GLbyte s GLbyte t GLbyte r GLbyte q void glTexCoord4bvOES const GLbyte *coords void glTexCoord4d GLdouble s GLdouble t GLdouble r GLdouble q void glTexCoord4dv const GLdouble *v void glTexCoord4f GLfloat s GLfloat t GLfloat r GLfloat q void glTexCoord4fColor4fNormal3fVertex4fSUN GLfloat s GLfloat t GLfloat p GLfloat q GLfloat r GLfloat g GLfloat b GLfloat a GLfloat nx GLfloat ny GLfloat nz GLfloat x GLfloat y GLfloat z GLfloat w void glTexCoord4fColor4fNormal3fVertex4fvSUN const GLfloat *tc const GLfloat *c const GLfloat *n const GLfloat *v void glTexCoord4fVertex4fSUN GLfloat s GLfloat t GLfloat p GLfloat q GLfloat x GLfloat y GLfloat z GLfloat w void glTexCoord4fVertex4fvSUN const GLfloat *tc const GLfloat *v void glTexCoord4fv const GLfloat *v void glTexCoord4hNV GLhalfNV s GLhalfNV t GLhalfNV r GLhalfNV q void glTexCoord4hvNV const GLhalfNV *v void glTexCoord4i GLint s GLint t GLint r GLint q void glTexCoord4iv const GLint *v void glTexCoord4s GLshort s GLshort t GLshort r GLshort q void glTexCoord4sv const GLshort *v void glTexCoord4xOES GLfixed s GLfixed t GLfixed r GLfixed q void glTexCoord4xvOES const GLfixed *coords void glTexCoordFormatNV GLint size GLenum type GLsizei stride void glTexCoordP1ui GLenum type GLuint coords void glTexCoordP1uiv GLenum type const GLuint *coords void glTexCoordP2ui GLenum type GLuint coords void glTexCoordP2uiv GLenum type const GLuint *coords void glTexCoordP3ui GLenum type GLuint coords void glTexCoordP3uiv GLenum type const GLuint *coords void glTexCoordP4ui GLenum type GLuint coords void glTexCoordP4uiv GLenum type const GLuint *coords void glTexCoordPointer GLint size GLenum type GLsizei stride const void *pointer void glTexCoordPointerEXT GLint size GLenum type GLsizei stride GLsizei count const void *pointer void glTexCoordPointerListIBM GLint size GLenum type GLint stride const void **pointer GLint ptrstride void glTexCoordPointervINTEL GLint size GLenum type const void **pointer void glTexEnvf GLenum target GLenum pname GLfloat param void glTexEnvfv GLenum target GLenum pname const GLfloat *params void glTexEnvi GLenum target GLenum pname GLint param void glTexEnviv GLenum target GLenum pname const GLint *params void glTexEnvx GLenum target GLenum pname GLfixed param void glTexEnvxOES GLenum target GLenum pname GLfixed param void glTexEnvxv GLenum target GLenum pname const GLfixed *params void glTexEnvxvOES GLenum target GLenum pname const GLfixed *params void glTexFilterFuncSGIS GLenum target GLenum filter GLsizei n const GLfloat *weights void glTexGend GLenum coord GLenum pname GLdouble param void glTexGendv GLenum coord GLenum pname const GLdouble *params void glTexGenf GLenum coord GLenum pname GLfloat param void glTexGenfOES GLenum coord GLenum pname GLfloat param void glTexGenfv GLenum coord GLenum pname const GLfloat *params void glTexGenfvOES GLenum coord GLenum pname const GLfloat *params void glTexGeni GLenum coord GLenum pname GLint param void glTexGeniOES GLenum coord GLenum pname GLint param void glTexGeniv GLenum coord GLenum pname const GLint *params void glTexGenivOES GLenum coord GLenum pname const GLint *params void glTexGenxOES GLenum coord GLenum pname GLfixed param void glTexGenxvOES GLenum coord GLenum pname const GLfixed *params void glTexImage1D GLenum target GLint level GLint internalformat GLsizei width GLint border GLenum format GLenum type const void *pixels void glTexImage2D GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLint border GLenum format GLenum type const void *pixels void glTexImage2DMultisample GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLboolean fixedsamplelocations void glTexImage2DMultisampleCoverageNV GLenum target GLsizei coverageSamples GLsizei colorSamples GLint internalFormat GLsizei width GLsizei height GLboolean fixedSampleLocations void glTexImage3D GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLsizei depth GLint border GLenum format GLenum type const void *pixels void glTexImage3DEXT GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLenum format GLenum type const void *pixels void glTexImage3DMultisample GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLsizei depth GLboolean fixedsamplelocations void glTexImage3DMultisampleCoverageNV GLenum target GLsizei coverageSamples GLsizei colorSamples GLint internalFormat GLsizei width GLsizei height GLsizei depth GLboolean fixedSampleLocations void glTexImage3DOES GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLint border GLenum format GLenum type const void *pixels void glTexImage4DSGIS GLenum target GLint level GLenum internalformat GLsizei width GLsizei height GLsizei depth GLsizei size4d GLint border GLenum format GLenum type const void *pixels void glTexPageCommitmentARB GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLboolean commit void glTexPageCommitmentEXT GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLboolean commit void glTexParameterIiv GLenum target GLenum pname const GLint *params void glTexParameterIivEXT GLenum target GLenum pname const GLint *params void glTexParameterIivOES GLenum target GLenum pname const GLint *params void glTexParameterIuiv GLenum target GLenum pname const GLuint *params void glTexParameterIuivEXT GLenum target GLenum pname const GLuint *params void glTexParameterIuivOES GLenum target GLenum pname const GLuint *params void glTexParameterf GLenum target GLenum pname GLfloat param void glTexParameterfv GLenum target GLenum pname const GLfloat *params void glTexParameteri GLenum target GLenum pname GLint param void glTexParameteriv GLenum target GLenum pname const GLint *params void glTexParameterx GLenum target GLenum pname GLfixed param void glTexParameterxOES GLenum target GLenum pname GLfixed param void glTexParameterxv GLenum target GLenum pname const GLfixed *params void glTexParameterxvOES GLenum target GLenum pname const GLfixed *params void glTexRenderbufferNV GLenum target GLuint renderbuffer void glTexStorage1D GLenum target GLsizei levels GLenum internalformat GLsizei width void glTexStorage1DEXT GLenum target GLsizei levels GLenum internalformat GLsizei width void glTexStorage2D GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height void glTexStorage2DEXT GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height void glTexStorage2DMultisample GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLboolean fixedsamplelocations void glTexStorage3D GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height GLsizei depth void glTexStorage3DEXT GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height GLsizei depth void glTexStorage3DMultisample GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLsizei depth GLboolean fixedsamplelocations void glTexStorage3DMultisampleOES GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLsizei depth GLboolean fixedsamplelocations void glTexStorageSparseAMD GLenum target GLenum internalFormat GLsizei width GLsizei height GLsizei depth GLsizei layers GLbitfield flags void glTexSubImage1D GLenum target GLint level GLint xoffset GLsizei width GLenum format GLenum type const void *pixels void glTexSubImage1DEXT GLenum target GLint level GLint xoffset GLsizei width GLenum format GLenum type const void *pixels void glTexSubImage2D GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glTexSubImage2DEXT GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glTexSubImage3D GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glTexSubImage3DEXT GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glTexSubImage3DOES GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glTexSubImage4DSGIS GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLint woffset GLsizei width GLsizei height GLsizei depth GLsizei size4d GLenum format GLenum type const void *pixels void glTextureBarrier void glTextureBarrierNV void glTextureBuffer GLuint texture GLenum internalformat GLuint buffer void glTextureBufferEXT GLuint texture GLenum target GLenum internalformat GLuint buffer void glTextureBufferRange GLuint texture GLenum internalformat GLuint buffer GLintptr offset GLsizeiptr size void glTextureBufferRangeEXT GLuint texture GLenum target GLenum internalformat GLuint buffer GLintptr offset GLsizeiptr size void glTextureColorMaskSGIS GLboolean red GLboolean green GLboolean blue GLboolean alpha void glTextureImage1DEXT GLuint texture GLenum target GLint level GLint internalformat GLsizei width GLint border GLenum format GLenum type const void *pixels void glTextureImage2DEXT GLuint texture GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLint border GLenum format GLenum type const void *pixels void glTextureImage2DMultisampleCoverageNV GLuint texture GLenum target GLsizei coverageSamples GLsizei colorSamples GLint internalFormat GLsizei width GLsizei height GLboolean fixedSampleLocations void glTextureImage2DMultisampleNV GLuint texture GLenum target GLsizei samples GLint internalFormat GLsizei width GLsizei height GLboolean fixedSampleLocations void glTextureImage3DEXT GLuint texture GLenum target GLint level GLint internalformat GLsizei width GLsizei height GLsizei depth GLint border GLenum format GLenum type const void *pixels void glTextureImage3DMultisampleCoverageNV GLuint texture GLenum target GLsizei coverageSamples GLsizei colorSamples GLint internalFormat GLsizei width GLsizei height GLsizei depth GLboolean fixedSampleLocations void glTextureImage3DMultisampleNV GLuint texture GLenum target GLsizei samples GLint internalFormat GLsizei width GLsizei height GLsizei depth GLboolean fixedSampleLocations void glTextureLightEXT GLenum pname void glTextureMaterialEXT GLenum face GLenum mode void glTextureNormalEXT GLenum mode void glTexturePageCommitmentEXT GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLboolean commit void glTextureParameterIiv GLuint texture GLenum pname const GLint *params void glTextureParameterIivEXT GLuint texture GLenum target GLenum pname const GLint *params void glTextureParameterIuiv GLuint texture GLenum pname const GLuint *params void glTextureParameterIuivEXT GLuint texture GLenum target GLenum pname const GLuint *params void glTextureParameterf GLuint texture GLenum pname GLfloat param void glTextureParameterfEXT GLuint texture GLenum target GLenum pname GLfloat param void glTextureParameterfv GLuint texture GLenum pname const GLfloat *param void glTextureParameterfvEXT GLuint texture GLenum target GLenum pname const GLfloat *params void glTextureParameteri GLuint texture GLenum pname GLint param void glTextureParameteriEXT GLuint texture GLenum target GLenum pname GLint param void glTextureParameteriv GLuint texture GLenum pname const GLint *param void glTextureParameterivEXT GLuint texture GLenum target GLenum pname const GLint *params void glTextureRangeAPPLE GLenum target GLsizei length const void *pointer void glTextureRenderbufferEXT GLuint texture GLenum target GLuint renderbuffer void glTextureStorage1D GLuint texture GLsizei levels GLenum internalformat GLsizei width void glTextureStorage1DEXT GLuint texture GLenum target GLsizei levels GLenum internalformat GLsizei width void glTextureStorage2D GLuint texture GLsizei levels GLenum internalformat GLsizei width GLsizei height void glTextureStorage2DEXT GLuint texture GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height void glTextureStorage2DMultisample GLuint texture GLsizei samples GLenum internalformat GLsizei width GLsizei height GLboolean fixedsamplelocations void glTextureStorage2DMultisampleEXT GLuint texture GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLboolean fixedsamplelocations void glTextureStorage3D GLuint texture GLsizei levels GLenum internalformat GLsizei width GLsizei height GLsizei depth void glTextureStorage3DEXT GLuint texture GLenum target GLsizei levels GLenum internalformat GLsizei width GLsizei height GLsizei depth void glTextureStorage3DMultisample GLuint texture GLsizei samples GLenum internalformat GLsizei width GLsizei height GLsizei depth GLboolean fixedsamplelocations void glTextureStorage3DMultisampleEXT GLuint texture GLenum target GLsizei samples GLenum internalformat GLsizei width GLsizei height GLsizei depth GLboolean fixedsamplelocations void glTextureStorageSparseAMD GLuint texture GLenum target GLenum internalFormat GLsizei width GLsizei height GLsizei depth GLsizei layers GLbitfield flags void glTextureSubImage1D GLuint texture GLint level GLint xoffset GLsizei width GLenum format GLenum type const void *pixels void glTextureSubImage1DEXT GLuint texture GLenum target GLint level GLint xoffset GLsizei width GLenum format GLenum type const void *pixels void glTextureSubImage2D GLuint texture GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glTextureSubImage2DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLsizei width GLsizei height GLenum format GLenum type const void *pixels void glTextureSubImage3D GLuint texture GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glTextureSubImage3DEXT GLuint texture GLenum target GLint level GLint xoffset GLint yoffset GLint zoffset GLsizei width GLsizei height GLsizei depth GLenum format GLenum type const void *pixels void glTextureView GLuint texture GLenum target GLuint origtexture GLenum internalformat GLuint minlevel GLuint numlevels GLuint minlayer GLuint numlayers void glTextureViewEXT GLuint texture GLenum target GLuint origtexture GLenum internalformat GLuint minlevel GLuint numlevels GLuint minlayer GLuint numlayers void glTextureViewOES GLuint texture GLenum target GLuint origtexture GLenum internalformat GLuint minlevel GLuint numlevels GLuint minlayer GLuint numlayers void glTrackMatrixNV GLenum target GLuint address GLenum matrix GLenum transform void glTransformFeedbackAttribsNV GLsizei count const GLint *attribs GLenum bufferMode void glTransformFeedbackBufferBase GLuint xfb GLuint index GLuint buffer void glTransformFeedbackBufferRange GLuint xfb GLuint index GLuint buffer GLintptr offset GLsizeiptr size void glTransformFeedbackStreamAttribsNV GLsizei count const GLint *attribs GLsizei nbuffers const GLint *bufstreams GLenum bufferMode void glTransformFeedbackVaryings GLuint program GLsizei count const GLchar *const*varyings GLenum bufferMode void glTransformFeedbackVaryingsEXT GLuint program GLsizei count const GLchar *const*varyings GLenum bufferMode void glTransformFeedbackVaryingsNV GLuint program GLsizei count const GLint *locations GLenum bufferMode void glTransformPathNV GLuint resultPath GLuint srcPath GLenum transformType const GLfloat *transformValues void glTranslated GLdouble x GLdouble y GLdouble z void glTranslatef GLfloat x GLfloat y GLfloat z void glTranslatex GLfixed x GLfixed y GLfixed z void glTranslatexOES GLfixed x GLfixed y GLfixed z void glUniform1d GLint location GLdouble x void glUniform1dv GLint location GLsizei count const GLdouble *value void glUniform1f GLint location GLfloat v0 void glUniform1fARB GLint location GLfloat v0 void glUniform1fv GLint location GLsizei count const GLfloat *value void glUniform1fvARB GLint location GLsizei count const GLfloat *value void glUniform1i GLint location GLint v0 void glUniform1i64ARB GLint location GLint64 x void glUniform1i64NV GLint location GLint64EXT x void glUniform1i64vARB GLint location GLsizei count const GLint64 *value void glUniform1i64vNV GLint location GLsizei count const GLint64EXT *value void glUniform1iARB GLint location GLint v0 void glUniform1iv GLint location GLsizei count const GLint *value void glUniform1ivARB GLint location GLsizei count const GLint *value void glUniform1ui GLint location GLuint v0 void glUniform1ui64ARB GLint location GLuint64 x void glUniform1ui64NV GLint location GLuint64EXT x void glUniform1ui64vARB GLint location GLsizei count const GLuint64 *value void glUniform1ui64vNV GLint location GLsizei count const GLuint64EXT *value void glUniform1uiEXT GLint location GLuint v0 void glUniform1uiv GLint location GLsizei count const GLuint *value void glUniform1uivEXT GLint location GLsizei count const GLuint *value void glUniform2d GLint location GLdouble x GLdouble y void glUniform2dv GLint location GLsizei count const GLdouble *value void glUniform2f GLint location GLfloat v0 GLfloat v1 void glUniform2fARB GLint location GLfloat v0 GLfloat v1 void glUniform2fv GLint location GLsizei count const GLfloat *value void glUniform2fvARB GLint location GLsizei count const GLfloat *value void glUniform2i GLint location GLint v0 GLint v1 void glUniform2i64ARB GLint location GLint64 x GLint64 y void glUniform2i64NV GLint location GLint64EXT x GLint64EXT y void glUniform2i64vARB GLint location GLsizei count const GLint64 *value void glUniform2i64vNV GLint location GLsizei count const GLint64EXT *value void glUniform2iARB GLint location GLint v0 GLint v1 void glUniform2iv GLint location GLsizei count const GLint *value void glUniform2ivARB GLint location GLsizei count const GLint *value void glUniform2ui GLint location GLuint v0 GLuint v1 void glUniform2ui64ARB GLint location GLuint64 x GLuint64 y void glUniform2ui64NV GLint location GLuint64EXT x GLuint64EXT y void glUniform2ui64vARB GLint location GLsizei count const GLuint64 *value void glUniform2ui64vNV GLint location GLsizei count const GLuint64EXT *value void glUniform2uiEXT GLint location GLuint v0 GLuint v1 void glUniform2uiv GLint location GLsizei count const GLuint *value void glUniform2uivEXT GLint location GLsizei count const GLuint *value void glUniform3d GLint location GLdouble x GLdouble y GLdouble z void glUniform3dv GLint location GLsizei count const GLdouble *value void glUniform3f GLint location GLfloat v0 GLfloat v1 GLfloat v2 void glUniform3fARB GLint location GLfloat v0 GLfloat v1 GLfloat v2 void glUniform3fv GLint location GLsizei count const GLfloat *value void glUniform3fvARB GLint location GLsizei count const GLfloat *value void glUniform3i GLint location GLint v0 GLint v1 GLint v2 void glUniform3i64ARB GLint location GLint64 x GLint64 y GLint64 z void glUniform3i64NV GLint location GLint64EXT x GLint64EXT y GLint64EXT z void glUniform3i64vARB GLint location GLsizei count const GLint64 *value void glUniform3i64vNV GLint location GLsizei count const GLint64EXT *value void glUniform3iARB GLint location GLint v0 GLint v1 GLint v2 void glUniform3iv GLint location GLsizei count const GLint *value void glUniform3ivARB GLint location GLsizei count const GLint *value void glUniform3ui GLint location GLuint v0 GLuint v1 GLuint v2 void glUniform3ui64ARB GLint location GLuint64 x GLuint64 y GLuint64 z void glUniform3ui64NV GLint location GLuint64EXT x GLuint64EXT y GLuint64EXT z void glUniform3ui64vARB GLint location GLsizei count const GLuint64 *value void glUniform3ui64vNV GLint location GLsizei count const GLuint64EXT *value void glUniform3uiEXT GLint location GLuint v0 GLuint v1 GLuint v2 void glUniform3uiv GLint location GLsizei count const GLuint *value void glUniform3uivEXT GLint location GLsizei count const GLuint *value void glUniform4d GLint location GLdouble x GLdouble y GLdouble z GLdouble w void glUniform4dv GLint location GLsizei count const GLdouble *value void glUniform4f GLint location GLfloat v0 GLfloat v1 GLfloat v2 GLfloat v3 void glUniform4fARB GLint location GLfloat v0 GLfloat v1 GLfloat v2 GLfloat v3 void glUniform4fv GLint location GLsizei count const GLfloat *value void glUniform4fvARB GLint location GLsizei count const GLfloat *value void glUniform4i GLint location GLint v0 GLint v1 GLint v2 GLint v3 void glUniform4i64ARB GLint location GLint64 x GLint64 y GLint64 z GLint64 w void glUniform4i64NV GLint location GLint64EXT x GLint64EXT y GLint64EXT z GLint64EXT w void glUniform4i64vARB GLint location GLsizei count const GLint64 *value void glUniform4i64vNV GLint location GLsizei count const GLint64EXT *value void glUniform4iARB GLint location GLint v0 GLint v1 GLint v2 GLint v3 void glUniform4iv GLint location GLsizei count const GLint *value void glUniform4ivARB GLint location GLsizei count const GLint *value void glUniform4ui GLint location GLuint v0 GLuint v1 GLuint v2 GLuint v3 void glUniform4ui64ARB GLint location GLuint64 x GLuint64 y GLuint64 z GLuint64 w void glUniform4ui64NV GLint location GLuint64EXT x GLuint64EXT y GLuint64EXT z GLuint64EXT w void glUniform4ui64vARB GLint location GLsizei count const GLuint64 *value void glUniform4ui64vNV GLint location GLsizei count const GLuint64EXT *value void glUniform4uiEXT GLint location GLuint v0 GLuint v1 GLuint v2 GLuint v3 void glUniform4uiv GLint location GLsizei count const GLuint *value void glUniform4uivEXT GLint location GLsizei count const GLuint *value void glUniformBlockBinding GLuint program GLuint uniformBlockIndex GLuint uniformBlockBinding void glUniformBufferEXT GLuint program GLint location GLuint buffer void glUniformHandleui64ARB GLint location GLuint64 value void glUniformHandleui64NV GLint location GLuint64 value void glUniformHandleui64vARB GLint location GLsizei count const GLuint64 *value void glUniformHandleui64vNV GLint location GLsizei count const GLuint64 *value void glUniformMatrix2dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix2fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix2fvARB GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix2x3dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix2x3fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix2x3fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix2x4dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix2x4fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix2x4fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix3fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3fvARB GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3x2dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix3x2fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3x2fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3x4dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix3x4fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix3x4fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix4fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4fvARB GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4x2dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix4x2fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4x2fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4x3dv GLint location GLsizei count GLboolean transpose const GLdouble *value void glUniformMatrix4x3fv GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformMatrix4x3fvNV GLint location GLsizei count GLboolean transpose const GLfloat *value void glUniformSubroutinesuiv GLenum shadertype GLsizei count const GLuint *indices void glUniformui64NV GLint location GLuint64EXT value void glUniformui64vNV GLint location GLsizei count const GLuint64EXT *value void glUnlockArraysEXT GLboolean glUnmapBuffer GLenum target GLboolean glUnmapBufferARB GLenum target GLboolean glUnmapBufferOES GLenum target GLboolean glUnmapNamedBuffer GLuint buffer GLboolean glUnmapNamedBufferEXT GLuint buffer void glUnmapObjectBufferATI GLuint buffer void glUnmapTexture2DINTEL GLuint texture GLint level void glUpdateObjectBufferATI GLuint buffer GLuint offset GLsizei size const void *pointer GLenum preserve void glUseProgram GLuint program void glUseProgramObjectARB GLhandleARB programObj void glUseProgramStages GLuint pipeline GLbitfield stages GLuint program void glUseProgramStagesEXT GLuint pipeline GLbitfield stages GLuint program void glUseShaderProgramEXT GLenum type GLuint program void glVDPAUFiniNV void glVDPAUGetSurfaceivNV GLvdpauSurfaceNV surface GLenum pname GLsizei bufSize GLsizei *length GLint *values void glVDPAUInitNV const void *vdpDevice const void *getProcAddress GLboolean glVDPAUIsSurfaceNV GLvdpauSurfaceNV surface void glVDPAUMapSurfacesNV GLsizei numSurfaces const GLvdpauSurfaceNV *surfaces GLvdpauSurfaceNV glVDPAURegisterOutputSurfaceNV const void *vdpSurface GLenum target GLsizei numTextureNames const GLuint *textureNames GLvdpauSurfaceNV glVDPAURegisterVideoSurfaceNV const void *vdpSurface GLenum target GLsizei numTextureNames const GLuint *textureNames void glVDPAUSurfaceAccessNV GLvdpauSurfaceNV surface GLenum access void glVDPAUUnmapSurfacesNV GLsizei numSurface const GLvdpauSurfaceNV *surfaces void glVDPAUUnregisterSurfaceNV GLvdpauSurfaceNV surface void glValidateProgram GLuint program void glValidateProgramARB GLhandleARB programObj void glValidateProgramPipeline GLuint pipeline void glValidateProgramPipelineEXT GLuint pipeline void glVariantArrayObjectATI GLuint id GLenum type GLsizei stride GLuint buffer GLuint offset void glVariantPointerEXT GLuint id GLenum type GLuint stride const void *addr void glVariantbvEXT GLuint id const GLbyte *addr void glVariantdvEXT GLuint id const GLdouble *addr void glVariantfvEXT GLuint id const GLfloat *addr void glVariantivEXT GLuint id const GLint *addr void glVariantsvEXT GLuint id const GLshort *addr void glVariantubvEXT GLuint id const GLubyte *addr void glVariantuivEXT GLuint id const GLuint *addr void glVariantusvEXT GLuint id const GLushort *addr void glVertex2bOES GLbyte x GLbyte y void glVertex2bvOES const GLbyte *coords void glVertex2d GLdouble x GLdouble y void glVertex2dv const GLdouble *v void glVertex2f GLfloat x GLfloat y void glVertex2fv const GLfloat *v void glVertex2hNV GLhalfNV x GLhalfNV y void glVertex2hvNV const GLhalfNV *v void glVertex2i GLint x GLint y void glVertex2iv const GLint *v void glVertex2s GLshort x GLshort y void glVertex2sv const GLshort *v void glVertex2xOES GLfixed x void glVertex2xvOES const GLfixed *coords void glVertex3bOES GLbyte x GLbyte y GLbyte z void glVertex3bvOES const GLbyte *coords void glVertex3d GLdouble x GLdouble y GLdouble z void glVertex3dv const GLdouble *v void glVertex3f GLfloat x GLfloat y GLfloat z void glVertex3fv const GLfloat *v void glVertex3hNV GLhalfNV x GLhalfNV y GLhalfNV z void glVertex3hvNV const GLhalfNV *v void glVertex3i GLint x GLint y GLint z void glVertex3iv const GLint *v void glVertex3s GLshort x GLshort y GLshort z void glVertex3sv const GLshort *v void glVertex3xOES GLfixed x GLfixed y void glVertex3xvOES const GLfixed *coords void glVertex4bOES GLbyte x GLbyte y GLbyte z GLbyte w void glVertex4bvOES const GLbyte *coords void glVertex4d GLdouble x GLdouble y GLdouble z GLdouble w void glVertex4dv const GLdouble *v void glVertex4f GLfloat x GLfloat y GLfloat z GLfloat w void glVertex4fv const GLfloat *v void glVertex4hNV GLhalfNV x GLhalfNV y GLhalfNV z GLhalfNV w void glVertex4hvNV const GLhalfNV *v void glVertex4i GLint x GLint y GLint z GLint w void glVertex4iv const GLint *v void glVertex4s GLshort x GLshort y GLshort z GLshort w void glVertex4sv const GLshort *v void glVertex4xOES GLfixed x GLfixed y GLfixed z void glVertex4xvOES const GLfixed *coords void glVertexArrayAttribBinding GLuint vaobj GLuint attribindex GLuint bindingindex void glVertexArrayAttribFormat GLuint vaobj GLuint attribindex GLint size GLenum type GLboolean normalized GLuint relativeoffset void glVertexArrayAttribIFormat GLuint vaobj GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexArrayAttribLFormat GLuint vaobj GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexArrayBindVertexBufferEXT GLuint vaobj GLuint bindingindex GLuint buffer GLintptr offset GLsizei stride void glVertexArrayBindingDivisor GLuint vaobj GLuint bindingindex GLuint divisor void glVertexArrayColorOffsetEXT GLuint vaobj GLuint buffer GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayEdgeFlagOffsetEXT GLuint vaobj GLuint buffer GLsizei stride GLintptr offset void glVertexArrayElementBuffer GLuint vaobj GLuint buffer void glVertexArrayFogCoordOffsetEXT GLuint vaobj GLuint buffer GLenum type GLsizei stride GLintptr offset void glVertexArrayIndexOffsetEXT GLuint vaobj GLuint buffer GLenum type GLsizei stride GLintptr offset void glVertexArrayMultiTexCoordOffsetEXT GLuint vaobj GLuint buffer GLenum texunit GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayNormalOffsetEXT GLuint vaobj GLuint buffer GLenum type GLsizei stride GLintptr offset void glVertexArrayParameteriAPPLE GLenum pname GLint param void glVertexArrayRangeAPPLE GLsizei length void *pointer void glVertexArrayRangeNV GLsizei length const void *pointer void glVertexArraySecondaryColorOffsetEXT GLuint vaobj GLuint buffer GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayTexCoordOffsetEXT GLuint vaobj GLuint buffer GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayVertexAttribBindingEXT GLuint vaobj GLuint attribindex GLuint bindingindex void glVertexArrayVertexAttribDivisorEXT GLuint vaobj GLuint index GLuint divisor void glVertexArrayVertexAttribFormatEXT GLuint vaobj GLuint attribindex GLint size GLenum type GLboolean normalized GLuint relativeoffset void glVertexArrayVertexAttribIFormatEXT GLuint vaobj GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexArrayVertexAttribIOffsetEXT GLuint vaobj GLuint buffer GLuint index GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayVertexAttribLFormatEXT GLuint vaobj GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexArrayVertexAttribLOffsetEXT GLuint vaobj GLuint buffer GLuint index GLint size GLenum type GLsizei stride GLintptr offset void glVertexArrayVertexAttribOffsetEXT GLuint vaobj GLuint buffer GLuint index GLint size GLenum type GLboolean normalized GLsizei stride GLintptr offset void glVertexArrayVertexBindingDivisorEXT GLuint vaobj GLuint bindingindex GLuint divisor void glVertexArrayVertexBuffer GLuint vaobj GLuint bindingindex GLuint buffer GLintptr offset GLsizei stride void glVertexArrayVertexBuffers GLuint vaobj GLuint first GLsizei count const GLuint *buffers const GLintptr *offsets const GLsizei *strides void glVertexArrayVertexOffsetEXT GLuint vaobj GLuint buffer GLint size GLenum type GLsizei stride GLintptr offset void glVertexAttrib1d GLuint index GLdouble x void glVertexAttrib1dARB GLuint index GLdouble x void glVertexAttrib1dNV GLuint index GLdouble x void glVertexAttrib1dv GLuint index const GLdouble *v void glVertexAttrib1dvARB GLuint index const GLdouble *v void glVertexAttrib1dvNV GLuint index const GLdouble *v void glVertexAttrib1f GLuint index GLfloat x void glVertexAttrib1fARB GLuint index GLfloat x void glVertexAttrib1fNV GLuint index GLfloat x void glVertexAttrib1fv GLuint index const GLfloat *v void glVertexAttrib1fvARB GLuint index const GLfloat *v void glVertexAttrib1fvNV GLuint index const GLfloat *v void glVertexAttrib1hNV GLuint index GLhalfNV x void glVertexAttrib1hvNV GLuint index const GLhalfNV *v void glVertexAttrib1s GLuint index GLshort x void glVertexAttrib1sARB GLuint index GLshort x void glVertexAttrib1sNV GLuint index GLshort x void glVertexAttrib1sv GLuint index const GLshort *v void glVertexAttrib1svARB GLuint index const GLshort *v void glVertexAttrib1svNV GLuint index const GLshort *v void glVertexAttrib2d GLuint index GLdouble x GLdouble y void glVertexAttrib2dARB GLuint index GLdouble x GLdouble y void glVertexAttrib2dNV GLuint index GLdouble x GLdouble y void glVertexAttrib2dv GLuint index const GLdouble *v void glVertexAttrib2dvARB GLuint index const GLdouble *v void glVertexAttrib2dvNV GLuint index const GLdouble *v void glVertexAttrib2f GLuint index GLfloat x GLfloat y void glVertexAttrib2fARB GLuint index GLfloat x GLfloat y void glVertexAttrib2fNV GLuint index GLfloat x GLfloat y void glVertexAttrib2fv GLuint index const GLfloat *v void glVertexAttrib2fvARB GLuint index const GLfloat *v void glVertexAttrib2fvNV GLuint index const GLfloat *v void glVertexAttrib2hNV GLuint index GLhalfNV x GLhalfNV y void glVertexAttrib2hvNV GLuint index const GLhalfNV *v void glVertexAttrib2s GLuint index GLshort x GLshort y void glVertexAttrib2sARB GLuint index GLshort x GLshort y void glVertexAttrib2sNV GLuint index GLshort x GLshort y void glVertexAttrib2sv GLuint index const GLshort *v void glVertexAttrib2svARB GLuint index const GLshort *v void glVertexAttrib2svNV GLuint index const GLshort *v void glVertexAttrib3d GLuint index GLdouble x GLdouble y GLdouble z void glVertexAttrib3dARB GLuint index GLdouble x GLdouble y GLdouble z void glVertexAttrib3dNV GLuint index GLdouble x GLdouble y GLdouble z void glVertexAttrib3dv GLuint index const GLdouble *v void glVertexAttrib3dvARB GLuint index const GLdouble *v void glVertexAttrib3dvNV GLuint index const GLdouble *v void glVertexAttrib3f GLuint index GLfloat x GLfloat y GLfloat z void glVertexAttrib3fARB GLuint index GLfloat x GLfloat y GLfloat z void glVertexAttrib3fNV GLuint index GLfloat x GLfloat y GLfloat z void glVertexAttrib3fv GLuint index const GLfloat *v void glVertexAttrib3fvARB GLuint index const GLfloat *v void glVertexAttrib3fvNV GLuint index const GLfloat *v void glVertexAttrib3hNV GLuint index GLhalfNV x GLhalfNV y GLhalfNV z void glVertexAttrib3hvNV GLuint index const GLhalfNV *v void glVertexAttrib3s GLuint index GLshort x GLshort y GLshort z void glVertexAttrib3sARB GLuint index GLshort x GLshort y GLshort z void glVertexAttrib3sNV GLuint index GLshort x GLshort y GLshort z void glVertexAttrib3sv GLuint index const GLshort *v void glVertexAttrib3svARB GLuint index const GLshort *v void glVertexAttrib3svNV GLuint index const GLshort *v void glVertexAttrib4Nbv GLuint index const GLbyte *v void glVertexAttrib4NbvARB GLuint index const GLbyte *v void glVertexAttrib4Niv GLuint index const GLint *v void glVertexAttrib4NivARB GLuint index const GLint *v void glVertexAttrib4Nsv GLuint index const GLshort *v void glVertexAttrib4NsvARB GLuint index const GLshort *v void glVertexAttrib4Nub GLuint index GLubyte x GLubyte y GLubyte z GLubyte w void glVertexAttrib4NubARB GLuint index GLubyte x GLubyte y GLubyte z GLubyte w void glVertexAttrib4Nubv GLuint index const GLubyte *v void glVertexAttrib4NubvARB GLuint index const GLubyte *v void glVertexAttrib4Nuiv GLuint index const GLuint *v void glVertexAttrib4NuivARB GLuint index const GLuint *v void glVertexAttrib4Nusv GLuint index const GLushort *v void glVertexAttrib4NusvARB GLuint index const GLushort *v void glVertexAttrib4bv GLuint index const GLbyte *v void glVertexAttrib4bvARB GLuint index const GLbyte *v void glVertexAttrib4d GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glVertexAttrib4dARB GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glVertexAttrib4dNV GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glVertexAttrib4dv GLuint index const GLdouble *v void glVertexAttrib4dvARB GLuint index const GLdouble *v void glVertexAttrib4dvNV GLuint index const GLdouble *v void glVertexAttrib4f GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glVertexAttrib4fARB GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glVertexAttrib4fNV GLuint index GLfloat x GLfloat y GLfloat z GLfloat w void glVertexAttrib4fv GLuint index const GLfloat *v void glVertexAttrib4fvARB GLuint index const GLfloat *v void glVertexAttrib4fvNV GLuint index const GLfloat *v void glVertexAttrib4hNV GLuint index GLhalfNV x GLhalfNV y GLhalfNV z GLhalfNV w void glVertexAttrib4hvNV GLuint index const GLhalfNV *v void glVertexAttrib4iv GLuint index const GLint *v void glVertexAttrib4ivARB GLuint index const GLint *v void glVertexAttrib4s GLuint index GLshort x GLshort y GLshort z GLshort w void glVertexAttrib4sARB GLuint index GLshort x GLshort y GLshort z GLshort w void glVertexAttrib4sNV GLuint index GLshort x GLshort y GLshort z GLshort w void glVertexAttrib4sv GLuint index const GLshort *v void glVertexAttrib4svARB GLuint index const GLshort *v void glVertexAttrib4svNV GLuint index const GLshort *v void glVertexAttrib4ubNV GLuint index GLubyte x GLubyte y GLubyte z GLubyte w void glVertexAttrib4ubv GLuint index const GLubyte *v void glVertexAttrib4ubvARB GLuint index const GLubyte *v void glVertexAttrib4ubvNV GLuint index const GLubyte *v void glVertexAttrib4uiv GLuint index const GLuint *v void glVertexAttrib4uivARB GLuint index const GLuint *v void glVertexAttrib4usv GLuint index const GLushort *v void glVertexAttrib4usvARB GLuint index const GLushort *v void glVertexAttribArrayObjectATI GLuint index GLint size GLenum type GLboolean normalized GLsizei stride GLuint buffer GLuint offset void glVertexAttribBinding GLuint attribindex GLuint bindingindex void glVertexAttribDivisor GLuint index GLuint divisor void glVertexAttribDivisorANGLE GLuint index GLuint divisor void glVertexAttribDivisorARB GLuint index GLuint divisor void glVertexAttribDivisorEXT GLuint index GLuint divisor void glVertexAttribDivisorNV GLuint index GLuint divisor void glVertexAttribFormat GLuint attribindex GLint size GLenum type GLboolean normalized GLuint relativeoffset void glVertexAttribFormatNV GLuint index GLint size GLenum type GLboolean normalized GLsizei stride void glVertexAttribI1i GLuint index GLint x void glVertexAttribI1iEXT GLuint index GLint x void glVertexAttribI1iv GLuint index const GLint *v void glVertexAttribI1ivEXT GLuint index const GLint *v void glVertexAttribI1ui GLuint index GLuint x void glVertexAttribI1uiEXT GLuint index GLuint x void glVertexAttribI1uiv GLuint index const GLuint *v void glVertexAttribI1uivEXT GLuint index const GLuint *v void glVertexAttribI2i GLuint index GLint x GLint y void glVertexAttribI2iEXT GLuint index GLint x GLint y void glVertexAttribI2iv GLuint index const GLint *v void glVertexAttribI2ivEXT GLuint index const GLint *v void glVertexAttribI2ui GLuint index GLuint x GLuint y void glVertexAttribI2uiEXT GLuint index GLuint x GLuint y void glVertexAttribI2uiv GLuint index const GLuint *v void glVertexAttribI2uivEXT GLuint index const GLuint *v void glVertexAttribI3i GLuint index GLint x GLint y GLint z void glVertexAttribI3iEXT GLuint index GLint x GLint y GLint z void glVertexAttribI3iv GLuint index const GLint *v void glVertexAttribI3ivEXT GLuint index const GLint *v void glVertexAttribI3ui GLuint index GLuint x GLuint y GLuint z void glVertexAttribI3uiEXT GLuint index GLuint x GLuint y GLuint z void glVertexAttribI3uiv GLuint index const GLuint *v void glVertexAttribI3uivEXT GLuint index const GLuint *v void glVertexAttribI4bv GLuint index const GLbyte *v void glVertexAttribI4bvEXT GLuint index const GLbyte *v void glVertexAttribI4i GLuint index GLint x GLint y GLint z GLint w void glVertexAttribI4iEXT GLuint index GLint x GLint y GLint z GLint w void glVertexAttribI4iv GLuint index const GLint *v void glVertexAttribI4ivEXT GLuint index const GLint *v void glVertexAttribI4sv GLuint index const GLshort *v void glVertexAttribI4svEXT GLuint index const GLshort *v void glVertexAttribI4ubv GLuint index const GLubyte *v void glVertexAttribI4ubvEXT GLuint index const GLubyte *v void glVertexAttribI4ui GLuint index GLuint x GLuint y GLuint z GLuint w void glVertexAttribI4uiEXT GLuint index GLuint x GLuint y GLuint z GLuint w void glVertexAttribI4uiv GLuint index const GLuint *v void glVertexAttribI4uivEXT GLuint index const GLuint *v void glVertexAttribI4usv GLuint index const GLushort *v void glVertexAttribI4usvEXT GLuint index const GLushort *v void glVertexAttribIFormat GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexAttribIFormatNV GLuint index GLint size GLenum type GLsizei stride void glVertexAttribIPointer GLuint index GLint size GLenum type GLsizei stride const void *pointer void glVertexAttribIPointerEXT GLuint index GLint size GLenum type GLsizei stride const void *pointer void glVertexAttribL1d GLuint index GLdouble x void glVertexAttribL1dEXT GLuint index GLdouble x void glVertexAttribL1dv GLuint index const GLdouble *v void glVertexAttribL1dvEXT GLuint index const GLdouble *v void glVertexAttribL1i64NV GLuint index GLint64EXT x void glVertexAttribL1i64vNV GLuint index const GLint64EXT *v void glVertexAttribL1ui64ARB GLuint index GLuint64EXT x void glVertexAttribL1ui64NV GLuint index GLuint64EXT x void glVertexAttribL1ui64vARB GLuint index const GLuint64EXT *v void glVertexAttribL1ui64vNV GLuint index const GLuint64EXT *v void glVertexAttribL2d GLuint index GLdouble x GLdouble y void glVertexAttribL2dEXT GLuint index GLdouble x GLdouble y void glVertexAttribL2dv GLuint index const GLdouble *v void glVertexAttribL2dvEXT GLuint index const GLdouble *v void glVertexAttribL2i64NV GLuint index GLint64EXT x GLint64EXT y void glVertexAttribL2i64vNV GLuint index const GLint64EXT *v void glVertexAttribL2ui64NV GLuint index GLuint64EXT x GLuint64EXT y void glVertexAttribL2ui64vNV GLuint index const GLuint64EXT *v void glVertexAttribL3d GLuint index GLdouble x GLdouble y GLdouble z void glVertexAttribL3dEXT GLuint index GLdouble x GLdouble y GLdouble z void glVertexAttribL3dv GLuint index const GLdouble *v void glVertexAttribL3dvEXT GLuint index const GLdouble *v void glVertexAttribL3i64NV GLuint index GLint64EXT x GLint64EXT y GLint64EXT z void glVertexAttribL3i64vNV GLuint index const GLint64EXT *v void glVertexAttribL3ui64NV GLuint index GLuint64EXT x GLuint64EXT y GLuint64EXT z void glVertexAttribL3ui64vNV GLuint index const GLuint64EXT *v void glVertexAttribL4d GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glVertexAttribL4dEXT GLuint index GLdouble x GLdouble y GLdouble z GLdouble w void glVertexAttribL4dv GLuint index const GLdouble *v void glVertexAttribL4dvEXT GLuint index const GLdouble *v void glVertexAttribL4i64NV GLuint index GLint64EXT x GLint64EXT y GLint64EXT z GLint64EXT w void glVertexAttribL4i64vNV GLuint index const GLint64EXT *v void glVertexAttribL4ui64NV GLuint index GLuint64EXT x GLuint64EXT y GLuint64EXT z GLuint64EXT w void glVertexAttribL4ui64vNV GLuint index const GLuint64EXT *v void glVertexAttribLFormat GLuint attribindex GLint size GLenum type GLuint relativeoffset void glVertexAttribLFormatNV GLuint index GLint size GLenum type GLsizei stride void glVertexAttribLPointer GLuint index GLint size GLenum type GLsizei stride const void *pointer void glVertexAttribLPointerEXT GLuint index GLint size GLenum type GLsizei stride const void *pointer void glVertexAttribP1ui GLuint index GLenum type GLboolean normalized GLuint value void glVertexAttribP1uiv GLuint index GLenum type GLboolean normalized const GLuint *value void glVertexAttribP2ui GLuint index GLenum type GLboolean normalized GLuint value void glVertexAttribP2uiv GLuint index GLenum type GLboolean normalized const GLuint *value void glVertexAttribP3ui GLuint index GLenum type GLboolean normalized GLuint value void glVertexAttribP3uiv GLuint index GLenum type GLboolean normalized const GLuint *value void glVertexAttribP4ui GLuint index GLenum type GLboolean normalized GLuint value void glVertexAttribP4uiv GLuint index GLenum type GLboolean normalized const GLuint *value void glVertexAttribParameteriAMD GLuint index GLenum pname GLint param void glVertexAttribPointer GLuint index GLint size GLenum type GLboolean normalized GLsizei stride const void *pointer void glVertexAttribPointerARB GLuint index GLint size GLenum type GLboolean normalized GLsizei stride const void *pointer void glVertexAttribPointerNV GLuint index GLint fsize GLenum type GLsizei stride const void *pointer void glVertexAttribs1dvNV GLuint index GLsizei count const GLdouble *v void glVertexAttribs1fvNV GLuint index GLsizei count const GLfloat *v void glVertexAttribs1hvNV GLuint index GLsizei n const GLhalfNV *v void glVertexAttribs1svNV GLuint index GLsizei count const GLshort *v void glVertexAttribs2dvNV GLuint index GLsizei count const GLdouble *v void glVertexAttribs2fvNV GLuint index GLsizei count const GLfloat *v void glVertexAttribs2hvNV GLuint index GLsizei n const GLhalfNV *v void glVertexAttribs2svNV GLuint index GLsizei count const GLshort *v void glVertexAttribs3dvNV GLuint index GLsizei count const GLdouble *v void glVertexAttribs3fvNV GLuint index GLsizei count const GLfloat *v void glVertexAttribs3hvNV GLuint index GLsizei n const GLhalfNV *v void glVertexAttribs3svNV GLuint index GLsizei count const GLshort *v void glVertexAttribs4dvNV GLuint index GLsizei count const GLdouble *v void glVertexAttribs4fvNV GLuint index GLsizei count const GLfloat *v void glVertexAttribs4hvNV GLuint index GLsizei n const GLhalfNV *v void glVertexAttribs4svNV GLuint index GLsizei count const GLshort *v void glVertexAttribs4ubvNV GLuint index GLsizei count const GLubyte *v void glVertexBindingDivisor GLuint bindingindex GLuint divisor void glVertexBlendARB GLint count void glVertexBlendEnvfATI GLenum pname GLfloat param void glVertexBlendEnviATI GLenum pname GLint param void glVertexFormatNV GLint size GLenum type GLsizei stride void glVertexP2ui GLenum type GLuint value void glVertexP2uiv GLenum type const GLuint *value void glVertexP3ui GLenum type GLuint value void glVertexP3uiv GLenum type const GLuint *value void glVertexP4ui GLenum type GLuint value void glVertexP4uiv GLenum type const GLuint *value void glVertexPointer GLint size GLenum type GLsizei stride const void *pointer void glVertexPointerEXT GLint size GLenum type GLsizei stride GLsizei count const void *pointer void glVertexPointerListIBM GLint size GLenum type GLint stride const void **pointer GLint ptrstride void glVertexPointervINTEL GLint size GLenum type const void **pointer void glVertexStream1dATI GLenum stream GLdouble x void glVertexStream1dvATI GLenum stream const GLdouble *coords void glVertexStream1fATI GLenum stream GLfloat x void glVertexStream1fvATI GLenum stream const GLfloat *coords void glVertexStream1iATI GLenum stream GLint x void glVertexStream1ivATI GLenum stream const GLint *coords void glVertexStream1sATI GLenum stream GLshort x void glVertexStream1svATI GLenum stream const GLshort *coords void glVertexStream2dATI GLenum stream GLdouble x GLdouble y void glVertexStream2dvATI GLenum stream const GLdouble *coords void glVertexStream2fATI GLenum stream GLfloat x GLfloat y void glVertexStream2fvATI GLenum stream const GLfloat *coords void glVertexStream2iATI GLenum stream GLint x GLint y void glVertexStream2ivATI GLenum stream const GLint *coords void glVertexStream2sATI GLenum stream GLshort x GLshort y void glVertexStream2svATI GLenum stream const GLshort *coords void glVertexStream3dATI GLenum stream GLdouble x GLdouble y GLdouble z void glVertexStream3dvATI GLenum stream const GLdouble *coords void glVertexStream3fATI GLenum stream GLfloat x GLfloat y GLfloat z void glVertexStream3fvATI GLenum stream const GLfloat *coords void glVertexStream3iATI GLenum stream GLint x GLint y GLint z void glVertexStream3ivATI GLenum stream const GLint *coords void glVertexStream3sATI GLenum stream GLshort x GLshort y GLshort z void glVertexStream3svATI GLenum stream const GLshort *coords void glVertexStream4dATI GLenum stream GLdouble x GLdouble y GLdouble z GLdouble w void glVertexStream4dvATI GLenum stream const GLdouble *coords void glVertexStream4fATI GLenum stream GLfloat x GLfloat y GLfloat z GLfloat w void glVertexStream4fvATI GLenum stream const GLfloat *coords void glVertexStream4iATI GLenum stream GLint x GLint y GLint z GLint w void glVertexStream4ivATI GLenum stream const GLint *coords void glVertexStream4sATI GLenum stream GLshort x GLshort y GLshort z GLshort w void glVertexStream4svATI GLenum stream const GLshort *coords void glVertexWeightPointerEXT GLint size GLenum type GLsizei stride const void *pointer void glVertexWeightfEXT GLfloat weight void glVertexWeightfvEXT const GLfloat *weight void glVertexWeighthNV GLhalfNV weight void glVertexWeighthvNV const GLhalfNV *weight GLenum glVideoCaptureNV GLuint video_capture_slot GLuint *sequence_num GLuint64EXT *capture_time void glVideoCaptureStreamParameterdvNV GLuint video_capture_slot GLuint stream GLenum pname const GLdouble *params void glVideoCaptureStreamParameterfvNV GLuint video_capture_slot GLuint stream GLenum pname const GLfloat *params void glVideoCaptureStreamParameterivNV GLuint video_capture_slot GLuint stream GLenum pname const GLint *params void glViewport GLint x GLint y GLsizei width GLsizei height void glViewportArrayv GLuint first GLsizei count const GLfloat *v void glViewportArrayvNV GLuint first GLsizei count const GLfloat *v void glViewportIndexedf GLuint index GLfloat x GLfloat y GLfloat w GLfloat h void glViewportIndexedfNV GLuint index GLfloat x GLfloat y GLfloat w GLfloat h void glViewportIndexedfv GLuint index const GLfloat *v void glViewportIndexedfvNV GLuint index const GLfloat *v void glWaitSync GLsync sync GLbitfield flags GLuint64 timeout void glWaitSyncAPPLE GLsync sync GLbitfield flags GLuint64 timeout void glWeightPathsNV GLuint resultPath GLsizei numPaths const GLuint *paths const GLfloat *weights void glWeightPointerARB GLint size GLenum type GLsizei stride const void *pointer void glWeightPointerOES GLint size GLenum type GLsizei stride const void *pointer void glWeightbvARB GLint size const GLbyte *weights void glWeightdvARB GLint size const GLdouble *weights void glWeightfvARB GLint size const GLfloat *weights void glWeightivARB GLint size const GLint *weights void glWeightsvARB GLint size const GLshort *weights void glWeightubvARB GLint size const GLubyte *weights void glWeightuivARB GLint size const GLuint *weights void glWeightusvARB GLint size const GLushort *weights void glWindowPos2d GLdouble x GLdouble y void glWindowPos2dARB GLdouble x GLdouble y void glWindowPos2dMESA GLdouble x GLdouble y void glWindowPos2dv const GLdouble *v void glWindowPos2dvARB const GLdouble *v void glWindowPos2dvMESA const GLdouble *v void glWindowPos2f GLfloat x GLfloat y void glWindowPos2fARB GLfloat x GLfloat y void glWindowPos2fMESA GLfloat x GLfloat y void glWindowPos2fv const GLfloat *v void glWindowPos2fvARB const GLfloat *v void glWindowPos2fvMESA const GLfloat *v void glWindowPos2i GLint x GLint y void glWindowPos2iARB GLint x GLint y void glWindowPos2iMESA GLint x GLint y void glWindowPos2iv const GLint *v void glWindowPos2ivARB const GLint *v void glWindowPos2ivMESA const GLint *v void glWindowPos2s GLshort x GLshort y void glWindowPos2sARB GLshort x GLshort y void glWindowPos2sMESA GLshort x GLshort y void glWindowPos2sv const GLshort *v void glWindowPos2svARB const GLshort *v void glWindowPos2svMESA const GLshort *v void glWindowPos3d GLdouble x GLdouble y GLdouble z void glWindowPos3dARB GLdouble x GLdouble y GLdouble z void glWindowPos3dMESA GLdouble x GLdouble y GLdouble z void glWindowPos3dv const GLdouble *v void glWindowPos3dvARB const GLdouble *v void glWindowPos3dvMESA const GLdouble *v void glWindowPos3f GLfloat x GLfloat y GLfloat z void glWindowPos3fARB GLfloat x GLfloat y GLfloat z void glWindowPos3fMESA GLfloat x GLfloat y GLfloat z void glWindowPos3fv const GLfloat *v void glWindowPos3fvARB const GLfloat *v void glWindowPos3fvMESA const GLfloat *v void glWindowPos3i GLint x GLint y GLint z void glWindowPos3iARB GLint x GLint y GLint z void glWindowPos3iMESA GLint x GLint y GLint z void glWindowPos3iv const GLint *v void glWindowPos3ivARB const GLint *v void glWindowPos3ivMESA const GLint *v void glWindowPos3s GLshort x GLshort y GLshort z void glWindowPos3sARB GLshort x GLshort y GLshort z void glWindowPos3sMESA GLshort x GLshort y GLshort z void glWindowPos3sv const GLshort *v void glWindowPos3svARB const GLshort *v void glWindowPos3svMESA const GLshort *v void glWindowPos4dMESA GLdouble x GLdouble y GLdouble z GLdouble w void glWindowPos4dvMESA const GLdouble *v void glWindowPos4fMESA GLfloat x GLfloat y GLfloat z GLfloat w void glWindowPos4fvMESA const GLfloat *v void glWindowPos4iMESA GLint x GLint y GLint z GLint w void glWindowPos4ivMESA const GLint *v void glWindowPos4sMESA GLshort x GLshort y GLshort z GLshort w void glWindowPos4svMESA const GLshort *v void glWriteMaskEXT GLuint res GLuint in GLenum outX GLenum outY GLenum outZ GLenum outW opengl/tools/glgen2/registry/reg.py0100755 0000000 0000000 00000151740 13077405420 016423 0ustar000000000 0000000 #!/usr/bin/python3 -i # # Copyright (c) 2013-2014 The Khronos Group Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and/or associated documentation files (the # "Materials"), to deal in the Materials without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Materials, and to # permit persons to whom the Materials are furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Materials. # # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. import io,os,re,string,sys from lxml import etree def write( *args, **kwargs ): file = kwargs.pop('file',sys.stdout) end = kwargs.pop( 'end','\n') file.write( ' '.join([str(arg) for arg in args]) ) file.write( end ) # noneStr - returns string argument, or "" if argument is None. # Used in converting lxml Elements into text. # str - string to convert def noneStr(str): if (str): return str else: return "" # matchAPIProfile - returns whether an API and profile # being generated matches an element's profile # api - string naming the API to match # profile - string naming the profile to match # elem - Element which (may) have 'api' and 'profile' # attributes to match to. # If a tag is not present in the Element, the corresponding API # or profile always matches. # Otherwise, the tag must exactly match the API or profile. # Thus, if 'profile' = core: # with no attribute will match # will match # will not match # Possible match conditions: # Requested Element # Profile Profile # --------- -------- # None None Always matches # 'string' None Always matches # None 'string' Does not match. Can't generate multiple APIs # or profiles, so if an API/profile constraint # is present, it must be asked for explicitly. # 'string' 'string' Strings must match # # ** In the future, we will allow regexes for the attributes, # not just strings, so that api="^(gl|gles2)" will match. Even # this isn't really quite enough, we might prefer something # like "gl(core)|gles1(common-lite)". def matchAPIProfile(api, profile, elem): """Match a requested API & profile name to a api & profile attributes of an Element""" match = True # Match 'api', if present if ('api' in elem.attrib): if (api == None): raise UserWarning("No API requested, but 'api' attribute is present with value '" + elem.get('api') + "'") elif (api != elem.get('api')): # Requested API doesn't match attribute return False if ('profile' in elem.attrib): if (profile == None): raise UserWarning("No profile requested, but 'profile' attribute is present with value '" + elem.get('profile') + "'") elif (profile != elem.get('profile')): # Requested profile doesn't match attribute return False return True # BaseInfo - base class for information about a registry feature # (type/group/enum/command/API/extension). # required - should this feature be defined during header generation # (has it been removed by a profile or version)? # declared - has this feature been defined already? # elem - lxml.etree Element for this feature # resetState() - reset required/declared to initial values. Used # prior to generating a new API interface. class BaseInfo: """Represents the state of a registry feature, used during API generation""" def __init__(self, elem): self.required = False self.declared = False self.elem = elem def resetState(self): self.required = False self.declared = False # TypeInfo - registry information about a type. No additional state # beyond BaseInfo is required. class TypeInfo(BaseInfo): """Represents the state of a registry type""" def __init__(self, elem): BaseInfo.__init__(self, elem) # GroupInfo - registry information about a group of related enums. # enums - dictionary of enum names which are in the group class GroupInfo(BaseInfo): """Represents the state of a registry enumerant group""" def __init__(self, elem): BaseInfo.__init__(self, elem) self.enums = {} # EnumInfo - registry information about an enum # type - numeric type of the value of the tag # ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 ) class EnumInfo(BaseInfo): """Represents the state of a registry enum""" def __init__(self, elem): BaseInfo.__init__(self, elem) self.type = elem.get('type') if (self.type == None): self.type = '' # CmdInfo - registry information about a command # glxtype - type of GLX protocol { None, 'render', 'single', 'vendor' } # glxopcode - GLX protocol opcode { None, number } # glxequiv - equivalent command at GLX dispatch level { None, string } # vecequiv - equivalent vector form of a command taking multiple scalar args # { None, string } class CmdInfo(BaseInfo): """Represents the state of a registry command""" def __init__(self, elem): BaseInfo.__init__(self, elem) self.glxtype = None self.glxopcode = None self.glxequiv = None self.vecequiv = None # FeatureInfo - registry information about an API # or # name - feature name string (e.g. 'GL_ARB_multitexture') # number - feature version number (e.g. 1.2). # features are unversioned and assigned version number 0. # category - category, e.g. VERSION or ARB/KHR/OES/ETC/vendor # emit - has this feature been defined already? class FeatureInfo(BaseInfo): """Represents the state of an API feature (version/extension)""" def __init__(self, elem): BaseInfo.__init__(self, elem) self.name = elem.get('name') # Determine element category (vendor). Only works # for elements. if (elem.tag == 'feature'): self.category = 'VERSION' self.number = elem.get('number') else: self.category = self.name.split('_', 2)[1] self.number = "0" self.emit = False # Primary sort key for regSortFeatures. # Sorts by category of the feature name string: # Core API features (those defined with a tag) # ARB/KHR/OES (Khronos extensions) # other (EXT/vendor extensions) def regSortCategoryKey(feature): if (feature.elem.tag == 'feature'): return 0 elif (feature.category == 'ARB' or feature.category == 'KHR' or feature.category == 'OES'): return 1 else: return 2 # Secondary sort key for regSortFeatures. # Sorts by extension name. def regSortNameKey(feature): return feature.name # Tertiary sort key for regSortFeatures. # Sorts by feature version number. # elements all have version number "0" def regSortNumberKey(feature): return feature.number # regSortFeatures - default sort procedure for features. # Sorts by primary key of feature category, # then by feature name within the category, # then by version number def regSortFeatures(featureList): featureList.sort(key = regSortNumberKey) featureList.sort(key = regSortNameKey) featureList.sort(key = regSortCategoryKey) # GeneratorOptions - base class for options used during header production # These options are target language independent, and used by # Registry.apiGen() and by base OutputGenerator objects. # # Members # filename - name of file to generate, or None to write to stdout. # apiname - string matching 'apiname' attribute, e.g. 'gl'. # profile - string specifying API profile , e.g. 'core', or None. # versions - regex matching API versions to process interfaces for. # Normally '.*' or '[0-9]\.[0-9]' to match all defined versions. # emitversions - regex matching API versions to actually emit # interfaces for (though all requested versions are considered # when deciding which interfaces to generate). For GL 4.3 glext.h, # this might be '1\.[2-5]|[2-4]\.[0-9]'. # defaultExtensions - If not None, a string which must in its # entirety match the pattern in the "supported" attribute of # the . Defaults to None. Usually the same as apiname. # addExtensions - regex matching names of additional extensions # to include. Defaults to None. # removeExtensions - regex matching names of extensions to # remove (after defaultExtensions and addExtensions). Defaults # to None. # sortProcedure - takes a list of FeatureInfo objects and sorts # them in place to a preferred order in the generated output. # Default is core API versions, ARB/KHR/OES extensions, all # other extensions, alphabetically within each group. # The regex patterns can be None or empty, in which case they match # nothing. class GeneratorOptions: """Represents options during header production from an API registry""" def __init__(self, filename = None, apiname = None, profile = None, versions = '.*', emitversions = '.*', defaultExtensions = None, addExtensions = None, removeExtensions = None, sortProcedure = regSortFeatures): self.filename = filename self.apiname = apiname self.profile = profile self.versions = self.emptyRegex(versions) self.emitversions = self.emptyRegex(emitversions) self.defaultExtensions = defaultExtensions self.addExtensions = self.emptyRegex(addExtensions) self.removeExtensions = self.emptyRegex(removeExtensions) self.sortProcedure = sortProcedure # # Substitute a regular expression which matches no version # or extension names for None or the empty string. def emptyRegex(self,pat): if (pat == None or pat == ''): return '_nomatch_^' else: return pat # CGeneratorOptions - subclass of GeneratorOptions. # # Adds options used by COutputGenerator objects during C language header # generation. # # Additional members # prefixText - list of strings to prefix generated header with # (usually a copyright statement + calling convention macros). # protectFile - True if multiple inclusion protection should be # generated (based on the filename) around the entire header. # protectFeature - True if #ifndef..#endif protection should be # generated around a feature interface in the header file. # genFuncPointers - True if function pointer typedefs should be # generated # protectProto - True if #ifdef..#endif protection should be # generated around prototype declarations # protectProtoStr - #ifdef symbol to use around prototype # declarations, if protected # apicall - string to use for the function declaration prefix, # such as APICALL on Windows. # apientry - string to use for the calling convention macro, # in typedefs, such as APIENTRY. # apientryp - string to use for the calling convention macro # in function pointer typedefs, such as APIENTRYP. class CGeneratorOptions(GeneratorOptions): """Represents options during C header production from an API registry""" def __init__(self, filename = None, apiname = None, profile = None, versions = '.*', emitversions = '.*', defaultExtensions = None, addExtensions = None, removeExtensions = None, sortProcedure = regSortFeatures, prefixText = "", genFuncPointers = True, protectFile = True, protectFeature = True, protectProto = True, protectProtoStr = True, apicall = '', apientry = '', apientryp = ''): GeneratorOptions.__init__(self, filename, apiname, profile, versions, emitversions, defaultExtensions, addExtensions, removeExtensions, sortProcedure) self.prefixText = prefixText self.genFuncPointers = genFuncPointers self.protectFile = protectFile self.protectFeature = protectFeature self.protectProto = protectProto self.protectProtoStr = protectProtoStr self.apicall = apicall self.apientry = apientry self.apientryp = apientryp # OutputGenerator - base class for generating API interfaces. # Manages basic logic, logging, and output file control # Derived classes actually generate formatted output. # # ---- methods ---- # OutputGenerator(errFile, warnFile, diagFile) # errFile, warnFile, diagFile - file handles to write errors, # warnings, diagnostics to. May be None to not write. # logMsg(level, *args) - log messages of different categories # level - 'error', 'warn', or 'diag'. 'error' will also # raise a UserWarning exception # *args - print()-style arguments # beginFile(genOpts) - start a new interface file # genOpts - GeneratorOptions controlling what's generated and how # endFile() - finish an interface file, closing it when done # beginFeature(interface, emit) - write interface for a feature # and tag generated features as having been done. # interface - element for the / to generate # emit - actually write to the header only when True # endFeature() - finish an interface. # genType(typeinfo,name) - generate interface for a type # typeinfo - TypeInfo for a type # genEnum(enuminfo, name) - generate interface for an enum # enuminfo - EnumInfo for an enum # name - enum name # genCmd(cmdinfo) - generate interface for a command # cmdinfo - CmdInfo for a command class OutputGenerator: """Generate specified API interfaces in a specific style, such as a C header""" def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): self.outFile = None self.errFile = errFile self.warnFile = warnFile self.diagFile = diagFile # Internal state self.featureName = None self.genOpts = None # # logMsg - write a message of different categories to different # destinations. # level - # 'diag' (diagnostic, voluminous) # 'warn' (warning) # 'error' (fatal error - raises exception after logging) # *args - print()-style arguments to direct to corresponding log def logMsg(self, level, *args): """Log a message at the given level. Can be ignored or log to a file""" if (level == 'error'): strfile = io.StringIO() write('ERROR:', *args, file=strfile) if (self.errFile != None): write(strfile.getvalue(), file=self.errFile) raise UserWarning(strfile.getvalue()) elif (level == 'warn'): if (self.warnFile != None): write('WARNING:', *args, file=self.warnFile) elif (level == 'diag'): if (self.diagFile != None): write('DIAG:', *args, file=self.diagFile) else: raise UserWarning( '*** FATAL ERROR in Generator.logMsg: unknown level:' + level) # def beginFile(self, genOpts): self.genOpts = genOpts # # Open specified output file. Not done in constructor since a # Generator can be used without writing to a file. if (self.genOpts.filename != None): self.outFile = open(self.genOpts.filename, 'w') else: self.outFile = sys.stdout def endFile(self): self.errFile and self.errFile.flush() self.warnFile and self.warnFile.flush() self.diagFile and self.diagFile.flush() self.outFile.flush() if (self.outFile != sys.stdout and self.outFile != sys.stderr): self.outFile.close() self.genOpts = None # def beginFeature(self, interface, emit): self.emit = emit self.featureName = interface.get('name') # If there's an additional 'protect' attribute in the feature, save it self.featureExtraProtect = interface.get('protect') def endFeature(self): # Derived classes responsible for emitting feature self.featureName = None self.featureExtraProtect = None # # Type generation def genType(self, typeinfo, name): if (self.featureName == None): raise UserWarning('Attempt to generate type', name, 'when not in feature') # # Enumerant generation def genEnum(self, enuminfo, name): if (self.featureName == None): raise UserWarning('Attempt to generate enum', name, 'when not in feature') # # Command generation def genCmd(self, cmd, name): if (self.featureName == None): raise UserWarning('Attempt to generate command', name, 'when not in feature') # COutputGenerator - subclass of OutputGenerator. # Generates C-language API interfaces. # # ---- methods ---- # COutputGenerator(errFile, warnFile, diagFile) - args as for # OutputGenerator. Defines additional internal state. # makeCDecls(cmd) - return C prototype and function pointer typedef for a # Element, as a list of two strings # cmd - Element for the # newline() - print a newline to the output file (utility function) # ---- methods overriding base class ---- # beginFile(genOpts) # endFile() # beginFeature(interface, emit) # endFeature() # genType(typeinfo,name) - generate interface for a type # genEnum(enuminfo, name) # genCmd(cmdinfo) class COutputGenerator(OutputGenerator): """Generate specified API interfaces in a specific style, such as a C header""" def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) # Internal state - accumulators for different inner block text self.typeBody = '' self.enumBody = '' self.cmdBody = '' # # makeCDecls - return C prototype and function pointer typedef for a # command, as a two-element list of strings. # cmd - Element containing a tag def makeCDecls(self, cmd): """Generate C function pointer typedef for Element""" proto = cmd.find('proto') params = cmd.findall('param') # Begin accumulating prototype and typedef strings pdecl = self.genOpts.apicall tdecl = 'typedef ' # # Insert the function return type/name. # For prototypes, add APIENTRY macro before the name # For typedefs, add (APIENTRYP ) around the name and # use the PFNGLCMDNAMEPROC nameng convention. # Done by walking the tree for element by element. # lxml.etree has elem.text followed by (elem[i], elem[i].tail) # for each child element and any following text # Leading text pdecl += noneStr(proto.text) tdecl += noneStr(proto.text) # For each child element, if it's a wrap in appropriate # declaration. Otherwise append its contents and tail contents. for elem in proto: text = noneStr(elem.text) tail = noneStr(elem.tail) if (elem.tag == 'name'): pdecl += self.genOpts.apientry + text + tail tdecl += '(' + self.genOpts.apientryp + 'PFN' + text.upper() + 'PROC' + tail + ')' else: pdecl += text + tail tdecl += text + tail # Now add the parameter declaration list, which is identical # for prototypes and typedefs. Concatenate all the text from # a node without the tags. No tree walking required # since all tags are ignored. n = len(params) paramdecl = ' (' if n > 0: for i in range(0,n): paramdecl += ''.join([t for t in params[i].itertext()]) if (i < n - 1): paramdecl += ', ' else: paramdecl += 'void' paramdecl += ");\n"; return [ pdecl + paramdecl, tdecl + paramdecl ] # def newline(self): write('', file=self.outFile) # def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) # C-specific # # Multiple inclusion protection & C++ wrappers. if (genOpts.protectFile and self.genOpts.filename): headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename)) write('#ifndef', headerSym, file=self.outFile) write('#define', headerSym, '1', file=self.outFile) self.newline() write('#ifdef __cplusplus', file=self.outFile) write('extern "C" {', file=self.outFile) write('#endif', file=self.outFile) self.newline() # # User-supplied prefix text, if any (list of strings) if (genOpts.prefixText): for s in genOpts.prefixText: write(s, file=self.outFile) # # Some boilerplate describing what was generated - this # will probably be removed later since the extensions # pattern may be very long. write('/* Generated C header for:', file=self.outFile) write(' * API:', genOpts.apiname, file=self.outFile) if (genOpts.profile): write(' * Profile:', genOpts.profile, file=self.outFile) write(' * Versions considered:', genOpts.versions, file=self.outFile) write(' * Versions emitted:', genOpts.emitversions, file=self.outFile) write(' * Default extensions included:', genOpts.defaultExtensions, file=self.outFile) write(' * Additional extensions included:', genOpts.addExtensions, file=self.outFile) write(' * Extensions removed:', genOpts.removeExtensions, file=self.outFile) write(' */', file=self.outFile) def endFile(self): # C-specific # Finish C++ wrapper and multiple inclusion protection self.newline() write('#ifdef __cplusplus', file=self.outFile) write('}', file=self.outFile) write('#endif', file=self.outFile) if (self.genOpts.protectFile and self.genOpts.filename): self.newline() write('#endif', file=self.outFile) # Finish processing in superclass OutputGenerator.endFile(self) def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) # C-specific # Accumulate types, enums, function pointer typedefs, end function # prototypes separately for this feature. They're only printed in # endFeature(). self.typeBody = '' self.enumBody = '' self.cmdPointerBody = '' self.cmdBody = '' def endFeature(self): # C-specific # Actually write the interface to the output file. if (self.emit): self.newline() if (self.genOpts.protectFeature): write('#ifndef', self.featureName, file=self.outFile) write('#define', self.featureName, '1', file=self.outFile) if (self.typeBody != ''): write(self.typeBody, end='', file=self.outFile) # # Don't add additional protection for derived type declarations, # which may be needed by other features later on. if (self.featureExtraProtect != None): write('#ifdef', self.featureExtraProtect, file=self.outFile) if (self.enumBody != ''): write(self.enumBody, end='', file=self.outFile) if (self.genOpts.genFuncPointers and self.cmdPointerBody != ''): write(self.cmdPointerBody, end='', file=self.outFile) if (self.cmdBody != ''): if (self.genOpts.protectProto): write('#ifdef', self.genOpts.protectProtoStr, file=self.outFile) write(self.cmdBody, end='', file=self.outFile) if (self.genOpts.protectProto): write('#endif', file=self.outFile) if (self.featureExtraProtect != None): write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) if (self.genOpts.protectFeature): write('#endif /*', self.featureName, '*/', file=self.outFile) # Finish processing in superclass OutputGenerator.endFeature(self) # # Type generation def genType(self, typeinfo, name): OutputGenerator.genType(self, typeinfo, name) # # Replace tags with an APIENTRY-style string # (from self.genOpts). Copy other text through unchanged. # If the resulting text is an empty string, don't emit it. typeElem = typeinfo.elem s = noneStr(typeElem.text) for elem in typeElem: if (elem.tag == 'apientry'): s += self.genOpts.apientry + noneStr(elem.tail) else: s += noneStr(elem.text) + noneStr(elem.tail) if (len(s) > 0): self.typeBody += s + "\n" # # Enumerant generation def genEnum(self, enuminfo, name): OutputGenerator.genEnum(self, enuminfo, name) # # EnumInfo.type is a C value suffix (e.g. u, ull) self.enumBody += '#define ' + name.ljust(33) + ' ' + enuminfo.elem.get('value') # # Handle non-integer 'type' fields by using it as the C value suffix t = enuminfo.elem.get('type') if (t != '' and t != 'i'): self.enumBody += enuminfo.type self.enumBody += "\n" # # Command generation def genCmd(self, cmdinfo, name): OutputGenerator.genCmd(self, cmdinfo, name) # decls = self.makeCDecls(cmdinfo.elem) self.cmdBody += decls[0] if (self.genOpts.genFuncPointers): self.cmdPointerBody += decls[1] # Registry - object representing an API registry, loaded from an XML file # Members # tree - ElementTree containing the root # typedict - dictionary of TypeInfo objects keyed by type name # groupdict - dictionary of GroupInfo objects keyed by group name # enumdict - dictionary of EnumInfo objects keyed by enum name # cmddict - dictionary of CmdInfo objects keyed by command name # apidict - dictionary of Elements keyed by API name # extensions - list of Elements # extdict - dictionary of Elements keyed by extension name # gen - OutputGenerator object used to write headers / messages # genOpts - GeneratorOptions object used to control which # fetures to write and how to format them # emitFeatures - True to actually emit features for a version / extension, # or False to just treat them as emitted # Public methods # loadElementTree(etree) - load registry from specified ElementTree # loadFile(filename) - load registry from XML file # setGenerator(gen) - OutputGenerator to use # parseTree() - parse the registry once loaded & create dictionaries # dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries # to specified file handle (default stdout). Truncates type / # enum / command elements to maxlen characters (default 80) # generator(g) - specify the output generator object # apiGen(apiname, genOpts) - generate API headers for the API type # and profile specified in genOpts, but only for the versions and # extensions specified there. # apiReset() - call between calls to apiGen() to reset internal state # validateGroups() - call to verify that each or # with a 'group' attribute matches an actual existing group. # Private methods # addElementInfo(elem,info,infoName,dictionary) - add feature info to dict # lookupElementInfo(fname,dictionary) - lookup feature info in dict class Registry: """Represents an API registry loaded from XML""" def __init__(self): self.tree = None self.typedict = {} self.groupdict = {} self.enumdict = {} self.cmddict = {} self.apidict = {} self.extensions = [] self.extdict = {} # A default output generator, so commands prior to apiGen can report # errors via the generator object. self.gen = OutputGenerator() self.genOpts = None self.emitFeatures = False def loadElementTree(self, tree): """Load ElementTree into a Registry object and parse it""" self.tree = tree self.parseTree() def loadFile(self, file): """Load an API registry XML file into a Registry object and parse it""" self.tree = etree.parse(file) self.parseTree() def setGenerator(self, gen): """Specify output generator object. None restores the default generator""" self.gen = gen # addElementInfo - add information about an element to the # corresponding dictionary # elem - ///// Element # info - corresponding {Type|Group|Enum|Cmd|Feature}Info object # infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' # dictionary - self.{type|group|enum|cmd|api|ext}dict # If the Element has an 'api' attribute, the dictionary key is the # tuple (name,api). If not, the key is the name. 'name' is an # attribute of the Element def addElementInfo(self, elem, info, infoName, dictionary): if ('api' in elem.attrib): key = (elem.get('name'),elem.get('api')) else: key = elem.get('name') if key in dictionary: self.gen.logMsg('warn', '*** Attempt to redefine', infoName, 'with key:', key) else: dictionary[key] = info # # lookupElementInfo - find a {Type|Enum|Cmd}Info object by name. # If an object qualified by API name exists, use that. # fname - name of type / enum / command # dictionary - self.{type|enum|cmd}dict def lookupElementInfo(self, fname, dictionary): key = (fname, self.genOpts.apiname) if (key in dictionary): # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) return dictionary[key] elif (fname in dictionary): # self.gen.logMsg('diag', 'Found generic element for feature', fname) return dictionary[fname] else: return None def parseTree(self): """Parse the registry Element, once created""" # This must be the Element for the root self.reg = self.tree.getroot() # # Create dictionary of registry types from toplevel tags # and add 'name' attribute to each tag (where missing) # based on its element. # # There's usually one block; more are OK # Required attributes: 'name' or nested tag contents self.typedict = {} for type in self.reg.findall('types/type'): # If the doesn't already have a 'name' attribute, set # it from contents of its tag. if (type.get('name') == None): type.attrib['name'] = type.find('name').text self.addElementInfo(type, TypeInfo(type), 'type', self.typedict) # # Create dictionary of registry groups from toplevel tags. # # There's usually one block; more are OK. # Required attributes: 'name' self.groupdict = {} for group in self.reg.findall('groups/group'): self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) # # Create dictionary of registry enums from toplevel tags # # There are usually many tags in different namespaces, but # these are functional namespaces of the values, while the actual # enum names all share the dictionary. # Required attributes: 'name', 'value' self.enumdict = {} for enum in self.reg.findall('enums/enum'): self.addElementInfo(enum, EnumInfo(enum), 'enum', self.enumdict) # # Create dictionary of registry commands from tags # and add 'name' attribute to each tag (where missing) # based on its element. # # There's usually only one block; more are OK. # Required attributes: 'name' or tag contents self.cmddict = {} for cmd in self.reg.findall('commands/command'): # If the doesn't already have a 'name' attribute, set # it from contents of its tag. if (cmd.get('name') == None): cmd.attrib['name'] = cmd.find('proto/name').text ci = CmdInfo(cmd) self.addElementInfo(cmd, ci, 'command', self.cmddict) # # Create dictionaries of API and extension interfaces # from toplevel and tags. # self.apidict = {} for feature in self.reg.findall('feature'): ai = FeatureInfo(feature) self.addElementInfo(feature, ai, 'feature', self.apidict) self.extensions = self.reg.findall('extensions/extension') self.extdict = {} for feature in self.extensions: ei = FeatureInfo(feature) self.addElementInfo(feature, ei, 'extension', self.extdict) def dumpReg(self, maxlen = 40, filehandle = sys.stdout): """Dump all the dictionaries constructed from the Registry object""" write('***************************************', file=filehandle) write(' ** Dumping Registry contents **', file=filehandle) write('***************************************', file=filehandle) write('// Types', file=filehandle) for name in self.typedict: tobj = self.typedict[name] write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) write('// Groups', file=filehandle) for name in self.groupdict: gobj = self.groupdict[name] write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) write('// Enums', file=filehandle) for name in self.enumdict: eobj = self.enumdict[name] write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) write('// Commands', file=filehandle) for name in self.cmddict: cobj = self.cmddict[name] write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) write('// APIs', file=filehandle) for key in self.apidict: write(' API Version ', key, '->', etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) write('// Extensions', file=filehandle) for key in self.extdict: write(' Extension', key, '->', etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) # write('***************************************', file=filehandle) # write(' ** Dumping XML ElementTree **', file=filehandle) # write('***************************************', file=filehandle) # write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle) # # typename - name of type # required - boolean (to tag features as required or not) def markTypeRequired(self, typename, required): """Require (along with its dependencies) or remove (but not its dependencies) a type""" self.gen.logMsg('diag', '*** tagging type:', typename, '-> required =', required) # Get TypeInfo object for tag corresponding to typename type = self.lookupElementInfo(typename, self.typedict) if (type != None): # Tag required type dependencies as required. # This DOES NOT un-tag dependencies in a tag. # See comments in markRequired() below for the reason. if (required and ('requires' in type.elem.attrib)): depType = type.elem.get('requires') self.gen.logMsg('diag', '*** Generating dependent type', depType, 'for type', typename) self.markTypeRequired(depType, required) type.required = required else: self.gen.logMsg('warn', '*** type:', typename , 'IS NOT DEFINED') # # features - Element for or tag # required - boolean (to tag features as required or not) def markRequired(self, features, required): """Require or remove features specified in the Element""" self.gen.logMsg('diag', '*** markRequired (features = , required =', required, ')') # Loop over types, enums, and commands in the tag # @@ It would be possible to respect 'api' and 'profile' attributes # in individual features, but that's not done yet. for typeElem in features.findall('type'): self.markTypeRequired(typeElem.get('name'), required) for enumElem in features.findall('enum'): name = enumElem.get('name') self.gen.logMsg('diag', '*** tagging enum:', name, '-> required =', required) enum = self.lookupElementInfo(name, self.enumdict) if (enum != None): enum.required = required else: self.gen.logMsg('warn', '*** enum:', name , 'IS NOT DEFINED') for cmdElem in features.findall('command'): name = cmdElem.get('name') self.gen.logMsg('diag', '*** tagging command:', name, '-> required =', required) cmd = self.lookupElementInfo(name, self.cmddict) if (cmd != None): cmd.required = required # Tag all parameter types of this command as required. # This DOES NOT remove types of commands in a # tag, because many other commands may use the same type. # We could be more clever and reference count types, # instead of using a boolean. if (required): # Look for in entire tree, # not just immediate children for ptype in cmd.elem.findall('.//ptype'): self.gen.logMsg('diag', '*** markRequired: command implicitly requires dependent type', ptype.text) self.markTypeRequired(ptype.text, required) else: self.gen.logMsg('warn', '*** command:', name, 'IS NOT DEFINED') # # interface - Element for or , containing # and tags # api - string specifying API name being generated # profile - string specifying API profile being generated def requireAndRemoveFeatures(self, interface, api, profile): """Process and tags for a or """ # marks things that are required by this version/profile for feature in interface.findall('require'): if (matchAPIProfile(api, profile, feature)): self.markRequired(feature,True) # marks things that are removed by this version/profile for feature in interface.findall('remove'): if (matchAPIProfile(api, profile, feature)): self.markRequired(feature,False) # # generateFeature - generate a single type / enum / command, # and all its dependencies as needed. # fname - name of feature (// # ftype - type of feature, 'type' | 'enum' | 'command' # dictionary - of *Info objects - self.{type|enum|cmd}dict # genProc - bound function pointer for self.gen.gen{Type|Enum|Cmd} def generateFeature(self, fname, ftype, dictionary, genProc): f = self.lookupElementInfo(fname, dictionary) if (f == None): # No such feature. This is an error, but reported earlier self.gen.logMsg('diag', '*** No entry found for feature', fname, 'returning!') return # # If feature isn't required, or has already been declared, return if (not f.required): self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not required)') return if (f.declared): self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(already declared)') return # # Pull in dependent type declaration(s) of the feature. # For types, there may be one in the 'required' attribute of the element # For commands, there may be many in tags within the element # For enums, no dependencies are allowed (though perhasps if you # have a uint64 enum, it should require GLuint64) if (ftype == 'type'): if ('requires' in f.elem.attrib): depname = f.elem.get('requires') self.gen.logMsg('diag', '*** Generating required dependent type', depname) self.generateFeature(depname, 'type', self.typedict, self.gen.genType) elif (ftype == 'command'): for ptype in f.elem.findall('.//ptype'): depname = ptype.text self.gen.logMsg('diag', '*** Generating required parameter type', depname) self.generateFeature(depname, 'type', self.typedict, self.gen.genType) # # Actually generate the type only if emitting declarations if self.emitFeatures: self.gen.logMsg('diag', '*** Emitting', ftype, 'decl for', fname) genProc(f, fname) else: self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not emitting this feature)') # Always mark feature declared, as though actually emitted f.declared = True # # generateRequiredInterface - generate all interfaces required # by an API version or extension # interface - Element for or def generateRequiredInterface(self, interface): """Generate required C interface for specified API version/extension""" # # Loop over all features inside all tags. # tags are ignored (handled in pass 1). for features in interface.findall('require'): for t in features.findall('type'): self.generateFeature(t.get('name'), 'type', self.typedict, self.gen.genType) for e in features.findall('enum'): self.generateFeature(e.get('name'), 'enum', self.enumdict, self.gen.genEnum) for c in features.findall('command'): self.generateFeature(c.get('name'), 'command', self.cmddict, self.gen.genCmd) # # apiGen(genOpts) - generate interface for specified versions # genOpts - GeneratorOptions object with parameters used # by the Generator object. def apiGen(self, genOpts): """Generate interfaces for the specified API type and range of versions""" # self.gen.logMsg('diag', '*******************************************') self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename, 'api:', genOpts.apiname, 'profile:', genOpts.profile) self.gen.logMsg('diag', '*******************************************') # self.genOpts = genOpts # Reset required/declared flags for all features self.apiReset() # # Compile regexps used to select versions & extensions regVersions = re.compile(self.genOpts.versions) regEmitVersions = re.compile(self.genOpts.emitversions) regAddExtensions = re.compile(self.genOpts.addExtensions) regRemoveExtensions = re.compile(self.genOpts.removeExtensions) # # Get all matching API versions & add to list of FeatureInfo features = [] apiMatch = False for key in self.apidict: fi = self.apidict[key] api = fi.elem.get('api') if (api == self.genOpts.apiname): apiMatch = True if (regVersions.match(fi.number)): # Matches API & version #s being generated. Mark for # emission and add to the features[] list . # @@ Could use 'declared' instead of 'emit'? fi.emit = (regEmitVersions.match(fi.number) != None) features.append(fi) if (not fi.emit): self.gen.logMsg('diag', '*** NOT tagging feature api =', api, 'name =', fi.name, 'number =', fi.number, 'for emission (does not match emitversions pattern)') else: self.gen.logMsg('diag', '*** NOT including feature api =', api, 'name =', fi.name, 'number =', fi.number, '(does not match requested versions)') else: self.gen.logMsg('diag', '*** NOT including feature api =', api, 'name =', fi.name, '(does not match requested API)') if (not apiMatch): self.gen.logMsg('warn', '*** No matching API versions found!') # # Get all matching extensions & add to the list. # Start with extensions tagged with 'api' pattern matching the API # being generated. Add extensions matching the pattern specified in # regExtensions, then remove extensions matching the pattern # specified in regRemoveExtensions for key in self.extdict: ei = self.extdict[key] extName = ei.name include = False # # Include extension if defaultExtensions is not None and if the # 'supported' attribute matches defaultExtensions. The regexp in # 'supported' must exactly match defaultExtensions, so bracket # it with ^(pat)$. pat = '^(' + ei.elem.get('supported') + ')$' if (self.genOpts.defaultExtensions and re.match(pat, self.genOpts.defaultExtensions)): self.gen.logMsg('diag', '*** Including extension', extName, "(defaultExtensions matches the 'supported' attribute)") include = True # # Include additional extensions if the extension name matches # the regexp specified in the generator options. This allows # forcing extensions into an interface even if they're not # tagged appropriately in the registry. if (regAddExtensions.match(extName) != None): self.gen.logMsg('diag', '*** Including extension', extName, '(matches explicitly requested extensions to add)') include = True # Remove extensions if the name matches the regexp specified # in generator options. This allows forcing removal of # extensions from an interface even if they're tagged that # way in the registry. if (regRemoveExtensions.match(extName) != None): self.gen.logMsg('diag', '*** Removing extension', extName, '(matches explicitly requested extensions to remove)') include = False # # If the extension is to be included, add it to the # extension features list. if (include): ei.emit = True features.append(ei) else: self.gen.logMsg('diag', '*** NOT including extension', extName, '(does not match api attribute or explicitly requested extensions)') # # Sort the extension features list, if a sort procedure is defined if (self.genOpts.sortProcedure): self.genOpts.sortProcedure(features) # # Pass 1: loop over requested API versions and extensions tagging # types/commands/features as required (in an block) or no # longer required (in an block). It is possible to remove # a feature in one version and restore it later by requiring it in # a later version. # If a profile other than 'None' is being generated, it must # match the profile attribute (if any) of the and # tags. self.gen.logMsg('diag', '*** PASS 1: TAG FEATURES ********************************************') for f in features: self.gen.logMsg('diag', '*** PASS 1: Tagging required and removed features for', f.name) self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile) # # Pass 2: loop over specified API versions and extensions printing # declarations for required things which haven't already been # generated. self.gen.logMsg('diag', '*** PASS 2: GENERATE INTERFACES FOR FEATURES ************************') self.gen.beginFile(self.genOpts) for f in features: self.gen.logMsg('diag', '*** PASS 2: Generating interface for', f.name) emit = self.emitFeatures = f.emit if (not emit): self.gen.logMsg('diag', '*** PASS 2: NOT declaring feature', f.elem.get('name'), 'because it is not tagged for emission') # Generate the interface (or just tag its elements as having been # emitted, if they haven't been). self.gen.beginFeature(f.elem, emit) self.generateRequiredInterface(f.elem) self.gen.endFeature() self.gen.endFile() # # apiReset - use between apiGen() calls to reset internal state # def apiReset(self): """Reset type/enum/command dictionaries before generating another API""" for type in self.typedict: self.typedict[type].resetState() for enum in self.enumdict: self.enumdict[enum].resetState() for cmd in self.cmddict: self.cmddict[cmd].resetState() for cmd in self.apidict: self.apidict[cmd].resetState() # # validateGroups - check that group= attributes match actual groups # def validateGroups(self): """Validate group= attributes on and tags""" # Keep track of group names not in tags badGroup = {} self.gen.logMsg('diag', '*** VALIDATING GROUP ATTRIBUTES ***') for cmd in self.reg.findall('commands/command'): proto = cmd.find('proto') funcname = cmd.find('proto/name').text if ('group' in proto.attrib.keys()): group = proto.get('group') # self.gen.logMsg('diag', '*** Command ', funcname, ' has return group ', group) if (group not in self.groupdict.keys()): # self.gen.logMsg('diag', '*** Command ', funcname, ' has UNKNOWN return group ', group) if (group not in badGroup.keys()): badGroup[group] = 1 else: badGroup[group] = badGroup[group] + 1 for param in cmd.findall('param'): pname = param.find('name') if (pname != None): pname = pname.text else: pname = type.get('name') if ('group' in param.attrib.keys()): group = param.get('group') if (group not in self.groupdict.keys()): # self.gen.logMsg('diag', '*** Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group) if (group not in badGroup.keys()): badGroup[group] = 1 else: badGroup[group] = badGroup[group] + 1 if (len(badGroup.keys()) > 0): self.gen.logMsg('diag', '*** SUMMARY OF UNRECOGNIZED GROUPS ***') for key in sorted(badGroup.keys()): self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times') services/0040755 0000000 0000000 00000000000 13077405420 011435 5ustar000000000 0000000 services/batteryservice/0040755 0000000 0000000 00000000000 13077405420 014470 5ustar000000000 0000000 services/batteryservice/Android.mk0100644 0000000 0000000 00000000635 13077405420 016402 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BatteryProperties.cpp \ BatteryProperty.cpp \ IBatteryPropertiesListener.cpp \ IBatteryPropertiesRegistrar.cpp LOCAL_STATIC_LIBRARIES := \ libutils \ libbinder LOCAL_MODULE:= libbatteryservice LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_STATIC_LIBRARY) services/batteryservice/BatteryProperties.cpp0100644 0000000 0000000 00000004343 13077405420 020664 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include #include #include namespace android { /* * Parcel read/write code must be kept in sync with * frameworks/base/core/java/android/os/BatteryProperties.java */ status_t BatteryProperties::readFromParcel(Parcel* p) { chargerAcOnline = p->readInt32() == 1 ? true : false; chargerUsbOnline = p->readInt32() == 1 ? true : false; chargerWirelessOnline = p->readInt32() == 1 ? true : false; maxChargingCurrent = p->readInt32(); maxChargingVoltage = p->readInt32(); batteryStatus = p->readInt32(); batteryHealth = p->readInt32(); batteryPresent = p->readInt32() == 1 ? true : false; batteryLevel = p->readInt32(); batteryVoltage = p->readInt32(); batteryTemperature = p->readInt32(); batteryChargeCounter = p->readInt32(); batteryTechnology = String8((p->readString16()).string()); return OK; } status_t BatteryProperties::writeToParcel(Parcel* p) const { p->writeInt32(chargerAcOnline ? 1 : 0); p->writeInt32(chargerUsbOnline ? 1 : 0); p->writeInt32(chargerWirelessOnline ? 1 : 0); p->writeInt32(maxChargingCurrent); p->writeInt32(maxChargingVoltage); p->writeInt32(batteryStatus); p->writeInt32(batteryHealth); p->writeInt32(batteryPresent ? 1 : 0); p->writeInt32(batteryLevel); p->writeInt32(batteryVoltage); p->writeInt32(batteryTemperature); p->writeInt32(batteryChargeCounter); p->writeString16(String16(batteryTechnology)); return OK; } }; // namespace android services/batteryservice/BatteryProperty.cpp0100644 0000000 0000000 00000002164 13077405420 020353 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include #include namespace android { /* * Parcel read/write code must be kept in sync with * frameworks/base/core/java/android/os/BatteryProperty.java */ status_t BatteryProperty::readFromParcel(Parcel* p) { valueInt64 = p->readInt64(); return OK; } status_t BatteryProperty::writeToParcel(Parcel* p) const { p->writeInt64(valueInt64); return OK; } }; // namespace android services/batteryservice/IBatteryPropertiesListener.cpp0100644 0000000 0000000 00000003014 13077405420 022475 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include #include #include namespace android { class BpBatteryPropertiesListener : public BpInterface { public: BpBatteryPropertiesListener(const sp& impl) : BpInterface(impl) { } void batteryPropertiesChanged(struct BatteryProperties props) { Parcel data, reply; data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor()); data.writeInt32(1); props.writeToParcel(&data); remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener"); // ---------------------------------------------------------------------------- }; // namespace android services/batteryservice/IBatteryPropertiesRegistrar.cpp0100644 0000000 0000000 00000007706 13077405420 022666 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "IBatteryPropertiesRegistrar" //#define LOG_NDEBUG 0 #include #include #include #include #include #include namespace android { class BpBatteryPropertiesRegistrar : public BpInterface { public: BpBatteryPropertiesRegistrar(const sp& impl) : BpInterface(impl) {} void registerListener(const sp& listener) { Parcel data; data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(listener)); remote()->transact(REGISTER_LISTENER, data, NULL); } void unregisterListener(const sp& listener) { Parcel data; data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(listener)); remote()->transact(UNREGISTER_LISTENER, data, NULL); } status_t getProperty(int id, struct BatteryProperty *val) { Parcel data, reply; data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); data.writeInt32(id); remote()->transact(GET_PROPERTY, data, &reply); int32_t ret = reply.readExceptionCode(); if (ret != 0) { return ret; } ret = reply.readInt32(); int parcelpresent = reply.readInt32(); if (parcelpresent) val->readFromParcel(&reply); return ret; } }; IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar"); status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case REGISTER_LISTENER: { CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); sp listener = interface_cast(data.readStrongBinder()); registerListener(listener); return OK; } case UNREGISTER_LISTENER: { CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); sp listener = interface_cast(data.readStrongBinder()); unregisterListener(listener); return OK; } case GET_PROPERTY: { CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply); int id = data.readInt32(); struct BatteryProperty val; status_t result = getProperty(id, &val); reply->writeNoException(); reply->writeInt32(result); reply->writeInt32(1); val.writeToParcel(reply); return OK; } } return BBinder::onTransact(code, data, reply, flags); }; // ---------------------------------------------------------------------------- }; // namespace android services/inputflinger/0040755 0000000 0000000 00000000000 13077405420 014143 5ustar000000000 0000000 services/inputflinger/Android.mk0100644 0000000 0000000 00000002415 13077405420 016053 0ustar000000000 0000000 # Copyright (C) 2013 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. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ EventHub.cpp \ InputApplication.cpp \ InputDispatcher.cpp \ InputListener.cpp \ InputManager.cpp \ InputReader.cpp \ InputWindow.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ libcrypto \ libcutils \ libinput \ liblog \ libutils \ libui \ libhardware_legacy # TODO: Move inputflinger to its own process and mark it hidden #LOCAL_CFLAGS += -fvisibility=hidden LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) LOCAL_MODULE := libinputflinger include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) services/inputflinger/EventHub.cpp0100644 0000000 0000000 00000176050 13077405420 016375 0ustar000000000 0000000 /* * Copyright (C) 2005 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "EventHub" // #define LOG_NDEBUG 0 #include "EventHub.h" #include #include #include #include #include #include #include #include #include #include /* this macro is used to tell if "bit" is set in "array" * it selects a byte from the array, and does a boolean AND * operation with a byte that only has the relevant bit set. * eg. to check for the 12th bit, we do (array[1] & 1<<4) */ #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) /* this macro computes the number of bytes needed to represent a bit array of the specified size */ #define sizeof_bit_array(bits) ((bits + 7) / 8) #define INDENT " " #define INDENT2 " " #define INDENT3 " " namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; static const char *DEVICE_PATH = "/dev/input"; /* return the larger integer */ static inline int max(int v1, int v2) { return (v1 > v2) ? v1 : v2; } static inline const char* toString(bool value) { return value ? "true" : "false"; } static String8 sha1(const String8& in) { SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, reinterpret_cast(in.string()), in.size()); u_char digest[SHA_DIGEST_LENGTH]; SHA1_Final(digest, &ctx); String8 out; for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) { out.appendFormat("%02x", digest[i]); } return out; } static void getLinuxRelease(int* major, int* minor) { struct utsname info; if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) { *major = 0, *minor = 0; ALOGE("Could not get linux version: %s", strerror(errno)); } } // --- Global Functions --- uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { switch (axis) { case ABS_X: case ABS_Y: case ABS_PRESSURE: case ABS_TOOL_WIDTH: case ABS_DISTANCE: case ABS_TILT_X: case ABS_TILT_Y: case ABS_MT_SLOT: case ABS_MT_TOUCH_MAJOR: case ABS_MT_TOUCH_MINOR: case ABS_MT_WIDTH_MAJOR: case ABS_MT_WIDTH_MINOR: case ABS_MT_ORIENTATION: case ABS_MT_POSITION_X: case ABS_MT_POSITION_Y: case ABS_MT_TOOL_TYPE: case ABS_MT_BLOB_ID: case ABS_MT_TRACKING_ID: case ABS_MT_PRESSURE: case ABS_MT_DISTANCE: return INPUT_DEVICE_CLASS_TOUCH; } } // External stylus gets the pressure axis if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { if (axis == ABS_PRESSURE) { return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; } } // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } // --- EventHub::Device --- EventHub::Device::Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier) : next(NULL), fd(fd), id(id), path(path), identifier(identifier), classes(0), configuration(NULL), virtualKeyMap(NULL), ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), timestampOverrideSec(0), timestampOverrideUsec(0) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); memset(swBitmask, 0, sizeof(swBitmask)); memset(ledBitmask, 0, sizeof(ledBitmask)); memset(ffBitmask, 0, sizeof(ffBitmask)); memset(propBitmask, 0, sizeof(propBitmask)); } EventHub::Device::~Device() { close(); delete configuration; delete virtualKeyMap; } void EventHub::Device::close() { if (fd >= 0) { ::close(fd); fd = -1; } } // --- EventHub --- const uint32_t EventHub::EPOLL_ID_INOTIFY; const uint32_t EventHub::EPOLL_ID_WAKE; const int EventHub::EPOLL_SIZE_HINT; const int EventHub::EPOLL_MAX_EVENTS; EventHub::EventHub(void) : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), mOpeningDevices(0), mClosingDevices(0), mNeedToSendFinishedDeviceScan(false), mNeedToReopenDevices(false), mNeedToScanDevices(true), mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); mINotifyFd = inotify_init(); int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d", DEVICE_PATH, errno); struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno); int wakeFds[2]; result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); int major, minor; getLinuxRelease(&major, &minor); // EPOLLWAKEUP was introduced in kernel 3.5 mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5); } EventHub::~EventHub(void) { closeAllDevicesLocked(); while (mClosingDevices) { Device* device = mClosingDevices; mClosingDevices = device->next; delete device; } ::close(mEpollFd); ::close(mINotifyFd); ::close(mWakeReadPipeFd); ::close(mWakeWritePipeFd); release_wake_lock(WAKE_LOCK_ID); } InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == NULL) return InputDeviceIdentifier(); return device->identifier; } uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->classes; } int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->controllerNumber; } void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->configuration) { *outConfiguration = *device->configuration; } else { outConfiguration->clear(); } } status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); if (axis >= 0 && axis <= ABS_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, device->identifier.name.string(), device->fd, errno); return -errno; } if (info.minimum != info.maximum) { outAxisInfo->valid = true; outAxisInfo->minValue = info.minimum; outAxisInfo->maxValue = info.maximum; outAxisInfo->flat = info.flat; outAxisInfo->fuzz = info.fuzz; outAxisInfo->resolution = info.resolution; } return OK; } } return -1; } bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { if (axis >= 0 && axis <= REL_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return test_bit(axis, device->relBitmask); } } return false; } bool EventHub::hasInputProperty(int32_t deviceId, int property) const { if (property >= 0 && property <= INPUT_PROP_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return test_bit(property, device->propBitmask); } } return false; } int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { Vector scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); if (scanCodes.size() != 0) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { for (size_t i = 0; i < scanCodes.size(); i++) { int32_t sc = scanCodes.itemAt(i); if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) { return AKEY_STATE_DOWN; } } return AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; memset(swState, 0, sizeof(swState)); if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { *outValue = 0; if (axis >= 0 && axis <= ABS_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, device->identifier.name.string(), device->fd, errno); return -errno; } *outValue = info.value; return OK; } } return -1; } bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->keyMap.haveKeyLayout()) { Vector scanCodes; for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( keyCodes[codeIndex], &scanCodes); if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver for (size_t sc = 0; sc < scanCodes.size(); sc++) { if (test_bit(scanCodes[sc], device->keyBitmask)) { outFlags[codeIndex] = 1; break; } } } } return true; } return false; } status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); status_t status = NAME_NOT_FOUND; if (device) { // Check the key character map first. sp kcm = device->getKeyCharacterMap(); if (kcm != NULL) { if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { *outFlags = 0; status = NO_ERROR; } } // Check the key layout next. if (status != NO_ERROR && device->keyMap.haveKeyLayout()) { if (!device->keyMap.keyLayoutMap->mapKey( scanCode, usageCode, outKeycode, outFlags)) { status = NO_ERROR; } } if (status == NO_ERROR) { if (kcm != NULL) { kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState); } else { *outMetaState = metaState; } } } if (status != NO_ERROR) { *outKeycode = 0; *outFlags = 0; *outMetaState = metaState; } return status; } status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->keyMap.haveKeyLayout()) { status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo); if (err == NO_ERROR) { return NO_ERROR; } } return NAME_NOT_FOUND; } void EventHub::setExcludedDevices(const Vector& devices) { AutoMutex _l(mLock); mExcludedDevices = devices; } bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && scanCode >= 0 && scanCode <= KEY_MAX) { if (test_bit(scanCode, device->keyBitmask)) { return true; } } return false; } bool EventHub::hasLed(int32_t deviceId, int32_t led) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); int32_t sc; if (device && mapLed(device, led, &sc) == NO_ERROR) { if (test_bit(sc, device->ledBitmask)) { return true; } } return false; } void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); setLedStateLocked(device, led, on); } void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) { int32_t sc; if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) { struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_LED; ev.code = sc; ev.value = on ? 1 : 0; ssize_t nWrite; do { nWrite = write(device->fd, &ev, sizeof(struct input_event)); } while (nWrite == -1 && errno == EINTR); } } void EventHub::getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const { outVirtualKeys.clear(); AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->virtualKeyMap) { outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); } } sp EventHub::getKeyCharacterMap(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return device->getKeyCharacterMap(); } return NULL; } bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { if (map != device->overlayKeyMap) { device->overlayKeyMap = map; device->combinedKeyMap = KeyCharacterMap::combine( device->keyMap.keyCharacterMap, map); return true; } } return false; } static String8 generateDescriptor(InputDeviceIdentifier& identifier) { String8 rawDescriptor; rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product); // TODO add handling for USB devices to not uniqueify kbs that show up twice if (!identifier.uniqueId.isEmpty()) { rawDescriptor.append("uniqueId:"); rawDescriptor.append(identifier.uniqueId); } else if (identifier.nonce != 0) { rawDescriptor.appendFormat("nonce:%04x", identifier.nonce); } if (identifier.vendor == 0 && identifier.product == 0) { // If we don't know the vendor and product id, then the device is probably // built-in so we need to rely on other information to uniquely identify // the input device. Usually we try to avoid relying on the device name or // location but for built-in input device, they are unlikely to ever change. if (!identifier.name.isEmpty()) { rawDescriptor.append("name:"); rawDescriptor.append(identifier.name); } else if (!identifier.location.isEmpty()) { rawDescriptor.append("location:"); rawDescriptor.append(identifier.location); } } identifier.descriptor = sha1(rawDescriptor); return rawDescriptor; } void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { // Compute a device descriptor that uniquely identifies the device. // The descriptor is assumed to be a stable identifier. Its value should not // change between reboots, reconnections, firmware updates or new releases // of Android. In practice we sometimes get devices that cannot be uniquely // identified. In this case we enforce uniqueness between connected devices. // Ideally, we also want the descriptor to be short and relatively opaque. identifier.nonce = 0; String8 rawDescriptor = generateDescriptor(identifier); if (identifier.uniqueId.isEmpty()) { // If it didn't have a unique id check for conflicts and enforce // uniqueness if necessary. while(getDeviceByDescriptorLocked(identifier.descriptor) != NULL) { identifier.nonce++; rawDescriptor = generateDescriptor(identifier); } } ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(), identifier.descriptor.string()); } void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual()) { ff_effect effect; memset(&effect, 0, sizeof(effect)); effect.type = FF_RUMBLE; effect.id = device->ffEffectId; effect.u.rumble.strong_magnitude = 0xc000; effect.u.rumble.weak_magnitude = 0xc000; effect.replay.length = (duration + 999999LL) / 1000000LL; effect.replay.delay = 0; if (ioctl(device->fd, EVIOCSFF, &effect)) { ALOGW("Could not upload force feedback effect to device %s due to error %d.", device->identifier.name.string(), errno); return; } device->ffEffectId = effect.id; struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_FF; ev.code = device->ffEffectId; ev.value = 1; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not start force feedback effect on device %s due to error %d.", device->identifier.name.string(), errno); return; } device->ffEffectPlaying = true; } } void EventHub::cancelVibrate(int32_t deviceId) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual()) { if (device->ffEffectPlaying) { device->ffEffectPlaying = false; struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_FF; ev.code = device->ffEffectId; ev.value = 0; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not stop force feedback effect on device %s due to error %d.", device->identifier.name.string(), errno); return; } } } } EventHub::Device* EventHub::getDeviceByDescriptorLocked(String8& descriptor) const { size_t size = mDevices.size(); for (size_t i = 0; i < size; i++) { Device* device = mDevices.valueAt(i); if (descriptor.compare(device->identifier.descriptor) == 0) { return device; } } return NULL; } EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { if (deviceId == BUILT_IN_KEYBOARD_ID) { deviceId = mBuiltInKeyboardId; } ssize_t index = mDevices.indexOfKey(deviceId); return index >= 0 ? mDevices.valueAt(index) : NULL; } EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const { for (size_t i = 0; i < mDevices.size(); i++) { Device* device = mDevices.valueAt(i); if (device->path == devicePath) { return device; } } return NULL; } size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); AutoMutex _l(mLock); struct input_event readBuffer[bufferSize]; RawEvent* event = buffer; size_t capacity = bufferSize; bool awoken = false; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // Reopen input devices if needed. if (mNeedToReopenDevices) { mNeedToReopenDevices = false; ALOGI("Reopening all input devices due to a configuration change."); closeAllDevicesLocked(); mNeedToScanDevices = true; break; // return to the caller before we actually rescan } // Report any devices that had last been added/removed. while (mClosingDevices) { Device* device = mClosingDevices; ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } if (mNeedToScanDevices) { mNeedToScanDevices = false; scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; event->type = DEVICE_ADDED; event += 1; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; event->when = now; event->type = FINISHED_DEVICE_SCAN; event += 1; if (--capacity == 0) { break; } } // Grab the next input event. bool deviceChanged = false; while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { if (eventItem.events & EPOLLIN) { mPendingINotify = true; } else { ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events); } continue; } if (eventItem.data.u32 == EPOLL_ID_WAKE) { if (eventItem.events & EPOLLIN) { ALOGV("awoken after wake()"); awoken = true; char buffer[16]; ssize_t nRead; do { nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } else { ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", eventItem.events); } continue; } ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); if (deviceIndex < 0) { ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", eventItem.events, eventItem.data.u32); continue; } Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %" PRId32 " bufferSize: %zu capacity: %zu errno: %d)\n", device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); } else if (readSize < 0) { if (errno != EAGAIN && errno != EINTR) { ALOGW("could not get event (errno=%d)", errno); } } else if ((readSize % sizeof(struct input_event)) != 0) { ALOGE("could not get event (wrong size: %d)", readSize); } else { int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { struct input_event& iev = readBuffer[i]; ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d", device->path.string(), (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); // Some input devices may have a better concept of the time // when an input event was actually generated than the kernel // which simply timestamps all events on entry to evdev. // This is a custom Android extension of the input protocol // mainly intended for use with uinput based device drivers. if (iev.type == EV_MSC) { if (iev.code == MSC_ANDROID_TIME_SEC) { device->timestampOverrideSec = iev.value; continue; } else if (iev.code == MSC_ANDROID_TIME_USEC) { device->timestampOverrideUsec = iev.value; continue; } } if (device->timestampOverrideSec || device->timestampOverrideUsec) { iev.time.tv_sec = device->timestampOverrideSec; iev.time.tv_usec = device->timestampOverrideUsec; if (iev.type == EV_SYN && iev.code == SYN_REPORT) { device->timestampOverrideSec = 0; device->timestampOverrideUsec = 0; } ALOGV("applied override time %d.%06d", int(iev.time.tv_sec), int(iev.time.tv_usec)); } // Use the time specified in the event instead of the current time // so that downstream code can get more accurate estimates of // event dispatch latency from the time the event is enqueued onto // the evdev client buffer. // // The event's timestamp fortuitously uses the same monotonic clock // time base as the rest of Android. The kernel event device driver // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a // system call that also queries ktime_get_ts(). event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL; ALOGV("event time %" PRId64 ", now %" PRId64, event->when, now); // Bug 7291243: Add a guard in case the kernel generates timestamps // that appear to be far into the future because they were generated // using the wrong clock source. // // This can happen because when the input device is initially opened // it has a default clock source of CLOCK_REALTIME. Any input events // enqueued right after the device is opened will have timestamps // generated using CLOCK_REALTIME. We later set the clock source // to CLOCK_MONOTONIC but it is already too late. // // Invalid input event timestamps can result in ANRs, crashes and // and other issues that are hard to track down. We must not let them // propagate through the system. // // Log a warning so that we notice the problem and recover gracefully. if (event->when >= now + 10 * 1000000000LL) { // Double-check. Time may have moved on. nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC); if (event->when > time) { ALOGW("An input event from %s has a timestamp that appears to " "have been generated using the wrong clock source " "(expected CLOCK_MONOTONIC): " "event time %" PRId64 ", current time %" PRId64 ", call time %" PRId64 ". " "Using current time instead.", device->path.string(), event->when, time, now); event->when = time; } else { ALOGV("Event time is ok but failed the fast path and required " "an extra call to systemTime: " "event time %" PRId64 ", current time %" PRId64 ", call time %" PRId64 ".", event->when, time, now); } } event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1; capacity -= 1; } if (capacity == 0) { // The result buffer is full. Reset the pending event index // so we will try to read the device again on the next iteration. mPendingEventIndex -= 1; break; } } } else if (eventItem.events & EPOLLHUP) { ALOGI("Removing device %s due to epoll hang-up event.", device->identifier.name.string()); deviceChanged = true; closeDeviceLocked(device); } else { ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, device->identifier.name.string()); } } // readNotify() will modify the list of devices so this must be done after // processing all other events to ensure that we read all remaining events // before closing the devices. if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false; readNotifyLocked(); deviceChanged = true; } // Report added or removed devices immediately. if (deviceChanged) { continue; } // Return now if we have collected any events or if we were explicitly awoken. if (event != buffer || awoken) { break; } // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during epoll_wait(). This works due to some // subtle choreography. When a device driver has pending (unread) events, it acquires // a kernel wake lock. However, once the last pending event has been read, the device // driver will release the kernel wake lock. To prevent the system from going to sleep // when this happens, the EventHub holds onto its own user wake lock while the client // is processing events. Thus the system can only sleep if there are no events // pending or currently being processed. // // The timeout is advisory only. If the device is asleep, it will not wake just to // service the timeout. mPendingEventIndex = 0; mLock.unlock(); // release lock before poll, must be before release_wake_lock release_wake_lock(WAKE_LOCK_ID); int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock if (pollResult == 0) { // Timed out. mPendingEventCount = 0; break; } if (pollResult < 0) { // An error occurred. mPendingEventCount = 0; // Sleep after errors to avoid locking up the system. // Hopefully the error is transient. if (errno != EINTR) { ALOGW("poll failed (errno=%d)\n", errno); usleep(100000); } } else { // Some events occurred. mPendingEventCount = size_t(pollResult); } } // All done, return the number of events we read. return event - buffer; } void EventHub::wake() { ALOGV("wake() called"); ssize_t nWrite; do { nWrite = write(mWakeWritePipeFd, "W", 1); } while (nWrite == -1 && errno == EINTR); if (nWrite != 1 && errno != EAGAIN) { ALOGW("Could not write wake signal, errno=%d", errno); } } void EventHub::scanDevicesLocked() { status_t res = scanDirLocked(DEVICE_PATH); if(res < 0) { ALOGE("scan dir failed for %s\n", DEVICE_PATH); } if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { createVirtualKeyboardLocked(); } } // ---------------------------------------------------------------------------- static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { const uint8_t* end = array + endIndex; array += startIndex; while (array != end) { if (*(array++) != 0) { return true; } } return false; } static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, }; status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; // Get device name. if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.name.setTo(buffer); } // Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); close(fd); return -1; } } // Get device driver version. int driverVersion; if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } // Get device identifier. struct input_id inputId; if(ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location.setTo(buffer); } // Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId.setTo(buffer); } // Fill in the descriptor. assignDescriptorLocked(identifier); // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { ALOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); ALOGV("add device %d: %s\n", deviceId, devicePath); ALOGV(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGV(" name: \"%s\"\n", identifier.name.string()); ALOGV(" location: \"%s\"\n", identifier.location.string()); ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string()); ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string()); ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); // Load the configuration file for the device. loadConfigurationLocked(device); // Figure out the kinds of events the device reports. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a rotary encoder type device. String8 deviceType = String8(); if (device->configuration && device->configuration->tryGetProperty(String8("device.type"), deviceType)) { if (!deviceType.compare(String8("rotaryEncoder"))) { device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER; } } // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; // Is this a BT stylus? } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || test_bit(BTN_TOUCH, device->keyBitmask)) && !test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; // Keyboard will try to claim some of the buttons but we really want to reserve those so we // can fuse it with the touch screen data, so just take them back. Note this means an // external stylus cannot also be a keyboard device. device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD; } // See if this device is a joystick. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Check whether this device supports the vibrator. if (test_bit(FF_RUMBLE, device->ffBitmask)) { device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } // Disable kernel key repeat since we handle it ourselves unsigned int repeatRate[] = {0,0}; if (ioctl(fd, EVIOCSREP, repeatRate)) { ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); } } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } // Determine whether the device has a mic. if (deviceHasMicLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_MIC; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { device->controllerNumber = getNextControllerNumberLocked(device); setLedForController(device); } // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; if (mUsingEpollWakeup) { eventItem.events |= EPOLLWAKEUP; } eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } String8 wakeMechanism("EPOLLWAKEUP"); if (!mUsingEpollWakeup) { #ifndef EVIOCSSUSPENDBLOCK // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels // will use an epoll flag instead, so as long as we want to support // this feature, we need to be prepared to define the ioctl ourselves. #define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) #endif if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) { wakeMechanism = ""; } else { wakeMechanism = "EVIOCSSUSPENDBLOCK"; } } // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. // // In older kernel, before Linux 3.4, there was no way to tell the kernel which // clock to use to input event timestamps. The standard kernel behavior was to // record a real time timestamp, which isn't what we want. Android kernels therefore // contained a patch to the evdev_event() function in drivers/input/evdev.c to // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic // clock to be used instead of the real time clock. // // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. // Therefore, we no longer require the Android-specific kernel patch described above // as long as we make sure to set select the monotonic clock. We do that here. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " "wakeMechanism=%s, usingClockIoctl=%s", deviceId, fd, devicePath, device->identifier.name.string(), device->classes, device->configurationFile.string(), device->keyMap.keyLayoutFile.string(), device->keyMap.keyCharacterMapFile.string(), toString(mBuiltInKeyboardId == deviceId), wakeMechanism.string(), toString(usingClockIoctl)); addDeviceLocked(device); return 0; } void EventHub::createVirtualKeyboardLocked() { InputDeviceIdentifier identifier; identifier.name = "Virtual"; identifier.uniqueId = ""; assignDescriptorLocked(identifier); Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8(""), identifier); device->classes = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY | INPUT_DEVICE_CLASS_DPAD | INPUT_DEVICE_CLASS_VIRTUAL; loadKeyMapLocked(device); addDeviceLocked(device); } void EventHub::addDeviceLocked(Device* device) { mDevices.add(device->id, device); device->next = mOpeningDevices; mOpeningDevices = device; } void EventHub::loadConfigurationLocked(Device* device) { device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (device->configurationFile.isEmpty()) { ALOGD("No input device configuration file found for device '%s'.", device->identifier.name.string()); } else { status_t status = PropertyMap::load(device->configurationFile, &device->configuration); if (status) { ALOGE("Error loading input device configuration file for device '%s'. " "Using default configuration.", device->identifier.name.string()); } } } status_t EventHub::loadVirtualKeyMapLocked(Device* device) { // The virtual key map is supplied by the kernel as a system board property file. String8 path; path.append("/sys/board_properties/virtualkeys."); path.append(device->identifier.name); if (access(path.string(), R_OK)) { return NAME_NOT_FOUND; } return VirtualKeyMap::load(path, &device->virtualKeyMap); } status_t EventHub::loadKeyMapLocked(Device* device) { return device->keyMap.load(device->identifier, device->configuration); } bool EventHub::isExternalDeviceLocked(Device* device) { if (device->configuration) { bool value; if (device->configuration->tryGetProperty(String8("device.internal"), value)) { return !value; } } return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; } bool EventHub::deviceHasMicLocked(Device* device) { if (device->configuration) { bool value; if (device->configuration->tryGetProperty(String8("audio.mic"), value)) { return value; } } return false; } int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", device->identifier.name.string()); return 0; } // Since the controller number 0 is reserved for non-controllers, translate all numbers up by // one return static_cast(mControllerNumbers.markFirstUnmarkedBit() + 1); } void EventHub::releaseControllerNumberLocked(Device* device) { int32_t num = device->controllerNumber; device->controllerNumber= 0; if (num == 0) { return; } mControllerNumbers.clearBit(static_cast(num - 1)); } void EventHub::setLedForController(Device* device) { for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) { setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1); } } bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { if (!device->keyMap.haveKeyLayout()) { return false; } Vector scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; i= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { return true; } } return false; } status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) const { if (!device->keyMap.haveKeyLayout()) { return NAME_NOT_FOUND; } int32_t scanCode; if(device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) { if(scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) { *outScanCode = scanCode; return NO_ERROR; } } return NAME_NOT_FOUND; } status_t EventHub::closeDeviceByPathLocked(const char *devicePath) { Device* device = getDeviceByPathLocked(devicePath); if (device) { closeDeviceLocked(device); return 0; } ALOGV("Remove device: %s not found, device may already have been removed.", devicePath); return -1; } void EventHub::closeAllDevicesLocked() { while (mDevices.size() > 0) { closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1)); } } void EventHub::closeDeviceLocked(Device* device) { ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", device->path.string(), device->identifier.name.string(), device->id, device->fd, device->classes); if (device->id == mBuiltInKeyboardId) { ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", device->path.string(), mBuiltInKeyboardId); mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } if (!device->isVirtual()) { if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); } } releaseControllerNumberLocked(device); mDevices.removeItem(device->id); device->close(); // Unlink for opening devices list if it is present. Device* pred = NULL; bool found = false; for (Device* entry = mOpeningDevices; entry != NULL; ) { if (entry == device) { found = true; break; } pred = entry; entry = entry->next; } if (found) { // Unlink the device from the opening devices list then delete it. // We don't need to tell the client that the device was closed because // it does not even know it was opened in the first place. ALOGI("Device %s was immediately closed after opening.", device->path.string()); if (pred) { pred->next = device->next; } else { mOpeningDevices = device->next; } delete device; } else { // Link into closing devices list. // The device will be deleted later after we have informed the client. device->next = mClosingDevices; mClosingDevices = device; } } status_t EventHub::readNotifyLocked() { int res; char devname[PATH_MAX]; char *filename; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); res = read(mINotifyFd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) return 0; ALOGW("could not get event, %s\n", strerror(errno)); return -1; } //printf("got %d bytes of event information\n", res); strcpy(devname, DEVICE_PATH); filename = devname + strlen(devname); *filename++ = '/'; while(res >= (int)sizeof(*event)) { event = (struct inotify_event *)(event_buf + event_pos); //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); if(event->len) { strcpy(filename, event->name); if(event->mask & IN_CREATE) { openDeviceLocked(devname); } else { ALOGI("Removing device '%s' due to inotify event\n", devname); closeDeviceByPathLocked(devname); } } event_size = sizeof(*event) + event->len; res -= event_size; event_pos += event_size; } return 0; } status_t EventHub::scanDirLocked(const char *dirname) { char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); openDeviceLocked(devname); } closedir(dir); return 0; } void EventHub::requestReopenDevices() { ALOGV("requestReopenDevices() called"); AutoMutex _l(mLock); mNeedToReopenDevices = true; } void EventHub::dump(String8& dump) { dump.append("Event Hub State:\n"); { // acquire lock AutoMutex _l(mLock); dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); dump.append(INDENT "Devices:\n"); for (size_t i = 0; i < mDevices.size(); i++) { const Device* device = mDevices.valueAt(i); if (mBuiltInKeyboardId == device->id) { dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", device->id, device->identifier.name.string()); } else { dump.appendFormat(INDENT2 "%d: %s\n", device->id, device->identifier.name.string()); } dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " "product=0x%04x, version=0x%04x\n", device->identifier.bus, device->identifier.vendor, device->identifier.product, device->identifier.version); dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", device->keyMap.keyLayoutFile.string()); dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", device->keyMap.keyCharacterMapFile.string()); dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", device->configurationFile.string()); dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", toString(device->overlayKeyMap != NULL)); } } // release lock } void EventHub::monitor() { // Acquire and release the lock to ensure that the event hub has not deadlocked. mLock.lock(); mLock.unlock(); } }; // namespace android services/inputflinger/EventHub.h0100644 0000000 0000000 00000040201 13077405420 016026 0ustar000000000 0000000 /* * Copyright (C) 2005 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 _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Convenience constants. */ #define BTN_FIRST 0x100 // first button code #define BTN_LAST 0x15f // last button code /* * These constants are used privately in Android to pass raw timestamps * through evdev from uinput device drivers because there is currently no * other way to transfer this information. The evdev driver automatically * timestamps all input events with the time they were posted and clobbers * whatever information was passed in. * * For the purposes of this hack, the timestamp is specified in the * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying * seconds and microseconds. */ #define MSC_ANDROID_TIME_SEC 0x6 #define MSC_ANDROID_TIME_USEC 0x7 namespace android { enum { // Device id of a special "virtual" keyboard that is always present. VIRTUAL_KEYBOARD_ID = -1, // Device id of the "built-in" keyboard if there is one. BUILT_IN_KEYBOARD_ID = 0, }; /* * A raw event as retrieved from the EventHub. */ struct RawEvent { nsecs_t when; int32_t deviceId; int32_t type; int32_t code; int32_t value; }; /* Describes an absolute axis. */ struct RawAbsoluteAxisInfo { bool valid; // true if the information is valid, false otherwise int32_t minValue; // minimum value int32_t maxValue; // maximum value int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise int32_t resolution; // resolution in units per mm or radians per mm inline void clear() { valid = false; minValue = 0; maxValue = 0; flat = 0; fuzz = 0; resolution = 0; } }; /* * Input device classes. */ enum { /* The input device is a keyboard or has buttons. */ INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, /* The input device is an alpha-numeric keyboard (not just a dial pad). */ INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ INPUT_DEVICE_CLASS_TOUCH = 0x00000004, /* The input device is a cursor device such as a trackball or mouse. */ INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, /* The input device is a directional pad (implies keyboard, has DPAD keys). */ INPUT_DEVICE_CLASS_DPAD = 0x00000020, /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, /* The input device has switches. */ INPUT_DEVICE_CLASS_SWITCH = 0x00000080, /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, /* The input device has a vibrator (supports FF_RUMBLE). */ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, /* The input device has a microphone. */ INPUT_DEVICE_CLASS_MIC = 0x00000400, /* The input device is an external stylus (has data we want to fuse with touch data). */ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, /* The input device has a rotary encoder */ INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000, /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, /* The input device is external (not built-in). */ INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, }; /* * Gets the class that owns an axis, in cases where multiple classes might claim * the same axis for different purposes. */ extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); /* * Grand Central Station for events. * * The event hub aggregates input events received across all known input * devices on the system, including devices that may be emulated by the simulator * environment. In addition, the event hub generates fake input events to indicate * when devices are added or removed. * * The event hub provides a stream of input events (via the getEvent function). * It also supports querying the current actual state of input devices such as identifying * which keys are currently down. Finally, the event hub keeps track of the capabilities of * individual input devices, such as their class and the set of key codes that they support. */ class EventHubInterface : public virtual RefBase { protected: EventHubInterface() { } virtual ~EventHubInterface() { } public: // Synthetic raw event type codes produced when devices are added or removed. enum { // Sent when a device is added. DEVICE_ADDED = 0x10000000, // Sent when a device is removed. DEVICE_REMOVED = 0x20000000, // Sent when all added/removed devices from the most recent scan have been reported. // This event is always sent at least once. FINISHED_DEVICE_SCAN = 0x30000000, FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, }; virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0; virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const = 0; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0; virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const = 0; // Sets devices that are excluded from opening. // This can be used to ignore input devices for sensors. virtual void setExcludedDevices(const Vector& devices) = 0; /* * Wait for events to become available and returns them. * After returning, the EventHub holds onto a wake lock until the next call to getEvent. * This ensures that the device will not go to sleep while the event is being processed. * If the device needs to remain awake longer than that, then the caller is responsible * for taking care of it (say, by poking the power manager user activity timer). * * The timeout is advisory only. If the device is asleep, it will not wake just to * service the timeout. * * Returns the number of events obtained, or 0 if the timeout expired. */ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; /* * Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const = 0; /* * Examine key input devices for specific framework keycode support */ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; /* LED related functions expect Android LED constants, not scan codes or HID usages */ virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const = 0; virtual sp getKeyCharacterMap(int32_t deviceId) const = 0; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) = 0; /* Control the vibrator. */ virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; virtual void cancelVibrate(int32_t deviceId) = 0; /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ virtual void requestReopenDevices() = 0; /* Wakes up getEvents() if it is blocked on a read. */ virtual void wake() = 0; /* Dump EventHub state to a string. */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; }; class EventHub : public EventHubInterface { public: EventHub(); virtual uint32_t getDeviceClasses(int32_t deviceId) const; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; virtual int32_t getDeviceControllerNumber(int32_t deviceId) const; virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; virtual bool hasInputProperty(int32_t deviceId, int property) const; virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const; virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const; virtual void setExcludedDevices(const Vector& devices); virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; virtual bool hasLed(int32_t deviceId, int32_t led) const; virtual void setLedState(int32_t deviceId, int32_t led, bool on); virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const; virtual sp getKeyCharacterMap(int32_t deviceId) const; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map); virtual void vibrate(int32_t deviceId, nsecs_t duration); virtual void cancelVibrate(int32_t deviceId); virtual void requestReopenDevices(); virtual void wake(); virtual void dump(String8& dump); virtual void monitor(); protected: virtual ~EventHub(); private: struct Device { Device* next; int fd; // may be -1 if device is virtual const int32_t id; const String8 path; const InputDeviceIdentifier identifier; uint32_t classes; uint8_t keyBitmask[(KEY_MAX + 1) / 8]; uint8_t absBitmask[(ABS_MAX + 1) / 8]; uint8_t relBitmask[(REL_MAX + 1) / 8]; uint8_t swBitmask[(SW_MAX + 1) / 8]; uint8_t ledBitmask[(LED_MAX + 1) / 8]; uint8_t ffBitmask[(FF_MAX + 1) / 8]; uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; String8 configurationFile; PropertyMap* configuration; VirtualKeyMap* virtualKeyMap; KeyMap keyMap; sp overlayKeyMap; sp combinedKeyMap; bool ffEffectPlaying; int16_t ffEffectId; // initially -1 int32_t controllerNumber; int32_t timestampOverrideSec; int32_t timestampOverrideUsec; Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); ~Device(); void close(); inline bool isVirtual() const { return fd < 0; } const sp& getKeyCharacterMap() const { if (combinedKeyMap != NULL) { return combinedKeyMap; } return keyMap.keyCharacterMap; } }; status_t openDeviceLocked(const char *devicePath); void createVirtualKeyboardLocked(); void addDeviceLocked(Device* device); void assignDescriptorLocked(InputDeviceIdentifier& identifier); status_t closeDeviceByPathLocked(const char *devicePath); void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); status_t scanDirLocked(const char *dirname); void scanDevicesLocked(); status_t readNotifyLocked(); Device* getDeviceByDescriptorLocked(String8& descriptor) const; Device* getDeviceLocked(int32_t deviceId) const; Device* getDeviceByPathLocked(const char* devicePath) const; bool hasKeycodeLocked(Device* device, int keycode) const; void loadConfigurationLocked(Device* device); status_t loadVirtualKeyMapLocked(Device* device); status_t loadKeyMapLocked(Device* device); bool isExternalDeviceLocked(Device* device); bool deviceHasMicLocked(Device* device); int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); void setLedForController(Device* device); status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const; void setLedStateLocked(Device* device, int32_t led, bool on); // Protect all internal state. mutable Mutex mLock; // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. // EventHub remaps the built-in keyboard to id 0 externally as required by the API. enum { // Must not conflict with any other assigned device ids, including // the virtual keyboard id (-1). NO_BUILT_IN_KEYBOARD = -2, }; int32_t mBuiltInKeyboardId; int32_t mNextDeviceId; BitSet32 mControllerNumbers; KeyedVector mDevices; Device *mOpeningDevices; Device *mClosingDevices; bool mNeedToSendFinishedDeviceScan; bool mNeedToReopenDevices; bool mNeedToScanDevices; Vector mExcludedDevices; int mEpollFd; int mINotifyFd; int mWakeReadPipeFd; int mWakeWritePipeFd; // Ids used for epoll notifications not associated with devices. static const uint32_t EPOLL_ID_INOTIFY = 0x80000001; static const uint32_t EPOLL_ID_WAKE = 0x80000002; // Epoll FD list size hint. static const int EPOLL_SIZE_HINT = 8; // Maximum number of signalled FDs to handle at a time. static const int EPOLL_MAX_EVENTS = 16; // The array of pending epoll events and the index of the next event to be handled. struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; size_t mPendingEventCount; size_t mPendingEventIndex; bool mPendingINotify; bool mUsingEpollWakeup; }; }; // namespace android #endif // _RUNTIME_EVENT_HUB_H services/inputflinger/InputApplication.cpp0100644 0000000 0000000 00000002034 13077405420 020126 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "InputApplication" #include "InputApplication.h" #include namespace android { // --- InputApplicationHandle --- InputApplicationHandle::InputApplicationHandle() : mInfo(NULL) { } InputApplicationHandle::~InputApplicationHandle() { delete mInfo; } void InputApplicationHandle::releaseInfo() { if (mInfo) { delete mInfo; mInfo = NULL; } } } // namespace android services/inputflinger/InputApplication.h0100644 0000000 0000000 00000004275 13077405420 017604 0ustar000000000 0000000 /* * 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 _UI_INPUT_APPLICATION_H #define _UI_INPUT_APPLICATION_H #include #include #include #include namespace android { /* * Describes the properties of an application that can receive input. */ struct InputApplicationInfo { String8 name; nsecs_t dispatchingTimeout; }; /* * Handle for an application that can receive input. * * Used by the native input dispatcher as a handle for the window manager objects * that describe an application. */ class InputApplicationHandle : public RefBase { public: inline const InputApplicationInfo* getInfo() const { return mInfo; } inline String8 getName() const { return mInfo ? mInfo->name : String8(""); } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { return mInfo ? mInfo->dispatchingTimeout : defaultValue; } /** * Requests that the state of this object be updated to reflect * the most current available information about the application. * * This method should only be called from within the input dispatcher's * critical section. * * Returns true on success, or false if the handle is no longer valid. */ virtual bool updateInfo() = 0; /** * Releases the storage used by the associated information when it is * no longer needed. */ void releaseInfo(); protected: InputApplicationHandle(); virtual ~InputApplicationHandle(); InputApplicationInfo* mInfo; }; } // namespace android #endif // _UI_INPUT_APPLICATION_H services/inputflinger/InputDispatcher.cpp0100644 0000000 0000000 00000544131 13077405420 017762 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "InputDispatcher" #define ATRACE_TAG ATRACE_TAG_INPUT //#define LOG_NDEBUG 0 // Log detailed debug messages about each inbound event notification to the dispatcher. #define DEBUG_INBOUND_EVENT_DETAILS 0 // Log detailed debug messages about each outbound event processed by the dispatcher. #define DEBUG_OUTBOUND_EVENT_DETAILS 0 // Log debug messages about the dispatch cycle. #define DEBUG_DISPATCH_CYCLE 0 // Log debug messages about registrations. #define DEBUG_REGISTRATION 0 // Log debug messages about input event injection. #define DEBUG_INJECTION 0 // Log debug messages about input focus tracking. #define DEBUG_FOCUS 0 // Log debug messages about the app switch latency optimization. #define DEBUG_APP_SWITCH 0 // Log debug messages about hover events. #define DEBUG_HOVER 0 #include "InputDispatcher.h" #include #include #include #include #include #include #include #include #include #define INDENT " " #define INDENT2 " " #define INDENT3 " " #define INDENT4 " " namespace android { // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec // Amount of time to allow for all pending events to be processed when an app switch // key is on the way. This is used to preempt input dispatch and drop input events // when an application takes too long to respond and the user has pressed an app switch key. const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec // Amount of time to allow for an event to be dispatched (measured since its eventTime) // before considering it stale and dropping it. const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec // Amount of time to allow touch events to be streamed out to a connection before requiring // that the first event be finished. This value extends the ANR timeout by the specified // amount. For example, if streaming is allowed to get ahead by one second relative to the // queue of waiting unfinished events, then ANRs will similarly be delayed by one second. const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec // Log a warning when an event takes longer than this to process, even if an ANR does not occur. const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec // Number of recent events to keep for debugging purposes. const size_t RECENT_QUEUE_MAX_SIZE = 10; static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } static inline const char* toString(bool value) { return value ? "true" : "false"; } static inline int32_t getMotionEventActionPointerIndex(int32_t action) { return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } static bool isValidKeyAction(int32_t action) { switch (action) { case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_UP: return true; default: return false; } } static bool validateKeyEvent(int32_t action) { if (! isValidKeyAction(action)) { ALOGE("Key event has invalid action code 0x%x", action); return false; } return true; } static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_OUTSIDE: case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: case AMOTION_EVENT_ACTION_HOVER_EXIT: case AMOTION_EVENT_ACTION_SCROLL: return true; case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: { int32_t index = getMotionEventActionPointerIndex(action); return index >= 0 && index < pointerCount; } case AMOTION_EVENT_ACTION_BUTTON_PRESS: case AMOTION_EVENT_ACTION_BUTTON_RELEASE: return actionButton != 0; default: return false; } } static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, const PointerProperties* pointerProperties) { if (! isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.", pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { ALOGE("Motion event has duplicate pointer id %d", id); return false; } pointerIdBits.markBit(id); } return true; } static bool isMainDisplay(int32_t displayId) { return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE; } static void dumpRegion(String8& dump, const Region& region) { if (region.isEmpty()) { dump.append(""); return; } bool first = true; Region::const_iterator cur = region.begin(); Region::const_iterator const tail = region.end(); while (cur != tail) { if (first) { first = false; } else { dump.append("|"); } dump.appendFormat("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom); cur++; } } // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp& policy) : mPolicy(policy), mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mKeyRepeatState.lastKeyEntry = NULL; policy->getDispatcherConfiguration(&mConfig); } InputDispatcher::~InputDispatcher() { { // acquire lock AutoMutex _l(mLock); resetKeyRepeatLocked(); releasePendingEventLocked(); drainInboundQueueLocked(); } while (mConnectionsByFd.size() != 0) { unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); } } void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); // Run a dispatch loop if there are no pending commands. // The dispatch loop might enqueue commands to run afterwards. if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } // Run all pending commands if there are any. // If any commands were run then force the next poll to wake up immediately. if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); } void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever normal dispatch is suspended while the // device is in a non-interactive state. This is to ensure that we abort a key // repeat if the device is just coming out of sleep. if (!mDispatchEnabled) { resetKeyRepeatLocked(); } // If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { #if DEBUG_FOCUS ALOGD("Dispatch frozen. Waiting some more."); #endif return; } // Optimize latency of app switches. // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has // been pressed. When it expires, we preempt dispatch and drop all other pending events. bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; if (mAppSwitchDueTime < *nextWakeupTime) { *nextWakeupTime = mAppSwitchDueTime; } // Ready to start a new event. // If we don't already have a pending event, go grab one. if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting // for will never arrive. Stop waiting for it. resetPendingAppSwitchLocked(false); isAppSwitchDue = false; } // Synthesize a key repeat if appropriate. if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; } } } // Nothing to do if there is no pending event. if (!mPendingEvent) { return; } } else { // Inbound queue has at least one entry. mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } // Poke user activity for this event. if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(mPendingEvent); } // Get ready to dispatch the event. resetANRTimeoutsLocked(); } // Now we have an event to dispatch. // All events are eventually dequeued and processed this way, even if we intend to drop them. ALOG_ASSERT(mPendingEvent != NULL); bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED; if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY; } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } if (mNextUnblockedEvent == mPendingEvent) { mNextUnblockedEvent = NULL; } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast(mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped break; } case EventEntry::TYPE_DEVICE_RESET: { DeviceResetEntry* typedEntry = static_cast(mPendingEvent); done = dispatchDeviceResetLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped break; } case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast(mPendingEvent); if (isAppSwitchDue) { if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); isAppSwitchDue = false; } else if (dropReason == DROP_REASON_NOT_DROPPED) { dropReason = DROP_REASON_APP_SWITCH; } } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } default: ALOG_ASSERT(false); break; } if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } mLastDropReason = dropReason; releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); switch (entry->type) { case EventEntry::TYPE_KEY: { // Optimize app switch latency. // If the application takes too long to catch up then we drop all events preceding // the app switch key. KeyEntry* keyEntry = static_cast(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { mAppSwitchSawKeyDown = true; } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH ALOGD("App switch is pending!"); #endif mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; mAppSwitchSawKeyDown = false; needWake = true; } } } break; } case EventEntry::TYPE_MOTION: { // Optimize case where the current application is unresponsive and the user // decides to touch a window in a different application. // If the application takes too long to catch up then we drop all events preceding // the touch into the other window. MotionEntry* motionEntry = static_cast(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && mInputTargetWaitApplicationHandle != NULL) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; needWake = true; } } break; } } return needWake; } void InputDispatcher::addRecentEventLocked(EventEntry* entry) { entry->refCount += 1; mRecentQueue.enqueueAtTail(entry); if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) { mRecentQueue.dequeueAtHead()->release(); } } sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y) { // Traverse windows from front to back to find touched window. size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId == displayId) { int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { // Found window. return windowHandle; } } } } } return NULL; } void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { case DROP_REASON_POLICY: #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("Dropped event because policy consumed it."); #endif reason = "inbound event was dropped because the policy consumed it"; break; case DROP_REASON_DISABLED: if (mLastDropReason != DROP_REASON_DISABLED) { ALOGI("Dropped event because input dispatch is disabled."); } reason = "inbound event was dropped because input dispatch is disabled"; break; case DROP_REASON_APP_SWITCH: ALOGI("Dropped event because of pending overdue app switch."); reason = "inbound event was dropped because of pending overdue app switch"; break; case DROP_REASON_BLOCKED: ALOGI("Dropped event because the current application is not responding and the user " "has started interacting with a different application."); reason = "inbound event was dropped because the current application is not responding " "and the user has started interacting with a different application"; break; case DROP_REASON_STALE: ALOGI("Dropped event because it is stale."); reason = "inbound event was dropped because it is stale"; break; default: ALOG_ASSERT(false); return; } switch (entry->type) { case EventEntry::TYPE_KEY: { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(entry); if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); } else { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); } break; } } } bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL || keyCode == AKEYCODE_APP_SWITCH; } bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } bool InputDispatcher::isAppSwitchPendingLocked() { return mAppSwitchDueTime != LONG_LONG_MAX; } void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { mAppSwitchDueTime = LONG_LONG_MAX; #if DEBUG_APP_SWITCH if (handled) { ALOGD("App switch has arrived."); } else { ALOGD("App switch was abandoned."); } #endif } bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; } bool InputDispatcher::haveCommandsLocked() const { return !mCommandQueue.isEmpty(); } bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; } do { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); Command command = commandEntry->command; (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry; } while (! mCommandQueue.isEmpty()); return true; } InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; } void InputDispatcher::drainInboundQueueLocked() { while (! mInboundQueue.isEmpty()) { EventEntry* entry = mInboundQueue.dequeueAtHead(); releaseInboundEventLocked(entry); } traceInboundQueueLengthLocked(); } void InputDispatcher::releasePendingEventLocked() { if (mPendingEvent) { resetANRTimeoutsLocked(); releaseInboundEventLocked(mPendingEvent); mPendingEvent = NULL; } } void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { #if DEBUG_DISPATCH_CYCLE ALOGD("Injected inbound event was dropped."); #endif setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); } if (entry == mNextUnblockedEvent) { mNextUnblockedEvent = NULL; } addRecentEventLocked(entry); entry->release(); } void InputDispatcher::resetKeyRepeatLocked() { if (mKeyRepeatState.lastKeyEntry) { mKeyRepeatState.lastKeyEntry->release(); mKeyRepeatState.lastKeyEntry = NULL; } } InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. uint32_t policyFlags = entry->policyFlags & (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED); if (entry->refCount == 1) { entry->recycle(); entry->eventTime = currentTime; entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { KeyEntry* newEntry = new KeyEntry(currentTime, entry->deviceId, entry->source, policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; entry->release(); entry = newEntry; } entry->syntheticRepeat = true; // Increment reference count since we keep a reference to the event in // mKeyRepeatState.lastKeyEntry in addition to the one we return. entry->refCount += 1; mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; return entry; } bool InputDispatcher::dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); #endif // Reset key repeating in case a keyboard device was added or removed or something. resetKeyRepeatLocked(); // Enqueue a command to run outside the lock to tell the policy that the configuration changed. CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyConfigurationChangedInterruptible); commandEntry->eventTime = entry->eventTime; return true; } bool InputDispatcher::dispatchDeviceResetLocked( nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); #endif CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); options.deviceId = entry->deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); return true; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && (entry->policyFlags & POLICY_FLAG_TRUSTED) && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device // driver is automatically generating key repeats itself. We take note of the // repeat here, but we disable our own next key repeat timer since it is clear that // we will not need to synthesize key repeats ourselves. entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves } else { // Not a repeat. Save key down state in case we do see a repeat later. resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; } else if (! entry->syntheticRepeat) { resetKeyRepeatLocked(); } if (entry->repeatCount == 1) { entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; } else { entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; } entry->dispatchInProgress = true; logOutboundKeyDetailsLocked("dispatchKey - ", entry); } // Handle case where the policy asked us to try again later last time. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { if (currentTime < entry->interceptKeyWakeupTime) { if (entry->interceptKeyWakeupTime < *nextWakeupTime) { *nextWakeupTime = entry->interceptKeyWakeupTime; } return false; // wait until next wakeup } entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; entry->interceptKeyWakeupTime = 0; } // Give the policy a chance to intercept the key. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != NULL) { commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; return false; // wait for the command to run } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { if (*dropReason == DROP_REASON_NOT_DROPPED) { *dropReason = DROP_REASON_POLICY; } } // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } // Identify targets. Vector inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { return true; } addMonitoringTargetsLocked(inputTargets); // Dispatch the key. dispatchEventLocked(currentTime, entry, inputTargets); return true; } void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " "repeatCount=%d, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, entry->downTime); #endif } bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { entry->dispatchInProgress = true; logOutboundMotionDetailsLocked("dispatchMotion - ", entry); } // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; // Identify targets. Vector inputTargets; bool conflictingPointerActions = false; int32_t injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { // Non touch event. (eg. trackball) injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { CancelationOptions::Mode mode(isPointerEvent ? CancelationOptions::CANCEL_POINTER_EVENTS : CancelationOptions::CANCEL_NON_POINTER_EVENTS); CancelationOptions options(mode, "input event injection failed"); synthesizeCancelationEventsForMonitorsLocked(options); } return true; } // TODO: support sending secondary display events to input monitors if (isMainDisplay(entry->displayId)) { addMonitoringTargetsLocked(inputTargets); } // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "conflicting pointer actions"); synthesizeCancelationEventsForAllConnectionsLocked(options); } dispatchEventLocked(currentTime, entry, inputTargets); return true; } void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f, relativeX=%f, relativeY=%f", i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType, entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); } #endif } void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector& inputTargets) { #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); #endif ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true pokeUserActivityLocked(eventEntry); for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " "is no longer registered with the input dispatcher.", inputTarget.inputChannel->getName().string()); #endif } } } int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp& applicationHandle, const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { if (applicationHandle == NULL && windowHandle == NULL) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for system to become ready for input. Reason: %s", reason); #endif mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), reason); #endif nsecs_t timeout; if (windowHandle != NULL) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != NULL) { timeout = applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); if (windowHandle != NULL) { mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; } if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { mInputTargetWaitApplicationHandle = applicationHandle; } } } if (mInputTargetWaitTimeoutExpired) { return INPUT_EVENT_INJECTION_TIMED_OUT; } if (currentTime >= mInputTargetWaitTimeoutTime) { onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, mInputTargetWaitStartTime, reason); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. *nextWakeupTime = LONG_LONG_MIN; return INPUT_EVENT_INJECTION_PENDING; } else { // Force poll loop to wake up when timeout is due. if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { *nextWakeupTime = mInputTargetWaitTimeoutTime; } return INPUT_EVENT_INJECTION_PENDING; } } void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, const sp& inputChannel) { if (newTimeout > 0) { // Extend the timeout. mInputTargetWaitTimeoutTime = now() + newTimeout; } else { // Give up. mInputTargetWaitTimeoutExpired = true; // Input state will not be realistic. Mark it out of sync. if (inputChannel.get()) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); sp windowHandle = connection->inputWindowHandle; if (windowHandle != NULL) { const InputWindowInfo* info = windowHandle->getInfo(); if (info) { ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId); if (stateIndex >= 0) { mTouchStatesByDisplay.editValueAt(stateIndex).removeWindow( windowHandle); } } } if (connection->status == Connection::STATUS_NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "application not responding"); synthesizeCancelationEventsForConnectionLocked(connection, options); } } } } } nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( nsecs_t currentTime) { if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { return currentTime - mInputTargetWaitStartTime; } return 0; } void InputDispatcher::resetANRTimeoutsLocked() { #if DEBUG_FOCUS ALOGD("Resetting ANR timeouts."); #endif // Reset input target wait timeout. mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; mInputTargetWaitApplicationHandle.clear(); } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; String8 reason; // If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application."); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check permissions. if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // Check whether the window is ready for more input. reason = checkWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry, "focused"); if (!reason.isEmpty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(mFocusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), inputTargets); // Done. Failed: Unresponsive: nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatisticsLocked(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findFocusedWindow finished: injectionResult=%d, " "timeSpentWaitingForApplication=%0.1fms", injectionResult, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, INJECTION_PERMISSION_DENIED }; nsecs_t startTime = now(); // For security reasons, we defer updating the touch state until we are sure that // event injection will be allowed. int32_t displayId = entry->displayId; int32_t action = entry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; // Update the touch state as needed based on the properties of the touch event. int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp newHoverWindowHandle; // Copy current touch state into mTempTouchState. // This state is always reset at the end of this function, so if we don't find state // for the specified display then our initial state will be empty. const TouchState* oldState = NULL; ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId); if (oldStateIndex >= 0) { oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex); mTempTouchState.copyFrom(*oldState); } bool isSplit = mTempTouchState.split; bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 && (mTempTouchState.deviceId != entry->deviceId || mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId); bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (switchedDevice && mTempTouchState.down && !down) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; switchedDevice = false; wrongDevice = true; goto Failed; } mTempTouchState.reset(); mTempTouchState.down = down; mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; isSplit = false; } if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ int32_t pointerIndex = getMotionEventActionPointerIndex(action); int32_t x = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp newTouchedWindowHandle; bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId != displayId) { continue; // wrong display } int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { newTouchedWindowHandle = windowHandle; break; // found touched window, exit window loop } } if (maskedAction == AMOTION_EVENT_ACTION_DOWN && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } else if (isWindowObscuredLocked(windowHandle)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } mTempTouchState.addOrUpdateWindow( windowHandle, outsideTargetFlags, BitSet32(0)); } } } // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { // New window supports splitting. isSplit = true; } else if (isSplit) { // New window does not support splitting but we have already split events. // Ignore the new window. newTouchedWindowHandle = NULL; } // Handle the case where we did not find a window. if (newTouchedWindowHandle == NULL) { // Try to assign the pointer to the first foreground window we find, if there is one. newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (newTouchedWindowHandle == NULL) { ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } } // Set target flags. int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } // Update hover state. if (isHoverAction) { newHoverWindowHandle = newTouchedWindowHandle; } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { newHoverWindowHandle = mLastHoverWindowHandle; } // Update the temporary touch state. BitSet32 pointerIds; if (isSplit) { uint32_t pointerId = entry->pointerProperties[pointerIndex].id; pointerIds.markBit(pointerId); } mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. if (! mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " "dropped the pointer down event."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check whether touches should slip outside of the current foreground window. if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 && mTempTouchState.isSlippery()) { int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); sp oldTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); sp newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (oldTouchedWindowHandle != newTouchedWindowHandle && newTouchedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s.", oldTouchedWindowHandle->getName().string(), newTouchedWindowHandle->getName().string()); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { isSplit = true; } int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } BitSet32 pointerIds; if (isSplit) { pointerIds.markBit(entry->pointerProperties[0].id); } mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } } if (newHoverWindowHandle != mLastHoverWindowHandle) { // Let the previous window know that the hover sequence is over. if (mLastHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->getName().string()); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); } // Let the new window know that the hover sequence is starting. if (newHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", newHoverWindowHandle->getName().string()); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); } } // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { bool haveForegroundWindow = false; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; if (! checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; } } } if (! haveForegroundWindow) { #if DEBUG_FOCUS ALOGD("Dropping event because there is no touched foreground window to receive it."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Permission granted to injection into all touched foreground windows. injectionPermission = INJECTION_PERMISSION_GRANTED; } // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { sp inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { mTempTouchState.addOrUpdateWindow(inputWindowHandle, InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); } } } } // Ensure all touched foreground windows are ready for new input. for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. String8 reason = checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry, "touched"); if (!reason.isEmpty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string()); goto Unresponsive; } } } // If this is the first pointer going down and the touched window has a wallpaper // then also add the touched wallpaper windows so they are locked in for the duration // of the touch gesture. // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper // engine only supports touch events. We would need to add a mechanism similar // to View.onGenericMotionEvent to enable wallpapers to handle these events. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle->getInfo()->hasWallpaper) { for (size_t i = 0; i < mWindowHandles.size(); i++) { sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { mTempTouchState.addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); } } } } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, inputTargets); } // Drop the outside or hover touch windows since we will not care about them // in the next iteration. mTempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { if (checkInjectionPermission(NULL, entry->injectionState)) { injectionPermission = INJECTION_PERMISSION_GRANTED; } else { injectionPermission = INJECTION_PERMISSION_DENIED; } } // Update final pieces of touch state if the injector had permission. if (injectionPermission == INJECTION_PERMISSION_GRANTED) { if (!wrongDevice) { if (switchedDevice) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Switched to a different device."); #endif *outConflictingPointerActions = true; } if (isHoverAction) { // Started hovering, therefore no longer down. if (oldState && oldState->down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Hover received while pointer was down."); #endif *outConflictingPointerActions = true; } mTempTouchState.reset(); if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; } } else if (maskedAction == AMOTION_EVENT_ACTION_UP || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. mTempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. if (oldState && oldState->down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Down received while already down."); #endif *outConflictingPointerActions = true; } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. if (isSplit) { int32_t pointerIndex = getMotionEventActionPointerIndex(action); uint32_t pointerId = entry->pointerProperties[pointerIndex].id; for (size_t i = 0; i < mTempTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.clearBit(pointerId); if (touchedWindow.pointerIds.isEmpty()) { mTempTouchState.windows.removeAt(i); continue; } } i += 1; } } } // Save changes unless the action was scroll in which case the temporary touch // state was only valid for this one action. if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { if (mTempTouchState.displayId >= 0) { if (oldStateIndex >= 0) { mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState); } else { mTouchStatesByDisplay.add(displayId, mTempTouchState); } } else if (oldStateIndex >= 0) { mTouchStatesByDisplay.removeItemsAt(oldStateIndex); } } // Update hover state. mLastHoverWindowHandle = newHoverWindowHandle; } } else { #if DEBUG_FOCUS ALOGD("Not updating touch focus because injection was denied."); #endif } Unresponsive: // Reset temporary touch state to ensure we release unnecessary references to input channels. mTempTouchState.reset(); nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatisticsLocked(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " "timeSpentWaitingForApplication=%0.1fms", injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds, Vector& inputTargets) { inputTargets.push(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget& target = inputTargets.editTop(); target.inputChannel = windowInfo->inputChannel; target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; target.pointerIds = pointerIds; } void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTargets) { for (size_t i = 0; i < mMonitoringChannels.size(); i++) { inputTargets.push(); InputTarget& target = inputTargets.editTop(); target.inputChannel = mMonitoringChannels[i]; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; target.xOffset = 0; target.yOffset = 0; target.pointerIds.clear(); target.scaleFactor = 1.0f; } } bool InputDispatcher::checkInjectionPermission(const sp& windowHandle, const InjectionState* injectionState) { if (injectionState && (windowHandle == NULL || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != NULL) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, windowHandle->getName().string(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } bool InputDispatcher::isWindowObscuredAtPointLocked( const sp& windowHandle, int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { sp otherHandle = mWindowHandles.itemAt(i); if (otherHandle == windowHandle) { break; } const InputWindowInfo* otherInfo = otherHandle->getInfo(); if (otherInfo->displayId == displayId && otherInfo->visible && !otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) { return true; } } return false; } bool InputDispatcher::isWindowObscuredLocked(const sp& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; const InputWindowInfo* windowInfo = windowHandle->getInfo(); size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { sp otherHandle = mWindowHandles.itemAt(i); if (otherHandle == windowHandle) { break; } const InputWindowInfo* otherInfo = otherHandle->getInfo(); if (otherInfo->displayId == displayId && otherInfo->visible && !otherInfo->isTrustedOverlay() && otherInfo->overlaps(windowInfo)) { return true; } } return false; } String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp& windowHandle, const EventEntry* eventEntry, const char* targetType) { // If the window is paused then keep waiting. if (windowHandle->getInfo()->paused) { return String8::format("Waiting because the %s window is paused.", targetType); } // If the window's connection is not registered then keep waiting. ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); if (connectionIndex < 0) { return String8::format("Waiting because the %s window's input channel is not " "registered with the input dispatcher. The window may be in the process " "of being removed.", targetType); } // If the connection is dead then keep waiting. sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status != Connection::STATUS_NORMAL) { return String8::format("Waiting because the %s window's input connection is %s." "The window may be in the process of being removed.", targetType, connection->getStatusLabel()); } // If the connection is backed up then keep waiting. if (connection->inputPublisherBlocked) { return String8::format("Waiting because the %s window's input channel is full. " "Outbound queue length: %d. Wait queue length: %d.", targetType, connection->outboundQueue.count(), connection->waitQueue.count()); } // Ensure that the dispatch queues aren't too far backed up for this event. if (eventEntry->type == EventEntry::TYPE_KEY) { // If the event is a key event, then we must wait for all previous events to // complete before delivering it because previous events may have the // side-effect of transferring focus to a different window and we want to // ensure that the following keys are sent to the new window. // // Suppose the user touches a button in a window then immediately presses "A". // If the button causes a pop-up window to appear then we want to ensure that // the "A" key is delivered to the new pop-up window. This is because users // often anticipate pending UI changes when typing on a keyboard. // To obtain this behavior, we must serialize key events with respect to all // prior input events. if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) { return String8::format("Waiting to send key event because the %s window has not " "finished processing all of the input events that were previously " "delivered to it. Outbound queue length: %d. Wait queue length: %d.", targetType, connection->outboundQueue.count(), connection->waitQueue.count()); } } else { // Touch events can always be sent to a window immediately because the user intended // to touch whatever was visible at the time. Even if focus changes or a new // window appears moments later, the touch event was meant to be delivered to // whatever window happened to be on screen at the time. // // Generic motion events, such as trackball or joystick events are a little trickier. // Like key events, generic motion events are delivered to the focused window. // Unlike key events, generic motion events don't tend to transfer focus to other // windows and it is not important for them to be serialized. So we prefer to deliver // generic motion events as soon as possible to improve efficiency and reduce lag // through batching. // // The one case where we pause input event delivery is when the wait queue is piling // up with lots of events because the application is not responding. // This condition ensures that ANRs are detected reliably. if (!connection->waitQueue.isEmpty() && currentTime >= connection->waitQueue.head->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) { return String8::format("Waiting to send non-key event because the %s window has not " "finished processing certain input events that were delivered to it over " "%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.", targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, connection->waitQueue.count(), (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f); } } return String8::empty(); } String8 InputDispatcher::getApplicationWindowLabelLocked( const sp& applicationHandle, const sp& windowHandle) { if (applicationHandle != NULL) { if (windowHandle != NULL) { String8 label(applicationHandle->getName()); label.append(" - "); label.append(windowHandle->getName()); return label; } else { return applicationHandle->getName(); } } else if (windowHandle != NULL) { return windowHandle->getName(); } else { return String8(""); } } void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { if (mFocusedWindowHandle != NULL) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { #if DEBUG_DISPATCH_CYCLE ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string()); #endif return; } } int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry->type) { case EventEntry::TYPE_MOTION: { const MotionEntry* motionEntry = static_cast(eventEntry); if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { return; } if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { eventType = USER_ACTIVITY_EVENT_TOUCH; } break; } case EventEntry::TYPE_KEY: { const KeyEntry* keyEntry = static_cast(eventEntry); if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { return; } eventType = USER_ACTIVITY_EVENT_BUTTON; break; } } CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doPokeUserActivityLockedInterruptible); commandEntry->eventTime = eventEntry->eventTime; commandEntry->userActivityEventType = eventType; } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " "xOffset=%f, yOffset=%f, scaleFactor=%f, " "pointerIds=0x%x", connection->getInputChannelName(), inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor, inputTarget->pointerIds.value); #endif // Skip this event if the connection status is not normal. // We don't want to enqueue additional outbound events if the connection is broken. if (connection->status != Connection::STATUS_NORMAL) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", connection->getInputChannelName(), connection->getStatusLabel()); #endif return; } // Split a motion event if needed. if (inputTarget->flags & InputTarget::FLAG_SPLIT) { ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); MotionEntry* originalMotionEntry = static_cast(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { MotionEntry* splitMotionEntry = splitMotionEvent( originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } #if DEBUG_FOCUS ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName()); logOutboundMotionDetailsLocked(" ", splitMotionEntry); #endif enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } } // Not splitting. Enqueue dispatch entries for the event as is. enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); } void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } } void InputDispatcher::enqueueDispatchEntryLocked( const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { int32_t inputTargetFlags = inputTarget->flags; if (!(inputTargetFlags & dispatchMode)) { return; } inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor); // Apply target flags and update the connection's input state. switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast(eventEntry); dispatchEntry->resolvedAction = keyEntry->action; dispatchEntry->resolvedFlags = keyEntry->flags; if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", connection->getInputChannelName()); #endif delete dispatchEntry; return; // skip the inconsistent event } break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(eventEntry); if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; } else { dispatchEntry->resolvedAction = motionEntry->action; } if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && !connection->inputState.isHovering( motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", connection->getInputChannelName()); #endif dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; } dispatchEntry->resolvedFlags = motionEntry->flags; if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; } if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", connection->getInputChannelName()); #endif delete dispatchEntry; return; // skip the inconsistent event } break; } } // Remember that we are waiting for this dispatch to complete. if (dispatchEntry->hasForegroundTarget()) { incrementPendingForegroundDispatchesLocked(eventEntry); } // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); traceOutboundQueueLengthLocked(connection); } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp& connection) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName()); #endif while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast(eventEntry); // Publish the key event. status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; // Set the X and Y offset depending on the input source. float xOffset, yOffset, scaleFactor; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { scaleFactor = dispatchEntry->scaleFactor; xOffset = dispatchEntry->xOffset * scaleFactor; yOffset = dispatchEntry->yOffset * scaleFactor; if (scaleFactor != 1.0f) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i] = motionEntry->pointerCoords[i]; scaledCoords[i].scale(scaleFactor); } usingCoords = scaledCoords; } } else { xOffset = 0.0f; yOffset = 0.0f; scaleFactor = 1.0f; // We don't want the dispatch target to know. if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i].clear(); } usingCoords = scaledCoords; } } // Publish the motion event. status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); break; } default: ALOG_ASSERT(false); return; } // Check the result. if (status) { if (status == WOULD_BLOCK) { if (connection->waitQueue.isEmpty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " "This is unexpected because the wait queue is empty, so the pipe " "should be empty and we shouldn't have any problems writing an " "event to it, status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " "waiting for the application to catch up", connection->getInputChannelName()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " "status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; } // Re-enqueue the event on the wait queue. connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", connection->getInputChannelName(), seq, toString(handled)); #endif connection->inputPublisherBlocked = false; if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return; } // Notify other system components and prepare to start the next dispatch cycle. onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); } void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", connection->getInputChannelName(), toString(notify)); #endif // Clear the dispatch queues. drainDispatchQueueLocked(&connection->outboundQueue); traceOutboundQueueLengthLocked(connection); drainDispatchQueueLocked(&connection->waitQueue); traceWaitQueueLengthLocked(connection); // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. if (connection->status == Connection::STATUS_NORMAL) { connection->status = Connection::STATUS_BROKEN; if (notify) { // Notify other system components. onDispatchCycleBrokenLocked(currentTime, connection); } } } void InputDispatcher::drainDispatchQueueLocked(Queue* queue) { while (!queue->isEmpty()) { DispatchEntry* dispatchEntry = queue->dequeueAtHead(); releaseDispatchEntryLocked(dispatchEntry); } } void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) { if (dispatchEntry->hasForegroundTarget()) { decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); } delete dispatchEntry; } int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { InputDispatcher* d = static_cast(data); { // acquire lock AutoMutex _l(d->mLock); ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) { ALOGE("Received spurious receive callback for unknown input channel. " "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } bool notify; sp connection = d->mConnectionsByFd.valueAt(connectionIndex); if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", connection->getInputChannelName(), events); return 1; } nsecs_t currentTime = now(); bool gotOne = false; status_t status; for (;;) { uint32_t seq; bool handled; status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); if (status) { break; } d->finishDispatchCycleLocked(currentTime, connection, seq, handled); gotOne = true; } if (gotOne) { d->runCommandsLockedInterruptible(); if (status == WOULD_BLOCK) { return 1; } } notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); } } else { // Monitor channels are never explicitly unregistered. // We do it automatically when the remote endpoint is closed so don't warn // about them. notify = !connection->monitor; if (notify) { ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " "events=0x%x", connection->getInputChannelName(), events); } } // Unregister the channel. d->unregisterInputChannelLocked(connection->inputChannel, notify); return 0; // remove the callback } // release lock } void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { synthesizeCancelationEventsForConnectionLocked( mConnectionsByFd.valueAt(i), options); } } void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( const CancelationOptions& options) { for (size_t i = 0; i < mMonitoringChannels.size(); i++) { synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options); } } void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); if (index >= 0) { synthesizeCancelationEventsForConnectionLocked( mConnectionsByFd.valueAt(index), options); } } void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const sp& connection, const CancelationOptions& options) { if (connection->status == Connection::STATUS_BROKEN) { return; } nsecs_t currentTime = now(); Vector cancelationEvents; connection->inputState.synthesizeCancelationEvents(currentTime, cancelationEvents, options); if (!cancelationEvents.isEmpty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " "with reality: %s, mode=%d.", connection->getInputChannelName(), cancelationEvents.size(), options.reason, options.mode); #endif for (size_t i = 0; i < cancelationEvents.size(); i++) { EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i); switch (cancelationEventEntry->type) { case EventEntry::TYPE_KEY: logOutboundKeyDetailsLocked("cancel - ", static_cast(cancelationEventEntry)); break; case EventEntry::TYPE_MOTION: logOutboundMotionDetailsLocked("cancel - ", static_cast(cancelationEventEntry)); break; } InputTarget target; sp windowHandle = getWindowHandleLocked(connection->inputChannel); if (windowHandle != NULL) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; target.yOffset = -windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; } else { target.xOffset = 0; target.yOffset = 0; target.scaleFactor = 1.0f; } target.inputChannel = connection->inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref &target, InputTarget::FLAG_DISPATCH_AS_IS); cancelationEventEntry->release(); } startDispatchCycleLocked(currentTime, connection); } } InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { ALOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; PointerProperties splitPointerProperties[MAX_POINTERS]; PointerCoords splitPointerCoords[MAX_POINTERS]; uint32_t originalPointerCount = originalMotionEntry->pointerCount; uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; originalPointerIndex++) { const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.hasBit(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); splitPointerCoords[splitPointerCount].copyFrom( originalMotionEntry->pointerCoords[originalPointerIndex]); splitPointerCount += 1; } } if (splitPointerCount != pointerIds.count()) { // This is bad. We are missing some of the pointers that we expected to deliver. // Most likely this indicates that we received an ACTION_MOVE events that has // different pointer ids than we expected based on the previous ACTION_DOWN // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " "we expected there to be %d pointers. This probably means we received " "a broken sequence of pointer ids from the input device.", splitPointerCount, pointerIds.count()); return NULL; } int32_t action = originalMotionEntry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.hasBit(pointerId)) { if (pointerIds.count() == 1) { // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { splitPointerIndex += 1; } action = maskedAction | (splitPointerIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. action = AMOTION_EVENT_ACTION_MOVE; } } MotionEntry* splitMotionEntry = new MotionEntry( originalMotionEntry->eventTime, originalMotionEntry->deviceId, originalMotionEntry->source, originalMotionEntry->policyFlags, action, originalMotionEntry->actionButton, originalMotionEntry->flags, originalMotionEntry->metaState, originalMotionEntry->buttonState, originalMotionEntry->edgeFlags, originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, originalMotionEntry->downTime, originalMotionEntry->displayId, splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; splitMotionEntry->injectionState->refCount += 1; } return splitMotionEntry; } void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); #endif bool needWake; { // acquire lock AutoMutex _l(mLock); ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime); needWake = enqueueInboundEventLocked(newEntry); } // release lock if (needWake) { mLooper->wake(); } } void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->flags, args->keyCode, args->scanCode, args->metaState, args->downTime); #endif if (!validateKeyEvent(args->action)) { return; } uint32_t policyFlags = args->policyFlags; int32_t flags = args->flags; int32_t metaState = args->metaState; if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { policyFlags |= POLICY_FLAG_VIRTUAL; flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; } if (policyFlags & POLICY_FLAG_FUNCTION) { metaState |= AMETA_FUNCTION_ON; } policyFlags |= POLICY_FLAG_TRUSTED; int32_t keyCode = args->keyCode; if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { newKeyCode = AKEYCODE_BACK; } else if (keyCode == AKEYCODE_ENTER) { newKeyCode = AKEYCODE_HOME; } if (newKeyCode != AKEYCODE_UNKNOWN) { AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; mReplacedKeys.add(replacement, newKeyCode); keyCode = newKeyCode; metaState &= ~AMETA_META_ON; } } else if (args->action == AKEY_EVENT_ACTION_UP) { // In order to maintain a consistent stream of up and down events, check to see if the key // going up is one we've replaced in a down event and haven't yet replaced in an up event, // even if the modifier was released between the down and the up events. AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; ssize_t index = mReplacedKeys.indexOfKey(replacement); if (index >= 0) { keyCode = mReplacedKeys.valueAt(index); mReplacedKeys.removeItemsAt(index); metaState &= ~AMETA_META_ON; } } KeyEvent event; event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime); mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (shouldSendKeyToInputFilterLocked(args)) { mLock.unlock(); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } int32_t repeatCount = 0; KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } } bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) { return mInputFilterEnabled; } void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", i, args->pointerProperties[i].id, args->pointerProperties[i].toolType, args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, args->pointerProperties)) { return; } uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (shouldSendMotionToInputFilterLocked(args)) { mLock.unlock(); MotionEvent event; event.initialize(args->deviceId, args->source, args->action, args->actionButton, args->flags, args->edgeFlags, args->metaState, args->buttonState, 0, 0, args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } // Just enqueue a new motion event. MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } } bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) { // TODO: support sending secondary display events to input filter return mInputFilterEnabled && isMainDisplay(args->displayId); } void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x", args->eventTime, args->policyFlags, args->switchValues, args->switchMask); #endif uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; mPolicy->notifySwitch(args->eventTime, args->switchValues, args->switchMask, policyFlags); } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", args->eventTime, args->deviceId); #endif bool needWake; { // acquire lock AutoMutex _l(mLock); DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); needWake = enqueueInboundEventLocked(newEntry); } // release lock if (needWake) { mLooper->wake(); } } int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= POLICY_FLAG_TRUSTED; } EventEntry* firstInjectedEntry; EventEntry* lastInjectedEntry; switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: { const KeyEvent* keyEvent = static_cast(event); int32_t action = keyEvent->getAction(); if (! validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } int32_t flags = keyEvent->getFlags(); if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { policyFlags |= POLICY_FLAG_VIRTUAL; } if (!(policyFlags & POLICY_FLAG_FILTERED)) { mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); } mLock.lock(); firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(), keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags, action, flags, keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), keyEvent->getRepeatCount(), keyEvent->getDownTime()); lastInjectedEntry = firstInjectedEntry; break; } case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent* motionEvent = static_cast(event); int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); int32_t actionButton = motionEvent->getActionButton(); if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { return INPUT_EVENT_INJECTION_FAILED; } if (!(policyFlags & POLICY_FLAG_FILTERED)) { nsecs_t eventTime = motionEvent->getEventTime(); mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); } mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); firstInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), displayId, uint32_t(pointerCount), pointerProperties, samplePointerCoords, motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry = firstInjectedEntry; for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), displayId, uint32_t(pointerCount), pointerProperties, samplePointerCoords, motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry->next = nextInjectedEntry; lastInjectedEntry = nextInjectedEntry; } break; } default: ALOGW("Cannot inject event of type %d", event->getType()); return INPUT_EVENT_INJECTION_FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { injectionState->injectionIsAsync = true; } injectionState->refCount += 1; lastInjectedEntry->injectionState = injectionState; bool needWake = false; for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { EventEntry* nextEntry = entry->next; needWake |= enqueueInboundEventLocked(entry); entry = nextEntry; } mLock.unlock(); if (needWake) { mLooper->wake(); } int32_t injectionResult; { // acquire lock AutoMutex _l(mLock); if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; } else { for (;;) { injectionResult = injectionState->injectionResult; if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { break; } nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for injection result " "to become available."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; } mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout); } if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { while (injectionState->pendingForegroundDispatches != 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", injectionState->pendingForegroundDispatches); #endif nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for pending foreground " "dispatches to finish."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; } mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout); } } } injectionState->release(); } // release lock #if DEBUG_INJECTION ALOGD("injectInputEvent - Finished with result %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); #endif return injectionResult; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { InjectionState* injectionState = entry->injectionState; if (injectionState) { #if DEBUG_INJECTION ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); #endif if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { // Log the outcome since the injector did not wait for the injection result. switch (injectionResult) { case INPUT_EVENT_INJECTION_SUCCEEDED: ALOGV("Asynchronous input event injection succeeded."); break; case INPUT_EVENT_INJECTION_FAILED: ALOGW("Asynchronous input event injection failed."); break; case INPUT_EVENT_INJECTION_PERMISSION_DENIED: ALOGW("Asynchronous input event injection permission denied."); break; case INPUT_EVENT_INJECTION_TIMED_OUT: ALOGW("Asynchronous input event injection timed out."); break; } } injectionState->injectionResult = injectionResult; mInjectionResultAvailableCondition.broadcast(); } } void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState) { injectionState->pendingForegroundDispatches += 1; } } void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState) { injectionState->pendingForegroundDispatches -= 1; if (injectionState->pendingForegroundDispatches == 0) { mInjectionSyncFinishedCondition.broadcast(); } } } sp InputDispatcher::getWindowHandleLocked( const sp& inputChannel) const { size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { const sp& windowHandle = mWindowHandles.itemAt(i); if (windowHandle->getInputChannel() == inputChannel) { return windowHandle; } } return NULL; } bool InputDispatcher::hasWindowHandleLocked( const sp& windowHandle) const { size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { if (mWindowHandles.itemAt(i) == windowHandle) { return true; } } return false; } void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) { #if DEBUG_FOCUS ALOGD("setInputWindows"); #endif { // acquire lock AutoMutex _l(mLock); Vector > oldWindowHandles = mWindowHandles; mWindowHandles = inputWindowHandles; sp newFocusedWindowHandle; bool foundHoveredWindow = false; for (size_t i = 0; i < mWindowHandles.size(); i++) { const sp& windowHandle = mWindowHandles.itemAt(i); if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) { mWindowHandles.removeAt(i--); continue; } if (windowHandle->getInfo()->hasFocus) { newFocusedWindowHandle = windowHandle; } if (windowHandle == mLastHoverWindowHandle) { foundHoveredWindow = true; } } if (!foundHoveredWindow) { mLastHoverWindowHandle = NULL; } if (mFocusedWindowHandle != newFocusedWindowHandle) { if (mFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus left window: %s", mFocusedWindowHandle->getName().string()); #endif sp focusedInputChannel = mFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != NULL) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); synthesizeCancelationEventsForInputChannelLocked( focusedInputChannel, options); } } if (newFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s", newFocusedWindowHandle->getName().string()); #endif } mFocusedWindowHandle = newFocusedWindowHandle; } for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { TouchState& state = mTouchStatesByDisplay.editValueAt(d); for (size_t i = 0; i < state.windows.size(); i++) { TouchedWindow& touchedWindow = state.windows.editItemAt(i); if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s", touchedWindow.windowHandle->getName().string()); #endif sp touchedInputChannel = touchedWindow.windowHandle->getInputChannel(); if (touchedInputChannel != NULL) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); synthesizeCancelationEventsForInputChannelLocked( touchedInputChannel, options); } state.windows.removeAt(i--); } } } // Release information for windows that are no longer present. // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed // which might not happen until the next GC. for (size_t i = 0; i < oldWindowHandles.size(); i++) { const sp& oldWindowHandle = oldWindowHandles.itemAt(i); if (!hasWindowHandleLocked(oldWindowHandle)) { #if DEBUG_FOCUS ALOGD("Window went away: %s", oldWindowHandle->getName().string()); #endif oldWindowHandle->releaseInfo(); } } } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } void InputDispatcher::setFocusedApplication( const sp& inputApplicationHandle) { #if DEBUG_FOCUS ALOGD("setFocusedApplication"); #endif { // acquire lock AutoMutex _l(mLock); if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) { if (mFocusedApplicationHandle != inputApplicationHandle) { if (mFocusedApplicationHandle != NULL) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); } mFocusedApplicationHandle = inputApplicationHandle; } } else if (mFocusedApplicationHandle != NULL) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); mFocusedApplicationHandle.clear(); } #if DEBUG_FOCUS //logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { #if DEBUG_FOCUS ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); #endif bool changed; { // acquire lock AutoMutex _l(mLock); if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { if (mDispatchFrozen && !frozen) { resetANRTimeoutsLocked(); } if (mDispatchEnabled && !enabled) { resetAndDropEverythingLocked("dispatcher is being disabled"); } mDispatchEnabled = enabled; mDispatchFrozen = frozen; changed = true; } else { changed = false; } #if DEBUG_FOCUS //logDispatchStateLocked(); #endif } // release lock if (changed) { // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } } void InputDispatcher::setInputFilterEnabled(bool enabled) { #if DEBUG_FOCUS ALOGD("setInputFilterEnabled: enabled=%d", enabled); #endif { // acquire lock AutoMutex _l(mLock); if (mInputFilterEnabled == enabled) { return; } mInputFilterEnabled = enabled; resetAndDropEverythingLocked("input filter is being enabled or disabled"); } // release lock // Wake up poll loop since there might be work to do to drop everything. mLooper->wake(); } bool InputDispatcher::transferTouchFocus(const sp& fromChannel, const sp& toChannel) { #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", fromChannel->getName().string(), toChannel->getName().string()); #endif { // acquire lock AutoMutex _l(mLock); sp fromWindowHandle = getWindowHandleLocked(fromChannel); sp toWindowHandle = getWindowHandleLocked(toChannel); if (fromWindowHandle == NULL || toWindowHandle == NULL) { #if DEBUG_FOCUS ALOGD("Cannot transfer focus because from or to window not found."); #endif return false; } if (fromWindowHandle == toWindowHandle) { #if DEBUG_FOCUS ALOGD("Trivial transfer to same window."); #endif return true; } if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { #if DEBUG_FOCUS ALOGD("Cannot transfer focus because windows are on different displays."); #endif return false; } bool found = false; for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { TouchState& state = mTouchStatesByDisplay.editValueAt(d); for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; if (touchedWindow.windowHandle == fromWindowHandle) { int32_t oldTargetFlags = touchedWindow.targetFlags; BitSet32 pointerIds = touchedWindow.pointerIds; state.windows.removeAt(i); int32_t newTargetFlags = oldTargetFlags & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; goto Found; } } } Found: if (! found) { #if DEBUG_FOCUS ALOGD("Focus transfer failed because from window did not have focus."); #endif return false; } ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { sp fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); sp toConnection = mConnectionsByFd.valueAt(toConnectionIndex); fromConnection->inputState.copyPointerStateTo(toConnection->inputState); CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); } #if DEBUG_FOCUS logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); return true; } void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { #if DEBUG_FOCUS ALOGD("Resetting and dropping all events (%s).", reason); #endif CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); resetKeyRepeatLocked(); releasePendingEventLocked(); drainInboundQueueLocked(); resetANRTimeoutsLocked(); mTouchStatesByDisplay.clear(); mLastHoverWindowHandle.clear(); mReplacedKeys.clear(); } void InputDispatcher::logDispatchStateLocked() { String8 dump; dumpDispatchStateLocked(dump); char* text = dump.lockBuffer(dump.size()); char* start = text; while (*start != '\0') { char* end = strchr(start, '\n'); if (*end == '\n') { *(end++) = '\0'; } ALOGD("%s", start); start = end; } } void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplicationHandle != NULL) { dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", mFocusedApplicationHandle->getName().string(), mFocusedApplicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } else { dump.append(INDENT "FocusedApplication: \n"); } dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : ""); if (!mTouchStatesByDisplay.isEmpty()) { dump.appendFormat(INDENT "TouchStatesByDisplay:\n"); for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", state.displayId, toString(state.down), toString(state.split), state.deviceId, state.source); if (!state.windows.isEmpty()) { dump.append(INDENT3 "Windows:\n"); for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", i, touchedWindow.windowHandle->getName().string(), touchedWindow.pointerIds.value, touchedWindow.targetFlags); } } else { dump.append(INDENT3 "Windows: \n"); } } } else { dump.append(INDENT "TouchStates: \n"); } if (!mWindowHandles.isEmpty()) { dump.append(INDENT "Windows:\n"); for (size_t i = 0; i < mWindowHandles.size(); i++) { const sp& windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump.appendFormat(INDENT2 "%zu: name='%s', displayId=%d, " "paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], scale=%f, " "touchableRegion=", i, windowInfo->name.string(), windowInfo->displayId, toString(windowInfo->paused), toString(windowInfo->hasFocus), toString(windowInfo->hasWallpaper), toString(windowInfo->visible), toString(windowInfo->canReceiveKeys), windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, windowInfo->layer, windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, windowInfo->scaleFactor); dumpRegion(dump, windowInfo->touchableRegion); dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures); dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", windowInfo->ownerPid, windowInfo->ownerUid, windowInfo->dispatchingTimeout / 1000000.0); } } else { dump.append(INDENT "Windows: \n"); } if (!mMonitoringChannels.isEmpty()) { dump.append(INDENT "MonitoringChannels:\n"); for (size_t i = 0; i < mMonitoringChannels.size(); i++) { const sp& channel = mMonitoringChannels[i]; dump.appendFormat(INDENT2 "%zu: '%s'\n", i, channel->getName().string()); } } else { dump.append(INDENT "MonitoringChannels: \n"); } nsecs_t currentTime = now(); // Dump recently dispatched or dropped events from oldest to newest. if (!mRecentQueue.isEmpty()) { dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count()); for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) { dump.append(INDENT2); entry->appendDescription(dump); dump.appendFormat(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump.append(INDENT "RecentQueue: \n"); } // Dump event currently being dispatched. if (mPendingEvent) { dump.append(INDENT "PendingEvent:\n"); dump.append(INDENT2); mPendingEvent->appendDescription(dump); dump.appendFormat(", age=%0.1fms\n", (currentTime - mPendingEvent->eventTime) * 0.000001f); } else { dump.append(INDENT "PendingEvent: \n"); } // Dump inbound events from oldest to newest. if (!mInboundQueue.isEmpty()) { dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { dump.append(INDENT2); entry->appendDescription(dump); dump.appendFormat(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump.append(INDENT "InboundQueue: \n"); } if (!mReplacedKeys.isEmpty()) { dump.append(INDENT "ReplacedKeys:\n"); for (size_t i = 0; i < mReplacedKeys.size(); i++) { const KeyReplacement& replacement = mReplacedKeys.keyAt(i); int32_t newKeyCode = mReplacedKeys.valueAt(i); dump.appendFormat(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, replacement.keyCode, replacement.deviceId, newKeyCode); } } else { dump.append(INDENT "ReplacedKeys: \n"); } if (!mConnectionsByFd.isEmpty()) { dump.append(INDENT "Connections:\n"); for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp& connection = mConnectionsByFd.valueAt(i); dump.appendFormat(INDENT2 "%zu: channelName='%s', windowName='%s', " "status=%s, monitor=%s, inputPublisherBlocked=%s\n", i, connection->getInputChannelName(), connection->getWindowName(), connection->getStatusLabel(), toString(connection->monitor), toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.isEmpty()) { dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n", connection->outboundQueue.count()); for (DispatchEntry* entry = connection->outboundQueue.head; entry; entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { dump.append(INDENT3 "OutboundQueue: \n"); } if (!connection->waitQueue.isEmpty()) { dump.appendFormat(INDENT3 "WaitQueue: length=%u\n", connection->waitQueue.count()); for (DispatchEntry* entry = connection->waitQueue.head; entry; entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, " "age=%0.1fms, wait=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f, (currentTime - entry->deliveryTime) * 0.000001f); } } else { dump.append(INDENT3 "WaitQueue: \n"); } } } else { dump.append(INDENT "Connections: \n"); } if (isAppSwitchPendingLocked()) { dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n", (mAppSwitchDueTime - now()) / 1000000.0); } else { dump.append(INDENT "AppSwitch: not pending\n"); } dump.append(INDENT "Configuration:\n"); dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } status_t InputDispatcher::registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), toString(monitor)); #endif { // acquire lock AutoMutex _l(mLock); if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", inputChannel->getName().string()); return BAD_VALUE; } sp connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); } // release lock // Wake the looper because some connections have changed. mLooper->wake(); return OK; } status_t InputDispatcher::unregisterInputChannel(const sp& inputChannel) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); #endif { // acquire lock AutoMutex _l(mLock); status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/); if (status) { return status; } } // release lock // Wake the poll loop because removing the connection may have changed the current // synchronization state. mLooper->wake(); return OK; } status_t InputDispatcher::unregisterInputChannelLocked(const sp& inputChannel, bool notify) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex < 0) { ALOGW("Attempted to unregister already unregistered input channel '%s'", inputChannel->getName().string()); return BAD_VALUE; } sp connection = mConnectionsByFd.valueAt(connectionIndex); mConnectionsByFd.removeItemsAt(connectionIndex); if (connection->monitor) { removeMonitorChannelLocked(inputChannel); } mLooper->removeFd(inputChannel->getFd()); nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); connection->status = Connection::STATUS_ZOMBIE; return OK; } void InputDispatcher::removeMonitorChannelLocked(const sp& inputChannel) { for (size_t i = 0; i < mMonitoringChannels.size(); i++) { if (mMonitoringChannels[i] == inputChannel) { mMonitoringChannels.removeAt(i); break; } } } ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputChannel.get() == inputChannel.get()) { return connectionIndex; } } return -1; } void InputDispatcher::onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; } void InputDispatcher::onDispatchCycleBrokenLocked( nsecs_t currentTime, const sp& connection) { ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", connection->getInputChannelName()); CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); commandEntry->connection = connection; } void InputDispatcher::onANRLocked( nsecs_t currentTime, const sp& applicationHandle, const sp& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), dispatchLatency, waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(NULL); struct tm tm; localtime_r(&t, &tm); char timestr[64]; strftime(timestr, sizeof(timestr), "%F %T", &tm); mLastANRState.clear(); mLastANRState.append(INDENT "ANR:\n"); mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr); mLastANRState.appendFormat(INDENT2 "Window: %s\n", getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; commandEntry->inputWindowHandle = windowHandle; commandEntry->reason = reason; } void InputDispatcher::doNotifyConfigurationChangedInterruptible( CommandEntry* commandEntry) { mLock.unlock(); mPolicy->notifyConfigurationChanged(commandEntry->eventTime); mLock.lock(); } void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( CommandEntry* commandEntry) { sp connection = commandEntry->connection; if (connection->status != Connection::STATUS_ZOMBIE) { mLock.unlock(); mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); mLock.lock(); } } void InputDispatcher::doNotifyANRLockedInterruptible( CommandEntry* commandEntry) { mLock.unlock(); nsecs_t newTimeout = mPolicy->notifyANR( commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle, commandEntry->reason); mLock.lock(); resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputWindowHandle != NULL ? commandEntry->inputWindowHandle->getInputChannel() : NULL); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; KeyEvent event; initializeKeyEvent(&event, entry); mLock.unlock(); nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); if (delay < 0) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; } entry->release(); } void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp connection = commandEntry->connection; nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; bool handled = commandEntry->handled; // Handle post-event policy actions. DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); if (dispatchEntry) { nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { String8 msg; msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", connection->getWindowName(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg); ALOGI("%s", msg.string()); } bool restartEvent; if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry); restartEvent = afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry); restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry, handled); } else { restartEvent = false; } // Dequeue the event and start the next cycle. // Note that because the lock might have been released, it is possible that the // contents of the wait queue to have been drained, so we need to double-check // a few things. if (dispatchEntry == connection->findWaitQueueEntry(seq)) { connection->waitQueue.dequeue(dispatchEntry); traceWaitQueueLengthLocked(connection); if (restartEvent && connection->status == Connection::STATUS_NORMAL) { connection->outboundQueue.enqueueAtHead(dispatchEntry); traceOutboundQueueLengthLocked(connection); } else { releaseDispatchEntryLocked(dispatchEntry); } } // Start the next dispatch cycle for this connection. startDispatchCycleLocked(now(), connection); } } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { // Get the fallback key state. // Clear it out after dispatching the UP. int32_t originalKeyCode = keyEntry->keyCode; int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); if (keyEntry->action == AKEY_EVENT_ACTION_UP) { connection->inputState.removeFallbackKey(originalKeyCode); } if (handled || !dispatchEntry->hasForegroundTarget()) { // If the application handles the original key for which we previously // generated a fallback or if the window is not a foreground window, // then cancel the associated fallback key, if any. if (fallbackKeyCode != -1) { // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); mLock.unlock(); mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); // Cancel the fallback key. if (fallbackKeyCode != AKEYCODE_UNKNOWN) { CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "application handled the original non-fallback key " "or is no longer a foreground target, " "canceling previously dispatched fallback key"); options.keyCode = fallbackKeyCode; synthesizeCancelationEventsForConnectionLocked(connection, options); } connection->inputState.removeFallbackKey(originalKeyCode); } } else { // If the application did not handle a non-fallback key, first check // that we are in a good state to perform unhandled key event processing // Then ask the policy what to do with it. bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0; if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Skipping unhandled key event processing " "since this is not an initial down. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif return false; } // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); mLock.unlock(); bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); if (connection->status != Connection::STATUS_NORMAL) { connection->inputState.removeFallbackKey(originalKeyCode); return false; } // Latch the fallback keycode for this key on an initial down. // The fallback keycode cannot change at any other point in the lifecycle. if (initialDown) { if (fallback) { fallbackKeyCode = event.getKeyCode(); } else { fallbackKeyCode = AKEYCODE_UNKNOWN; } connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } ALOG_ASSERT(fallbackKeyCode != -1); // Cancel the fallback key if the policy decides not to send it anymore. // We will continue to dispatch the key to the policy but we will no // longer dispatch a fallback key to the application. if (fallbackKeyCode != AKEYCODE_UNKNOWN && (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS if (fallback) { ALOGD("Unhandled key event: Policy requested to send key %d" "as a fallback for %d, but on the DOWN it had requested " "to send %d instead. Fallback canceled.", event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { ALOGD("Unhandled key event: Policy did not request fallback for %d, " "but on the DOWN it had requested to send %d. " "Fallback canceled.", originalKeyCode, fallbackKeyCode); } #endif CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "canceling fallback, policy no longer desires it"); options.keyCode = fallbackKeyCode; synthesizeCancelationEventsForConnectionLocked(connection, options); fallback = false; fallbackKeyCode = AKEYCODE_UNKNOWN; if (keyEntry->action != AKEY_EVENT_ACTION_UP) { connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } } #if DEBUG_OUTBOUND_EVENT_DETAILS { String8 msg; const KeyedVector& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); } ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", fallbackKeys.size(), msg.string()); } #endif if (fallback) { // Restart the dispatch cycle using the fallback key. keyEntry->eventTime = event.getEventTime(); keyEntry->deviceId = event.getDeviceId(); keyEntry->source = event.getSource(); keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; keyEntry->keyCode = fallbackKeyCode; keyEntry->scanCode = event.getScanCode(); keyEntry->metaState = event.getMetaState(); keyEntry->repeatCount = event.getRepeatCount(); keyEntry->downTime = event.getDownTime(); keyEntry->syntheticRepeat = false; #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Dispatching fallback key. " "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif return true; // restart the event } else { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: No fallback key."); #endif } } } return false; } bool InputDispatcher::afterMotionEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { return false; } void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); mLock.lock(); } void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, entry->downTime, entry->eventTime); } void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { // TODO Write some statistics about how long we spend waiting. } void InputDispatcher::traceInboundQueueLengthLocked() { if (ATRACE_ENABLED()) { ATRACE_INT("iq", mInboundQueue.count()); } } void InputDispatcher::traceOutboundQueueLengthLocked(const sp& connection) { if (ATRACE_ENABLED()) { char counterName[40]; snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName()); ATRACE_INT(counterName, connection->outboundQueue.count()); } } void InputDispatcher::traceWaitQueueLengthLocked(const sp& connection) { if (ATRACE_ENABLED()) { char counterName[40]; snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName()); ATRACE_INT(counterName, connection->waitQueue.count()); } } void InputDispatcher::dump(String8& dump) { AutoMutex _l(mLock); dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); if (!mLastANRState.isEmpty()) { dump.append("\nInput Dispatcher State at time of last ANR:\n"); dump.append(mLastANRState); } } void InputDispatcher::monitor() { // Acquire and release the lock to ensure that the dispatcher has not deadlocked. mLock.lock(); mLooper->wake(); mDispatcherIsAliveCondition.wait(mLock); mLock.unlock(); } // --- InputDispatcher::InjectionState --- InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : refCount(1), injectorPid(injectorPid), injectorUid(injectorUid), injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) { } InputDispatcher::InjectionState::~InjectionState() { } void InputDispatcher::InjectionState::release() { refCount -= 1; if (refCount == 0) { delete this; } else { ALOG_ASSERT(refCount > 0); } } // --- InputDispatcher::EventEntry --- InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), injectionState(NULL), dispatchInProgress(false) { } InputDispatcher::EventEntry::~EventEntry() { releaseInjectionState(); } void InputDispatcher::EventEntry::release() { refCount -= 1; if (refCount == 0) { delete this; } else { ALOG_ASSERT(refCount > 0); } } void InputDispatcher::EventEntry::releaseInjectionState() { if (injectionState) { injectionState->release(); injectionState = NULL; } } // --- InputDispatcher::ConfigurationChangedEntry --- InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { } InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { } void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); } // --- InputDispatcher::DeviceResetEntry --- InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : EventEntry(TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) { } InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { } void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags); } // --- InputDispatcher::KeyEntry --- InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime) : EventEntry(TYPE_KEY, eventTime, policyFlags), deviceId(deviceId), source(source), action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), metaState(metaState), repeatCount(repeatCount), downTime(downTime), syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), interceptKeyWakeupTime(0) { } InputDispatcher::KeyEntry::~KeyEntry() { } void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, " "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags); } void InputDispatcher::KeyEntry::recycle() { releaseInjectionState(); dispatchInProgress = false; syntheticRepeat = false; interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; interceptKeyWakeupTime = 0; } // --- InputDispatcher::MotionEntry --- InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), deviceId(deviceId), source(source), action(action), actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), displayId(displayId), pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); if (xOffset || yOffset) { this->pointerCoords[i].applyOffset(xOffset, yOffset); } } } InputDispatcher::MotionEntry::~MotionEntry() { } void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, displayId); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { msg.append(", "); } msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(), pointerCoords[i].getY()); } msg.appendFormat("]), policyFlags=0x%08x", policyFlags); } // --- InputDispatcher::DispatchEntry --- volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : seq(nextSeq()), eventEntry(eventEntry), targetFlags(targetFlags), xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), deliveryTime(0), resolvedAction(0), resolvedFlags(0) { eventEntry->refCount += 1; } InputDispatcher::DispatchEntry::~DispatchEntry() { eventEntry->release(); } uint32_t InputDispatcher::DispatchEntry::nextSeq() { // Sequence number 0 is reserved and will never be returned. uint32_t seq; do { seq = android_atomic_inc(&sNextSeqAtomic); } while (!seq); return seq; } // --- InputDispatcher::InputState --- InputDispatcher::InputState::InputState() { } InputDispatcher::InputState::~InputState() { } bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); } bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.deviceId == deviceId && memento.source == source && memento.displayId == displayId && memento.hovering) { return true; } } return false; } bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) { switch (action) { case AKEY_EVENT_ACTION_UP: { if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { for (size_t i = 0; i < mFallbackKeys.size(); ) { if (mFallbackKeys.valueAt(i) == entry->keyCode) { mFallbackKeys.removeItemsAt(i); } else { i += 1; } } } ssize_t index = findKeyMemento(entry); if (index >= 0) { mKeyMementos.removeAt(index); return true; } /* FIXME: We can't just drop the key up event because that prevents creating * popup windows that are automatically shown when a key is held and then * dismissed when the key is released. The problem is that the popup will * not have received the original key down, so the key up will be considered * to be inconsistent with its observed state. We could perhaps handle this * by synthesizing a key down but that will cause other problems. * * So for now, allow inconsistent key up events to be dispatched. * #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " "keyCode=%d, scanCode=%d", entry->deviceId, entry->source, entry->keyCode, entry->scanCode); #endif return false; */ return true; } case AKEY_EVENT_ACTION_DOWN: { ssize_t index = findKeyMemento(entry); if (index >= 0) { mKeyMementos.removeAt(index); } addKeyMemento(entry, flags); return true; } default: return true; } } bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action, int32_t flags) { int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; switch (actionMasked) { case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: { ssize_t index = findMotionMemento(entry, false /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " "actionMasked=%d", entry->deviceId, entry->source, actionMasked); #endif return false; } case AMOTION_EVENT_ACTION_DOWN: { ssize_t index = findMotionMemento(entry, false /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); } addMotionMemento(entry, flags, false /*hovering*/); return true; } case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_MOVE: { if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) { // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need to // generate cancellation events for these since they're based in relative rather than // absolute units. return true; } ssize_t index = findMotionMemento(entry, false /*hovering*/); if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) { // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. Any // other value and we need to track the motion so we can send cancellation events for // anything generating fallback events (e.g. DPad keys for joystick movements). if (index >= 0) { if (entry->pointerCoords[0].isEmpty()) { mMotionMementos.removeAt(index); } else { MotionMemento& memento = mMotionMementos.editItemAt(index); memento.setPointers(entry); } } else if (!entry->pointerCoords[0].isEmpty()) { addMotionMemento(entry, flags, false /*hovering*/); } // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. return true; } if (index >= 0) { MotionMemento& memento = mMotionMementos.editItemAt(index); memento.setPointers(entry); return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion pointer up/down or move event: " "deviceId=%d, source=%08x, actionMasked=%d", entry->deviceId, entry->source, actionMasked); #endif return false; } case AMOTION_EVENT_ACTION_HOVER_EXIT: { ssize_t index = findMotionMemento(entry, true /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x", entry->deviceId, entry->source); #endif return false; } case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: { ssize_t index = findMotionMemento(entry, true /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); } addMotionMemento(entry, flags, true /*hovering*/); return true; } default: return true; } } ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos.itemAt(i); if (memento.deviceId == entry->deviceId && memento.source == entry->source && memento.keyCode == entry->keyCode && memento.scanCode == entry->scanCode) { return i; } } return -1; } ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, bool hovering) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.deviceId == entry->deviceId && memento.source == entry->source && memento.displayId == entry->displayId && memento.hovering == hovering) { return i; } } return -1; } void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { mKeyMementos.push(); KeyMemento& memento = mKeyMementos.editTop(); memento.deviceId = entry->deviceId; memento.source = entry->source; memento.keyCode = entry->keyCode; memento.scanCode = entry->scanCode; memento.metaState = entry->metaState; memento.flags = flags; memento.downTime = entry->downTime; memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering) { mMotionMementos.push(); MotionMemento& memento = mMotionMementos.editTop(); memento.deviceId = entry->deviceId; memento.source = entry->source; memento.flags = flags; memento.xPrecision = entry->xPrecision; memento.yPrecision = entry->yPrecision; memento.downTime = entry->downTime; memento.displayId = entry->displayId; memento.setPointers(entry); memento.hovering = hovering; memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { pointerCount = entry->pointerCount; for (uint32_t i = 0; i < entry->pointerCount; i++) { pointerProperties[i].copyFrom(entry->pointerProperties[i]); pointerCoords[i].copyFrom(entry->pointerCoords[i]); } } void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, Vector& outEvents, const CancelationOptions& options) { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos.itemAt(i); if (shouldCancelKey(memento, options)) { outEvents.push(new KeyEntry(currentTime, memento.deviceId, memento.source, memento.policyFlags, AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); } } for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (shouldCancelMotion(memento, options)) { outEvents.push(new MotionEntry(currentTime, memento.deviceId, memento.source, memento.policyFlags, memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, memento.flags, 0, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.displayId, memento.pointerCount, memento.pointerProperties, memento.pointerCoords, 0, 0)); } } } void InputDispatcher::InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); mFallbackKeys.clear(); } void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { for (size_t j = 0; j < other.mMotionMementos.size(); ) { const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); if (memento.deviceId == otherMemento.deviceId && memento.source == otherMemento.source && memento.displayId == otherMemento.displayId) { other.mMotionMementos.removeAt(j); } else { j += 1; } } other.mMotionMementos.push(memento); } } } int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); return index >= 0 ? mFallbackKeys.valueAt(index) : -1; } void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) { ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); if (index >= 0) { mFallbackKeys.replaceValueAt(index, fallbackKeyCode); } else { mFallbackKeys.add(originalKeyCode, fallbackKeyCode); } } void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { mFallbackKeys.removeItem(originalKeyCode); } bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) { if (options.keyCode != -1 && memento.keyCode != options.keyCode) { return false; } if (options.deviceId != -1 && memento.deviceId != options.deviceId) { return false; } switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return true; case CancelationOptions::CANCEL_FALLBACK_EVENTS: return memento.flags & AKEY_EVENT_FLAG_FALLBACK; default: return false; } } bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options) { if (options.deviceId != -1 && memento.deviceId != options.deviceId) { return false; } switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: return true; case CancelationOptions::CANCEL_POINTER_EVENTS: return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); default: return false; } } // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) : status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), monitor(monitor), inputPublisher(inputChannel), inputPublisherBlocked(false) { } InputDispatcher::Connection::~Connection() { } const char* InputDispatcher::Connection::getWindowName() const { if (inputWindowHandle != NULL) { return inputWindowHandle->getName().string(); } if (monitor) { return "monitor"; } return "?"; } const char* InputDispatcher::Connection::getStatusLabel() const { switch (status) { case STATUS_NORMAL: return "NORMAL"; case STATUS_BROKEN: return "BROKEN"; case STATUS_ZOMBIE: return "ZOMBIE"; default: return "UNKNOWN"; } } InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) { if (entry->seq == seq) { return entry; } } return NULL; } // --- InputDispatcher::CommandEntry --- InputDispatcher::CommandEntry::CommandEntry(Command command) : command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), seq(0), handled(false) { } InputDispatcher::CommandEntry::~CommandEntry() { } // --- InputDispatcher::TouchState --- InputDispatcher::TouchState::TouchState() : down(false), split(false), deviceId(-1), source(0), displayId(-1) { } InputDispatcher::TouchState::~TouchState() { } void InputDispatcher::TouchState::reset() { down = false; split = false; deviceId = -1; source = 0; displayId = -1; windows.clear(); } void InputDispatcher::TouchState::copyFrom(const TouchState& other) { down = other.down; split = other.split; deviceId = other.deviceId; source = other.source; displayId = other.displayId; windows = other.windows; } void InputDispatcher::TouchState::addOrUpdateWindow(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; } for (size_t i = 0; i < windows.size(); i++) { TouchedWindow& touchedWindow = windows.editItemAt(i); if (touchedWindow.windowHandle == windowHandle) { touchedWindow.targetFlags |= targetFlags; if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; } touchedWindow.pointerIds.value |= pointerIds.value; return; } } windows.push(); TouchedWindow& touchedWindow = windows.editTop(); touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; touchedWindow.pointerIds = pointerIds; } void InputDispatcher::TouchState::removeWindow(const sp& windowHandle) { for (size_t i = 0; i < windows.size(); i++) { if (windows.itemAt(i).windowHandle == windowHandle) { windows.removeAt(i); return; } } } void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { for (size_t i = 0 ; i < windows.size(); ) { TouchedWindow& window = windows.editItemAt(i); if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; i += 1; } else { windows.removeAt(i); } } } sp InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { return window.windowHandle; } } return NULL; } bool InputDispatcher::TouchState::isSlippery() const { // Must have exactly one foreground window. bool haveSlipperyForegroundWindow = false; for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { if (haveSlipperyForegroundWindow || !(window.windowHandle->getInfo()->layoutParamsFlags & InputWindowInfo::FLAG_SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; } } return haveSlipperyForegroundWindow; } // --- InputDispatcherThread --- InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { } InputDispatcherThread::~InputDispatcherThread() { } bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true; } } // namespace android services/inputflinger/InputDispatcher.h0100644 0000000 0000000 00000130113 13077405420 017416 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "InputWindow.h" #include "InputApplication.h" #include "InputListener.h" namespace android { /* * Constants used to report the outcome of input event injection. */ enum { /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ INPUT_EVENT_INJECTION_PENDING = -1, /* Injection succeeded. */ INPUT_EVENT_INJECTION_SUCCEEDED = 0, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, /* Injection failed because there were no available input targets. */ INPUT_EVENT_INJECTION_FAILED = 2, /* Injection failed due to a timeout. */ INPUT_EVENT_INJECTION_TIMED_OUT = 3 }; /* * Constants used to determine the input event injection synchronization mode. */ enum { /* Injection is asynchronous and is assumed always to be successful. */ INPUT_EVENT_INJECTION_SYNC_NONE = 0, /* Waits for previous events to be dispatched so that the input dispatcher can determine * whether input event injection willbe permitted based on the current input focus. * Does not wait for the input event to finish processing. */ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, /* Waits for the input event to be completely processed. */ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, }; /* * An input target specifies how an input event is to be dispatched to a particular window * including the window's input channel, control flags, a timeout, and an X / Y offset to * be added to input event coordinates to compensate for the absolute position of the * window area. */ struct InputTarget { enum { /* This flag indicates that the event is being delivered to a foreground application. */ FLAG_FOREGROUND = 1 << 0, /* This flag indicates that the MotionEvent falls within the area of the target * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ FLAG_WINDOW_IS_OBSCURED = 1 << 1, /* This flag indicates that a motion event is being split across multiple windows. */ FLAG_SPLIT = 1 << 2, /* This flag indicates that the pointer coordinates dispatched to the application * will be zeroed out to avoid revealing information to an application. This is * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing * the same UID from watching all touches. */ FLAG_ZERO_COORDS = 1 << 3, /* This flag indicates that the event should be sent as is. * Should always be set unless the event is to be transmuted. */ FLAG_DISPATCH_AS_IS = 1 << 8, /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside * of the area of this target and so should instead be delivered as an * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, /* This flag indicates that a hover sequence is starting in the given window. * The event is transmuted into ACTION_HOVER_ENTER. */ FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, /* This flag indicates that a hover event happened outside of a window which handled * previous hover events, signifying the end of the current hover sequence for that * window. * The event is transmuted into ACTION_HOVER_ENTER. */ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, /* This flag indicates that the event should be canceled. * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips * outside of a window. */ FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, /* This flag indicates that the event should be dispatched as an initial down. * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips * into a new window. */ FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, /* Mask for all dispatch modes. */ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE | FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER, /* This flag indicates that the target of a MotionEvent is partly or wholly * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14, }; // The input channel to be targeted. sp inputChannel; // Flags for the input target. int32_t flags; // The x and y offset to add to a MotionEvent as it is delivered. // (ignored for KeyEvents) float xOffset, yOffset; // Scaling factor to apply to MotionEvent as it is delivered. // (ignored for KeyEvents) float scaleFactor; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. BitSet32 pointerIds; }; /* * Input dispatcher configuration. * * Specifies various options that modify the behavior of the input dispatcher. * The values provided here are merely defaults. The actual values will come from ViewConfiguration * and are passed into the dispatcher during initialization. */ struct InputDispatcherConfiguration { // The key repeat initial timeout. nsecs_t keyRepeatTimeout; // The key repeat inter-key delay. nsecs_t keyRepeatDelay; InputDispatcherConfiguration() : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) { } }; /* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager * and other system components. * * The actual implementation is partially supported by callbacks into the DVM * via JNI. This interface is also mocked in the unit tests. */ class InputDispatcherPolicyInterface : public virtual RefBase { protected: InputDispatcherPolicyInterface() { } virtual ~InputDispatcherPolicyInterface() { } public: /* Notifies the system that a configuration change has occurred. */ virtual void notifyConfigurationChanged(nsecs_t when) = 0; /* Notifies the system that an application is not responding. * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ virtual nsecs_t notifyANR(const sp& inputApplicationHandle, const sp& inputWindowHandle, const String8& reason) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp& inputWindowHandle) = 0; /* Gets the input dispatcher configuration. */ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; /* Filters an input event. * Return true to dispatch the event unmodified, false to consume the event. * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED * to injectInputEvent. */ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; /* Intercepts a key event immediately before queueing it. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. * * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; /* Intercepts a touch, trackball or other motion event before queueing it. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. * * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ virtual nsecs_t interceptKeyBeforeDispatching(const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; /* Allows the policy a chance to perform default processing for an unhandled key. * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ virtual bool dispatchUnhandledKey(const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; /* Notifies the policy about switch events. */ virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0; /* Poke user activity for an event dispatched to a window. */ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; /* Checks whether a given application pid/uid has permission to inject input events * into other applications. * * This method is special in that its implementation promises to be non-reentrant and * is safe to call while holding other locks. (Most other methods make no such guarantees!) */ virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid) = 0; }; /* Notifies the system about input events generated by the input reader. * The dispatcher is expected to be mostly asynchronous. */ class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { protected: InputDispatcherInterface() { } virtual ~InputDispatcherInterface() { } public: /* Dumps the state of the input dispatcher. * * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ virtual void monitor() = 0; /* Runs a single iteration of the dispatch loop. * Nominally processes one queued event, a timeout, or a response from an input consumer. * * This method should only be called on the input dispatcher thread. */ virtual void dispatchOnce() = 0; /* Injects an input event and optionally waits for sync. * The synchronization mode determines whether the method blocks while waiting for * input injection to proceed. * Returns one of the INPUT_EVENT_INJECTION_XXX constants. * * This method may be called on any thread (usually by the input manager). */ virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; /* Sets the list of input windows. * * This method may be called on any thread (usually by the input manager). */ virtual void setInputWindows(const Vector >& inputWindowHandles) = 0; /* Sets the focused application. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedApplication( const sp& inputApplicationHandle) = 0; /* Sets the input dispatching mode. * * This method may be called on any thread (usually by the input manager). */ virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; /* Sets whether input event filtering is enabled. * When enabled, incoming input events are sent to the policy's filterInputEvent * method instead of being dispatched. The filter is expected to use * injectInputEvent to inject the events it would like to have dispatched. * It should include POLICY_FLAG_FILTERED in the policy flags during injection. */ virtual void setInputFilterEnabled(bool enabled) = 0; /* Transfers touch focus from the window associated with one channel to the * window associated with the other channel. * * Returns true on success. False if the window did not actually have touch focus. */ virtual bool transferTouchFocus(const sp& fromChannel, const sp& toChannel) = 0; /* Registers or unregister input channels that may be used as targets for input events. * If monitor is true, the channel will receive a copy of all input events. * * These methods may be called on any thread (usually by the input manager). */ virtual status_t registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) = 0; virtual status_t unregisterInputChannel(const sp& inputChannel) = 0; }; /* Dispatches events to input targets. Some functions of the input dispatcher, such as * identifying input targets, are controlled by a separate policy object. * * IMPORTANT INVARIANT: * Because the policy can potentially block or cause re-entrance into the input dispatcher, * the input dispatcher never calls into the policy while holding its internal locks. * The implementation is also carefully designed to recover from scenarios such as an * input channel becoming unregistered while identifying input targets or processing timeouts. * * Methods marked 'Locked' must be called with the lock acquired. * * Methods marked 'LockedInterruptible' must be called with the lock acquired but * may during the course of their execution release the lock, call into the policy, and * then reacquire the lock. The caller is responsible for recovering gracefully. * * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. */ class InputDispatcher : public InputDispatcherInterface { protected: virtual ~InputDispatcher(); public: explicit InputDispatcher(const sp& policy); virtual void dump(String8& dump); virtual void monitor(); virtual void dispatchOnce(); virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags); virtual void setInputWindows(const Vector >& inputWindowHandles); virtual void setFocusedApplication(const sp& inputApplicationHandle); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); virtual bool transferTouchFocus(const sp& fromChannel, const sp& toChannel); virtual status_t registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor); virtual status_t unregisterInputChannel(const sp& inputChannel); private: template struct Link { T* next; T* prev; protected: inline Link() : next(NULL), prev(NULL) { } }; struct InjectionState { mutable int32_t refCount; int32_t injectorPid; int32_t injectorUid; int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING bool injectionIsAsync; // set to true if injection is not waiting for the result int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress InjectionState(int32_t injectorPid, int32_t injectorUid); void release(); private: ~InjectionState(); }; struct EventEntry : Link { enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION }; mutable int32_t refCount; int32_t type; nsecs_t eventTime; uint32_t policyFlags; InjectionState* injectionState; bool dispatchInProgress; // initially false, set to true while dispatching inline bool isInjected() const { return injectionState != NULL; } void release(); virtual void appendDescription(String8& msg) const = 0; protected: EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); virtual ~EventEntry(); void releaseInjectionState(); }; struct ConfigurationChangedEntry : EventEntry { ConfigurationChangedEntry(nsecs_t eventTime); virtual void appendDescription(String8& msg) const; protected: virtual ~ConfigurationChangedEntry(); }; struct DeviceResetEntry : EventEntry { int32_t deviceId; DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); virtual void appendDescription(String8& msg) const; protected: virtual ~DeviceResetEntry(); }; struct KeyEntry : EventEntry { int32_t deviceId; uint32_t source; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t repeatCount; nsecs_t downTime; bool syntheticRepeat; // set to true for synthetic key repeats enum InterceptKeyResult { INTERCEPT_KEY_RESULT_UNKNOWN, INTERCEPT_KEY_RESULT_SKIP, INTERCEPT_KEY_RESULT_CONTINUE, INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, }; InterceptKeyResult interceptKeyResult; // set based on the interception result nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER KeyEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime); virtual void appendDescription(String8& msg) const; void recycle(); protected: virtual ~KeyEntry(); }; struct MotionEntry : EventEntry { nsecs_t eventTime; int32_t deviceId; uint32_t source; int32_t action; int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; float xPrecision; float yPrecision; nsecs_t downTime; int32_t displayId; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset); virtual void appendDescription(String8& msg) const; protected: virtual ~MotionEntry(); }; // Tracks the progress of dispatching a particular event to a particular connection. struct DispatchEntry : Link { const uint32_t seq; // unique sequence number, never 0 EventEntry* eventEntry; // the event to dispatch int32_t targetFlags; float xOffset; float yOffset; float scaleFactor; nsecs_t deliveryTime; // time when the event was actually delivered // Set to the resolved action and flags when the event is enqueued. int32_t resolvedAction; int32_t resolvedFlags; DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); ~DispatchEntry(); inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; } private: static volatile int32_t sNextSeqAtomic; static uint32_t nextSeq(); }; // A command entry captures state and behavior for an action to be performed in the // dispatch loop after the initial processing has taken place. It is essentially // a kind of continuation used to postpone sensitive policy interactions to a point // in the dispatch loop where it is safe to release the lock (generally after finishing // the critical parts of the dispatch cycle). // // The special thing about commands is that they can voluntarily release and reacquire // the dispatcher lock at will. Initially when the command starts running, the // dispatcher lock is held. However, if the command needs to call into the policy to // do some work, it can release the lock, do the work, then reacquire the lock again // before returning. // // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch // never calls into the policy while holding its lock. // // Commands are implicitly 'LockedInterruptible'. struct CommandEntry; typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); class Connection; struct CommandEntry : Link { CommandEntry(Command command); ~CommandEntry(); Command command; // parameters for the command (usage varies by command) sp connection; nsecs_t eventTime; KeyEntry* keyEntry; sp inputApplicationHandle; sp inputWindowHandle; String8 reason; int32_t userActivityEventType; uint32_t seq; bool handled; }; // Generic queue implementation. template struct Queue { T* head; T* tail; uint32_t entryCount; inline Queue() : head(NULL), tail(NULL), entryCount(0) { } inline bool isEmpty() const { return !head; } inline void enqueueAtTail(T* entry) { entryCount++; entry->prev = tail; if (tail) { tail->next = entry; } else { head = entry; } entry->next = NULL; tail = entry; } inline void enqueueAtHead(T* entry) { entryCount++; entry->next = head; if (head) { head->prev = entry; } else { tail = entry; } entry->prev = NULL; head = entry; } inline void dequeue(T* entry) { entryCount--; if (entry->prev) { entry->prev->next = entry->next; } else { head = entry->next; } if (entry->next) { entry->next->prev = entry->prev; } else { tail = entry->prev; } } inline T* dequeueAtHead() { entryCount--; T* entry = head; head = entry->next; if (head) { head->prev = NULL; } else { tail = NULL; } return entry; } uint32_t count() const { return entryCount; } }; /* Specifies which events are to be canceled and why. */ struct CancelationOptions { enum Mode { CANCEL_ALL_EVENTS = 0, CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3, }; // The criterion to use to determine which events should be canceled. Mode mode; // Descriptive reason for the cancelation. const char* reason; // The specific keycode of the key event to cancel, or -1 to cancel any key event. int32_t keyCode; // The specific device id of events to cancel, or -1 to cancel events from any device. int32_t deviceId; CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } }; /* Tracks dispatched key and motion event state so that cancelation events can be * synthesized when events are dropped. */ class InputState { public: InputState(); ~InputState(); // Returns true if there is no state to be canceled. bool isNeutral() const; // Returns true if the specified source is known to have received a hover enter // motion event. bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; // Records tracking information for a key event that has just been published. // Returns true if the event should be delivered, false if it is inconsistent // and should be skipped. bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); // Records tracking information for a motion event that has just been published. // Returns true if the event should be delivered, false if it is inconsistent // and should be skipped. bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); // Synthesizes cancelation events for the current state and resets the tracked state. void synthesizeCancelationEvents(nsecs_t currentTime, Vector& outEvents, const CancelationOptions& options); // Clears the current state. void clear(); // Copies pointer-related parts of the input state to another instance. void copyPointerStateTo(InputState& other) const; // Gets the fallback key associated with a keycode. // Returns -1 if none. // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. int32_t getFallbackKey(int32_t originalKeyCode); // Sets the fallback key for a particular keycode. void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); // Removes the fallback key for a particular keycode. void removeFallbackKey(int32_t originalKeyCode); inline const KeyedVector& getFallbackKeys() const { return mFallbackKeys; } private: struct KeyMemento { int32_t deviceId; uint32_t source; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t flags; nsecs_t downTime; uint32_t policyFlags; }; struct MotionMemento { int32_t deviceId; uint32_t source; int32_t flags; float xPrecision; float yPrecision; nsecs_t downTime; int32_t displayId; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; bool hovering; uint32_t policyFlags; void setPointers(const MotionEntry* entry); }; Vector mKeyMementos; Vector mMotionMementos; KeyedVector mFallbackKeys; ssize_t findKeyMemento(const KeyEntry* entry) const; ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; void addKeyMemento(const KeyEntry* entry, int32_t flags); void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); }; /* Manages the dispatch state associated with a single input channel. */ class Connection : public RefBase { protected: virtual ~Connection(); public: enum Status { // Everything is peachy. STATUS_NORMAL, // An unrecoverable communication error has occurred. STATUS_BROKEN, // The input channel has been unregistered. STATUS_ZOMBIE }; Status status; sp inputChannel; // never null sp inputWindowHandle; // may be null bool monitor; InputPublisher inputPublisher; InputState inputState; // True if the socket is full and no further events can be published until // the application consumes some of the input. bool inputPublisherBlocked; // Queue of events that need to be published to the connection. Queue outboundQueue; // Queue of events that have been published to the connection but that have not // yet received a "finished" response from the application. Queue waitQueue; explicit Connection(const sp& inputChannel, const sp& inputWindowHandle, bool monitor); inline const char* getInputChannelName() const { return inputChannel->getName().string(); } const char* getWindowName() const; const char* getStatusLabel() const; DispatchEntry* findWaitQueueEntry(uint32_t seq); }; enum DropReason { DROP_REASON_NOT_DROPPED = 0, DROP_REASON_POLICY = 1, DROP_REASON_APP_SWITCH = 2, DROP_REASON_DISABLED = 3, DROP_REASON_BLOCKED = 4, DROP_REASON_STALE = 5, }; sp mPolicy; InputDispatcherConfiguration mConfig; Mutex mLock; Condition mDispatcherIsAliveCondition; sp mLooper; EventEntry* mPendingEvent; Queue mInboundQueue; Queue mRecentQueue; Queue mCommandQueue; DropReason mLastDropReason; void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Enqueues an inbound event. Returns true if mLooper->wake() should be called. bool enqueueInboundEventLocked(EventEntry* entry); // Cleans up input state when dropping an inbound event. void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); // Adds an event to a queue of recent events for debugging purposes. void addRecentEventLocked(EventEntry* entry); // App switch latency optimization. bool mAppSwitchSawKeyDown; nsecs_t mAppSwitchDueTime; static bool isAppSwitchKeyCode(int32_t keyCode); bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); bool isAppSwitchPendingLocked(); void resetPendingAppSwitchLocked(bool handled); // Stale event latency optimization. static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); // Blocked event latency optimization. Drops old events when the user intends // to transfer focus to a new application. EventEntry* mNextUnblockedEvent; sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y); // All registered connections mapped by channel file descriptor. KeyedVector > mConnectionsByFd; ssize_t getConnectionIndexLocked(const sp& inputChannel); // Input channels that will receive a copy of all input events. Vector > mMonitoringChannels; // Event injection and synchronization. Condition mInjectionResultAvailableCondition; bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); Condition mInjectionSyncFinishedCondition; void incrementPendingForegroundDispatchesLocked(EventEntry* entry); void decrementPendingForegroundDispatchesLocked(EventEntry* entry); // Key repeat tracking. struct KeyRepeatState { KeyEntry* lastKeyEntry; // or null if no repeat nsecs_t nextRepeatTime; } mKeyRepeatState; void resetKeyRepeatLocked(); KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); // Key replacement tracking struct KeyReplacement { int32_t keyCode; int32_t deviceId; bool operator==(const KeyReplacement& rhs) const { return keyCode == rhs.keyCode && deviceId == rhs.deviceId; } bool operator<(const KeyReplacement& rhs) const { return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; } }; // Maps the key code replaced, device id tuple to the key code it was replaced with KeyedVector mReplacedKeys; // Deferred command processing. bool haveCommandsLocked() const; bool runCommandsLockedInterruptible(); CommandEntry* postCommandLocked(Command command); // Input filter processing. bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args); bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args); // Inbound event processing. void drainInboundQueueLocked(); void releasePendingEventLocked(); void releaseInboundEventLocked(EventEntry* entry); // Dispatch state. bool mDispatchEnabled; bool mDispatchFrozen; bool mInputFilterEnabled; Vector > mWindowHandles; sp getWindowHandleLocked(const sp& inputChannel) const; bool hasWindowHandleLocked(const sp& windowHandle) const; // Focus tracking for keys, trackball, etc. sp mFocusedWindowHandle; // Focus tracking for touch. struct TouchedWindow { sp windowHandle; int32_t targetFlags; BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set }; struct TouchState { bool down; bool split; int32_t deviceId; // id of the device that is currently down, others are rejected uint32_t source; // source of the device that is current down, others are rejected int32_t displayId; // id to the display that currently has a touch, others are rejected Vector windows; TouchState(); ~TouchState(); void reset(); void copyFrom(const TouchState& other); void addOrUpdateWindow(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds); void removeWindow(const sp& windowHandle); void filterNonAsIsTouchWindows(); sp getFirstForegroundWindowHandle() const; bool isSlippery() const; }; KeyedVector mTouchStatesByDisplay; TouchState mTempTouchState; // Focused application. sp mFocusedApplicationHandle; // Dispatcher state at time of last ANR. String8 mLastANRState; // Dispatch inbound events. bool dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry); bool dispatchDeviceResetLocked( nsecs_t currentTime, DeviceResetEntry* entry); bool dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); bool dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, const Vector& inputTargets); void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); // Keeping track of ANR timeouts. enum InputTargetWaitCause { INPUT_TARGET_WAIT_CAUSE_NONE, INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, }; InputTargetWaitCause mInputTargetWaitCause; nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; sp mInputTargetWaitApplicationHandle; // Contains the last window which received a hover event. sp mLastHoverWindowHandle; // Finding targets for input events. int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp& applicationHandle, const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason); void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, const sp& inputChannel); nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); void resetANRTimeoutsLocked(); int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime); int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions); void addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds, Vector& inputTargets); void addMonitoringTargetsLocked(Vector& inputTargets); void pokeUserActivityLocked(const EventEntry* eventEntry); bool checkInjectionPermission(const sp& windowHandle, const InjectionState* injectionState); bool isWindowObscuredAtPointLocked(const sp& windowHandle, int32_t x, int32_t y) const; bool isWindowObscuredLocked(const sp& windowHandle) const; String8 getApplicationWindowLabelLocked(const sp& applicationHandle, const sp& windowHandle); String8 checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp& windowHandle, const EventEntry* eventEntry, const char* targetType); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work // with the mutex held makes it easier to ensure that connection invariants are maintained. // If needed, the methods post commands to run later once the critical bits are done. void prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget); void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget); void enqueueDispatchEntryLocked(const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode); void startDispatchCycleLocked(nsecs_t currentTime, const sp& connection); void finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled); void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, bool notify); void drainDispatchQueueLocked(Queue* queue); void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry); static int handleReceiveCallback(int fd, int events, void* data); void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options); void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options); void synthesizeCancelationEventsForInputChannelLocked(const sp& channel, const CancelationOptions& options); void synthesizeCancelationEventsForConnectionLocked(const sp& connection, const CancelationOptions& options); // Splitting motion events across windows. MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); // Reset and drop everything the dispatcher is doing. void resetAndDropEverythingLocked(const char* reason); // Dump state. void dumpDispatchStateLocked(String8& dump); void logDispatchStateLocked(); // Registration. void removeMonitorChannelLocked(const sp& inputChannel); status_t unregisterInputChannelLocked(const sp& inputChannel, bool notify); // Add or remove a connection to the mActiveConnections vector. void activateConnectionLocked(Connection* connection); void deactivateConnectionLocked(Connection* connection); // Interesting events that we might like to log or tell the framework about. void onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled); void onDispatchCycleBrokenLocked( nsecs_t currentTime, const sp& connection); void onANRLocked( nsecs_t currentTime, const sp& applicationHandle, const sp& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char* reason); // Outbound policy interactions. void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); bool afterKeyEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); bool afterMotionEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); // Statistics gathering. void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); void traceInboundQueueLengthLocked(); void traceOutboundQueueLengthLocked(const sp& connection); void traceWaitQueueLengthLocked(const sp& connection); }; /* Enqueues and dispatches input events, endlessly. */ class InputDispatcherThread : public Thread { public: explicit InputDispatcherThread(const sp& dispatcher); ~InputDispatcherThread(); private: virtual bool threadLoop(); sp mDispatcher; }; } // namespace android #endif // _UI_INPUT_DISPATCHER_H services/inputflinger/InputListener.cpp0100644 0000000 0000000 00000014360 13077405420 017455 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "InputListener" //#define LOG_NDEBUG 0 #include "InputListener.h" #include namespace android { // --- NotifyConfigurationChangedArgs --- NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) : eventTime(eventTime) { } NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( const NotifyConfigurationChangedArgs& other) : eventTime(other.eventTime) { } void NotifyConfigurationChangedArgs::notify(const sp& listener) const { listener->notifyConfigurationChanged(this); } // --- NotifyKeyArgs --- NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), metaState(metaState), downTime(downTime) { } NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), action(other.action), flags(other.flags), keyCode(other.keyCode), scanCode(other.scanCode), metaState(other.metaState), downTime(other.downTime) { } void NotifyKeyArgs::notify(const sp& listener) const { listener->notifyKey(this); } // --- NotifyMotionArgs --- NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), action(action), actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); } } NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), action(other.action), actionButton(other.actionButton), flags(other.flags), metaState(other.metaState), buttonState(other.buttonState), edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount), xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); pointerCoords[i].copyFrom(other.pointerCoords[i]); } } void NotifyMotionArgs::notify(const sp& listener) const { listener->notifyMotion(this); } // --- NotifySwitchArgs --- NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues, uint32_t switchMask) : eventTime(eventTime), policyFlags(policyFlags), switchValues(switchValues), switchMask(switchMask) { } NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : eventTime(other.eventTime), policyFlags(other.policyFlags), switchValues(other.switchValues), switchMask(other.switchMask) { } void NotifySwitchArgs::notify(const sp& listener) const { listener->notifySwitch(this); } // --- NotifyDeviceResetArgs --- NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : eventTime(eventTime), deviceId(deviceId) { } NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId) { } void NotifyDeviceResetArgs::notify(const sp& listener) const { listener->notifyDeviceReset(this); } // --- QueuedInputListener --- QueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) { } QueuedInputListener::~QueuedInputListener() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { delete mArgsQueue[i]; } } void QueuedInputListener::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); } void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { mArgsQueue.push(new NotifyKeyArgs(*args)); } void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); } void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { mArgsQueue.push(new NotifySwitchArgs(*args)); } void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mArgsQueue.push(new NotifyDeviceResetArgs(*args)); } void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); delete args; } mArgsQueue.clear(); } } // namespace android services/inputflinger/InputListener.h0100644 0000000 0000000 00000013201 13077405420 017113 0ustar000000000 0000000 /* * 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 _UI_INPUT_LISTENER_H #define _UI_INPUT_LISTENER_H #include #include #include namespace android { class InputListenerInterface; /* Superclass of all input event argument objects */ struct NotifyArgs { virtual ~NotifyArgs() { } virtual void notify(const sp& listener) const = 0; }; /* Describes a configuration change event. */ struct NotifyConfigurationChangedArgs : public NotifyArgs { nsecs_t eventTime; inline NotifyConfigurationChangedArgs() { } NotifyConfigurationChangedArgs(nsecs_t eventTime); NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); virtual ~NotifyConfigurationChangedArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a key event. */ struct NotifyKeyArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; uint32_t source; uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; nsecs_t downTime; inline NotifyKeyArgs() { } NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); NotifyKeyArgs(const NotifyKeyArgs& other); virtual ~NotifyKeyArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a motion event. */ struct NotifyMotionArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; uint32_t source; uint32_t policyFlags; int32_t action; int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; int32_t displayId; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; float xPrecision; float yPrecision; nsecs_t downTime; inline NotifyMotionArgs() { } NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); NotifyMotionArgs(const NotifyMotionArgs& other); virtual ~NotifyMotionArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a switch event. */ struct NotifySwitchArgs : public NotifyArgs { nsecs_t eventTime; uint32_t policyFlags; uint32_t switchValues; uint32_t switchMask; inline NotifySwitchArgs() { } NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues, uint32_t switchMask); NotifySwitchArgs(const NotifySwitchArgs& other); virtual ~NotifySwitchArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a device reset event, such as when a device is added, * reconfigured, or removed. */ struct NotifyDeviceResetArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; inline NotifyDeviceResetArgs() { } NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); virtual ~NotifyDeviceResetArgs() { } virtual void notify(const sp& listener) const; }; /* * The interface used by the InputReader to notify the InputListener about input events. */ class InputListenerInterface : public virtual RefBase { protected: InputListenerInterface() { } virtual ~InputListenerInterface() { } public: virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; virtual void notifyKey(const NotifyKeyArgs* args) = 0; virtual void notifyMotion(const NotifyMotionArgs* args) = 0; virtual void notifySwitch(const NotifySwitchArgs* args) = 0; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; }; /* * An implementation of the listener interface that queues up and defers dispatch * of decoded events until flushed. */ class QueuedInputListener : public InputListenerInterface { protected: virtual ~QueuedInputListener(); public: QueuedInputListener(const sp& innerListener); virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); void flush(); private: sp mInnerListener; Vector mArgsQueue; }; } // namespace android #endif // _UI_INPUT_LISTENER_H services/inputflinger/InputManager.cpp0100644 0000000 0000000 00000005032 13077405420 017236 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "InputManager" //#define LOG_NDEBUG 0 #include "InputManager.h" #include namespace android { InputManager::InputManager( const sp& eventHub, const sp& readerPolicy, const sp& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); } InputManager::InputManager( const sp& reader, const sp& dispatcher) : mReader(reader), mDispatcher(dispatcher) { initialize(); } InputManager::~InputManager() { stop(); } void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK; } status_t InputManager::stop() { status_t result = mReaderThread->requestExitAndWait(); if (result) { ALOGW("Could not stop InputReader thread due to error %d.", result); } result = mDispatcherThread->requestExitAndWait(); if (result) { ALOGW("Could not stop InputDispatcher thread due to error %d.", result); } return OK; } sp InputManager::getReader() { return mReader; } sp InputManager::getDispatcher() { return mDispatcher; } } // namespace android services/inputflinger/InputManager.h0100644 0000000 0000000 00000006523 13077405420 016711 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _UI_INPUT_MANAGER_H #define _UI_INPUT_MANAGER_H /** * Native input manager. */ #include "EventHub.h" #include "InputReader.h" #include "InputDispatcher.h" #include #include #include #include #include #include #include namespace android { /* * The input manager is the core of the system event processing. * * The input manager uses two threads. * * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, * applies policy, and posts messages to a queue managed by the DispatcherThread. * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the * queue and asynchronously dispatches them to applications. * * By design, the InputReaderThread class and InputDispatcherThread class do not share any * internal state. Moreover, all communication is done one way from the InputReaderThread * into the InputDispatcherThread and never the reverse. Both classes may interact with the * InputDispatchPolicy, however. * * The InputManager class never makes any calls into Java itself. Instead, the * InputDispatchPolicy is responsible for performing all external interactions with the * system, including calling DVM services. */ class InputManagerInterface : public virtual RefBase { protected: InputManagerInterface() { } virtual ~InputManagerInterface() { } public: /* Starts the input manager threads. */ virtual status_t start() = 0; /* Stops the input manager threads and waits for them to exit. */ virtual status_t stop() = 0; /* Gets the input reader. */ virtual sp getReader() = 0; /* Gets the input dispatcher. */ virtual sp getDispatcher() = 0; }; class InputManager : public InputManagerInterface { protected: virtual ~InputManager(); public: InputManager( const sp& eventHub, const sp& readerPolicy, const sp& dispatcherPolicy); // (used for testing purposes) InputManager( const sp& reader, const sp& dispatcher); virtual status_t start(); virtual status_t stop(); virtual sp getReader(); virtual sp getDispatcher(); private: sp mReader; sp mReaderThread; sp mDispatcher; sp mDispatcherThread; void initialize(); }; } // namespace android #endif // _UI_INPUT_MANAGER_H services/inputflinger/InputReader.cpp0100644 0000000 0000000 00001063525 13077405420 017102 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define LOG_TAG "InputReader" //#define LOG_NDEBUG 0 // Log debug messages for each raw event received from the EventHub. #define DEBUG_RAW_EVENTS 0 // Log debug messages about touch screen filtering hacks. #define DEBUG_HACKS 0 // Log debug messages about virtual key processing. #define DEBUG_VIRTUAL_KEYS 0 // Log debug messages about pointers. #define DEBUG_POINTERS 0 // Log debug messages about pointer assignment calculations. #define DEBUG_POINTER_ASSIGNMENT 0 // Log debug messages about gesture detection. #define DEBUG_GESTURES 0 // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 // Log debug messages about fusing stylus data. #define DEBUG_STYLUS_FUSION 0 #include "InputReader.h" #include #include #include #include #include #include #include #include #include #include #define INDENT " " #define INDENT2 " " #define INDENT3 " " #define INDENT4 " " #define INDENT5 " " namespace android { // --- Constants --- // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; // Maximum amount of latency to add to touch events while waiting for data from an // external stylus. static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); // Maximum amount of time to wait on touch data before pushing out new pressure data. static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); // Artificial latency on synthetic events created from stylus data without corresponding touch // data. static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); // --- Static Functions --- template inline static T abs(const T& value) { return value < 0 ? - value : value; } template inline static T min(const T& a, const T& b) { return a < b ? a : b; } template inline static void swap(T& a, T& b) { T temp = a; a = b; b = temp; } inline static float avg(float x, float y) { return (x + y) / 2; } inline static float distance(float x1, float y1, float x2, float y2) { return hypotf(x1 - x2, y1 - y2); } inline static int32_t signExtendNybble(int32_t value) { return value >= 8 ? value - 16 : value; } static inline const char* toString(bool value) { return value ? "true" : "false"; } static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, const int32_t map[][4], size_t mapSize) { if (orientation != DISPLAY_ORIENTATION_0) { for (size_t i = 0; i < mapSize; i++) { if (value == map[i][0]) { return map[i][orientation]; } } } return value; } static const int32_t keyCodeRotationMap[][4] = { // key codes enumerated counter-clockwise with the original (unrotated) key first // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, }; static const size_t keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap, keyCodeRotationMapSize); } static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { float temp; switch (orientation) { case DISPLAY_ORIENTATION_90: temp = *deltaX; *deltaX = *deltaY; *deltaY = -temp; break; case DISPLAY_ORIENTATION_180: *deltaX = -*deltaX; *deltaY = -*deltaY; break; case DISPLAY_ORIENTATION_270: temp = *deltaX; *deltaX = -*deltaY; *deltaY = temp; break; } } static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; } // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { return buttonState & (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY); } static float calculateCommonVector(float a, float b) { if (a > 0 && b > 0) { return a < b ? a : b; } else if (a < 0 && b < 0) { return a > b ? a : b; } else { return 0; } } static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, int32_t buttonState, int32_t keyCode) { if ( (action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) && (currentButtonState & buttonState)) || (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && !(currentButtonState & buttonState))) { NotifyKeyArgs args(when, deviceId, source, policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); context->getListener()->notifyKey(&args); } } static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); } // --- InputReaderConfiguration --- bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const { const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay; if (viewport.displayId >= 0) { *outViewport = viewport; return true; } return false; } void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) { DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay; v = viewport; } // -- TouchAffineTransformation -- void TouchAffineTransformation::applyTo(float& x, float& y) const { float newX, newY; newX = x * x_scale + y * x_ymix + x_offset; newY = x * y_xmix + y * y_scale + y_offset; x = newX; y = newY; } // --- InputReader --- InputReader::InputReader(const sp& eventHub, const sp& policy, const sp& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0), mGeneration(1), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); { // acquire lock AutoMutex _l(mLock); refreshConfigurationLocked(0); updateGlobalMetaStateLocked(); } // release lock } InputReader::~InputReader() { for (size_t i = 0; i < mDevices.size(); i++) { delete mDevices.valueAt(i); } } void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; bool inputDevicesChanged = false; Vector inputDevices; { // acquire lock AutoMutex _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; uint32_t changes = mConfigurationChangesToRefresh; if (changes) { mConfigurationChangesToRefresh = 0; timeoutMillis = 0; refreshConfigurationLocked(changes); } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } } // release lock size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { #if DEBUG_RAW_EVENTS ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); #endif mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. mQueuedListener->flush(); } void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } #if DEBUG_RAW_EVENTS ALOGD("BatchSize: %d Count: %d", batchSize, count); #endif processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } } void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); return; } InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); device->configure(when, &mConfig, 0); device->reset(when); if (device->isIgnored()) { ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, identifier.name.string()); } else { ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, identifier.name.string(), device->getSources()); } mDevices.add(deviceId, device); bumpGenerationLocked(); if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { notifyExternalStylusPresenceChanged(); } } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { InputDevice* device = NULL; ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); return; } device = mDevices.valueAt(deviceIndex); mDevices.removeItemsAt(deviceIndex, 1); bumpGenerationLocked(); if (device->isIgnored()) { ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), device->getName().string()); } else { ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), device->getName().string(), device->getSources()); } if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { notifyExternalStylusPresenceChanged(); } device->reset(when); delete device; } InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { device->setExternal(true); } // Devices with mics. if (classes & INPUT_DEVICE_CLASS_MIC) { device->setMic(true); } // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); } // Scroll wheel-like devices. if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { device->addMapper(new RotaryEncoderInputMapper(device)); } // Vibrator-like devices. if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { device->addMapper(new VibratorInputMapper(device)); } // Keyboard-like devices. uint32_t keyboardSource = 0; int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { keyboardSource |= AINPUT_SOURCE_KEYBOARD; } if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; } if (classes & INPUT_DEVICE_CLASS_DPAD) { keyboardSource |= AINPUT_SOURCE_DPAD; } if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { keyboardSource |= AINPUT_SOURCE_GAMEPAD; } if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { device->addMapper(new JoystickInputMapper(device)); } // External stylus-like devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { device->addMapper(new ExternalStylusInputMapper(device)); } return device; } void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); } void InputReader::timeoutExpiredLocked(nsecs_t when) { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); if (!device->isIgnored()) { device->timeoutExpired(when); } } } void InputReader::handleConfigurationChangedLocked(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaStateLocked(); // Enqueue configuration changed. NotifyConfigurationChangedArgs args(when); mQueuedListener->notifyConfigurationChanged(&args); } void InputReader::refreshConfigurationLocked(uint32_t changes) { mPolicy->getReaderConfiguration(&mConfig); mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); if (changes) { ALOGI("Reconfiguring input devices. changes=0x%08x", changes); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { mEventHub->requestReopenDevices(); } else { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->configure(now, &mConfig, changes); } } } } void InputReader::updateGlobalMetaStateLocked() { mGlobalMetaState = 0; for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); mGlobalMetaState |= device->getMetaState(); } } int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } void InputReader::notifyExternalStylusPresenceChanged() { refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); } void InputReader::getExternalStylusDevicesLocked(Vector& outDevices) { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { outDevices.push(); device->getDeviceInfo(&outDevices.editTop()); } } } void InputReader::dispatchExternalStylusState(const StylusState& state) { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->updateExternalStylusState(state); } } void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) { if (now < mDisableVirtualKeysTimeout) { ALOGI("Dropping virtual key from device %s because virtual keys are " "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", device->getName().string(), (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, scanCode); return true; } else { return false; } } void InputReader::fadePointerLocked() { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->fadePointer(); } } void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { if (when < mNextTimeout) { mNextTimeout = when; mEventHub->wake(); } } int32_t InputReader::bumpGenerationLocked() { return ++mGeneration; } void InputReader::getInputDevices(Vector& outInputDevices) { AutoMutex _l(mLock); getInputDevicesLocked(outInputDevices); } void InputReader::getInputDevicesLocked(Vector& outInputDevices) { outInputDevices.clear(); size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (!device->isIgnored()) { outInputDevices.push(); device->getDeviceInfo(&outInputDevices.editTop()); } } } int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); } int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); } int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); } int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; if (deviceId >= 0) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result = (device->*getStateFunc)(sourceMask, code); } } } else { size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. int32_t currentResult = (device->*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { result = currentResult; } } } } return result; } void InputReader::toggleCapsLockState(int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { return; } device->updateMetaState(AKEYCODE_CAPS_LOCK); } bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { AutoMutex _l(mLock); memset(outFlags, 0, numCodes); return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); } bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; if (deviceId >= 0) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } } else { size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } } return result; } void InputReader::requestRefreshConfiguration(uint32_t changes) { AutoMutex _l(mLock); if (changes) { bool needWake = !mConfigurationChangesToRefresh; mConfigurationChangesToRefresh |= changes; if (needWake) { mEventHub->wake(); } } } void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { AutoMutex _l(mLock); ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); device->vibrate(pattern, patternSize, repeat, token); } } void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { AutoMutex _l(mLock); ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); device->cancelVibrate(token); } } void InputReader::dump(String8& dump) { AutoMutex _l(mLock); mEventHub->dump(dump); dump.append("\n"); dump.append("Input Reader State:\n"); for (size_t i = 0; i < mDevices.size(); i++) { mDevices.valueAt(i)->dump(dump); } dump.append(INDENT "Configuration:\n"); dump.append(INDENT2 "ExcludedDeviceNames: ["); for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { if (i != 0) { dump.append(", "); } dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); } dump.append("]\n"); dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", mConfig.virtualKeyQuietTime * 0.000001f); dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.pointerVelocityControlParameters.scale, mConfig.pointerVelocityControlParameters.lowThreshold, mConfig.pointerVelocityControlParameters.highThreshold, mConfig.pointerVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.wheelVelocityControlParameters.scale, mConfig.wheelVelocityControlParameters.lowThreshold, mConfig.wheelVelocityControlParameters.highThreshold, mConfig.wheelVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "PointerGesture:\n"); dump.appendFormat(INDENT3 "Enabled: %s\n", toString(mConfig.pointerGesturesEnabled)); dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", mConfig.pointerGestureQuietInterval * 0.000001f); dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", mConfig.pointerGestureDragMinSwitchSpeed); dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", mConfig.pointerGestureTapInterval * 0.000001f); dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", mConfig.pointerGestureTapDragInterval * 0.000001f); dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", mConfig.pointerGestureTapSlop); dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", mConfig.pointerGestureMultitouchMinDistance); dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", mConfig.pointerGestureSwipeTransitionAngleCosine); dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", mConfig.pointerGestureSwipeMaxWidthRatio); dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", mConfig.pointerGestureMovementSpeedRatio); dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", mConfig.pointerGestureZoomSpeedRatio); } void InputReader::monitor() { // Acquire and release the lock to ensure that the reader has not deadlocked. mLock.lock(); mEventHub->wake(); mReaderIsAliveCondition.wait(mLock); mLock.unlock(); // Check the EventHub mEventHub->monitor(); } // --- InputReader::ContextImpl --- InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) { } void InputReader::ContextImpl::updateGlobalMetaState() { // lock is already held by the input loop mReader->updateGlobalMetaStateLocked(); } int32_t InputReader::ContextImpl::getGlobalMetaState() { // lock is already held by the input loop return mReader->getGlobalMetaStateLocked(); } void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { // lock is already held by the input loop mReader->disableVirtualKeysUntilLocked(time); } bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) { // lock is already held by the input loop return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); } void InputReader::ContextImpl::fadePointer() { // lock is already held by the input loop mReader->fadePointerLocked(); } void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { // lock is already held by the input loop mReader->requestTimeoutAtTimeLocked(when); } int32_t InputReader::ContextImpl::bumpGeneration() { // lock is already held by the input loop return mReader->bumpGenerationLocked(); } void InputReader::ContextImpl::getExternalStylusDevices(Vector& outDevices) { // lock is already held by whatever called refreshConfigurationLocked mReader->getExternalStylusDevicesLocked(outDevices); } void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { mReader->dispatchExternalStylusState(state); } InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } InputListenerInterface* InputReader::ContextImpl::getListener() { return mReader->mQueuedListener.get(); } EventHubInterface* InputReader::ContextImpl::getEventHub() { return mReader->mEventHub.get(); } // --- InputReaderThread --- InputReaderThread::InputReaderThread(const sp& reader) : Thread(/*canCallJava*/ true), mReader(reader) { } InputReaderThread::~InputReaderThread() { } bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } // --- InputDevice --- InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), mIdentifier(identifier), mClasses(classes), mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { delete mMappers[i]; } mMappers.clear(); } void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getDisplayName().string()); dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); const Vector& ranges = deviceInfo.getMotionRanges(); if (!ranges.isEmpty()) { dump.append(INDENT2 "Motion Ranges:\n"); for (size_t i = 0; i < ranges.size(); i++) { const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); const char* label = getAxisLabel(range.axis); char name[32]; if (label) { strncpy(name, label, sizeof(name)); name[sizeof(name) - 1] = '\0'; } else { snprintf(name, sizeof(name), "%d", range.axis); } dump.appendFormat(INDENT3 "%s: source=0x%08x, " "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", name, range.source, range.min, range.max, range.flat, range.fuzz, range.resolution); } } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->dump(dump); } } void InputDevice::addMapper(InputMapper* mapper) { mMappers.add(mapper); } void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; if (!isIgnored()) { if (!changes) { // first time only mContext->getEventHub()->getConfiguration(mId, &mConfiguration); } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { sp keyboardLayout = mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { bumpGeneration(); } } } if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); if (mAlias != alias) { mAlias = alias; bumpGeneration(); } } } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->configure(when, config, changes); mSources |= mapper->getSources(); } } } void InputDevice::reset(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->reset(when); } mContext->updateGlobalMetaState(); notifyReset(when); } void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { #if DEBUG_RAW_EVENTS ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when); #endif if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; #if DEBUG_RAW_EVENTS ALOGD("Recovered from input event buffer overrun."); #endif } else { #if DEBUG_RAW_EVENTS ALOGD("Dropped input event while waiting for next input sync."); #endif } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().string()); mDropUntilNextSync = true; reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } } void InputDevice::timeoutExpired(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->timeoutExpired(when); } } void InputDevice::updateExternalStylusState(const StylusState& state) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->updateExternalStylusState(state); } } void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, mHasMic); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->populateDeviceInfo(outDeviceInfo); } } int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); } int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); } int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return getState(sourceMask, switchCode, & InputMapper::getSwitchState); } int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; if (sourcesMatchMask(mapper->getSources(), sourceMask)) { // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { result = currentResult; } } } return result; } bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; if (sourcesMatchMask(mapper->getSources(), sourceMask)) { result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } return result; } void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->vibrate(pattern, patternSize, repeat, token); } } void InputDevice::cancelVibrate(int32_t token) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->cancelVibrate(token); } } void InputDevice::cancelTouch(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->cancelTouch(when); } } int32_t InputDevice::getMetaState() { int32_t result = 0; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; result |= mapper->getMetaState(); } return result; } void InputDevice::updateMetaState(int32_t keyCode) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { mMappers[i]->updateMetaState(keyCode); } } void InputDevice::fadePointer() { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->fadePointer(); } } void InputDevice::bumpGeneration() { mGeneration = mContext->bumpGeneration(); } void InputDevice::notifyReset(nsecs_t when) { NotifyDeviceResetArgs args(when, mId); mContext->getListener()->notifyDeviceReset(&args); } // --- CursorButtonAccumulator --- CursorButtonAccumulator::CursorButtonAccumulator() { clearButtons(); } void CursorButtonAccumulator::reset(InputDevice* device) { mBtnLeft = device->isKeyPressed(BTN_LEFT); mBtnRight = device->isKeyPressed(BTN_RIGHT); mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); mBtnBack = device->isKeyPressed(BTN_BACK); mBtnSide = device->isKeyPressed(BTN_SIDE); mBtnForward = device->isKeyPressed(BTN_FORWARD); mBtnExtra = device->isKeyPressed(BTN_EXTRA); mBtnTask = device->isKeyPressed(BTN_TASK); } void CursorButtonAccumulator::clearButtons() { mBtnLeft = 0; mBtnRight = 0; mBtnMiddle = 0; mBtnBack = 0; mBtnSide = 0; mBtnForward = 0; mBtnExtra = 0; mBtnTask = 0; } void CursorButtonAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_KEY) { switch (rawEvent->code) { case BTN_LEFT: mBtnLeft = rawEvent->value; break; case BTN_RIGHT: mBtnRight = rawEvent->value; break; case BTN_MIDDLE: mBtnMiddle = rawEvent->value; break; case BTN_BACK: mBtnBack = rawEvent->value; break; case BTN_SIDE: mBtnSide = rawEvent->value; break; case BTN_FORWARD: mBtnForward = rawEvent->value; break; case BTN_EXTRA: mBtnExtra = rawEvent->value; break; case BTN_TASK: mBtnTask = rawEvent->value; break; } } } uint32_t CursorButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnLeft) { result |= AMOTION_EVENT_BUTTON_PRIMARY; } if (mBtnRight) { result |= AMOTION_EVENT_BUTTON_SECONDARY; } if (mBtnMiddle) { result |= AMOTION_EVENT_BUTTON_TERTIARY; } if (mBtnBack || mBtnSide) { result |= AMOTION_EVENT_BUTTON_BACK; } if (mBtnForward || mBtnExtra) { result |= AMOTION_EVENT_BUTTON_FORWARD; } return result; } // --- CursorMotionAccumulator --- CursorMotionAccumulator::CursorMotionAccumulator() { clearRelativeAxes(); } void CursorMotionAccumulator::reset(InputDevice* device) { clearRelativeAxes(); } void CursorMotionAccumulator::clearRelativeAxes() { mRelX = 0; mRelY = 0; } void CursorMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_REL) { switch (rawEvent->code) { case REL_X: mRelX = rawEvent->value; break; case REL_Y: mRelY = rawEvent->value; break; } } } void CursorMotionAccumulator::finishSync() { clearRelativeAxes(); } // --- CursorScrollAccumulator --- CursorScrollAccumulator::CursorScrollAccumulator() : mHaveRelWheel(false), mHaveRelHWheel(false) { clearRelativeAxes(); } void CursorScrollAccumulator::configure(InputDevice* device) { mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); } void CursorScrollAccumulator::reset(InputDevice* device) { clearRelativeAxes(); } void CursorScrollAccumulator::clearRelativeAxes() { mRelWheel = 0; mRelHWheel = 0; } void CursorScrollAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_REL) { switch (rawEvent->code) { case REL_WHEEL: mRelWheel = rawEvent->value; break; case REL_HWHEEL: mRelHWheel = rawEvent->value; break; } } } void CursorScrollAccumulator::finishSync() { clearRelativeAxes(); } // --- TouchButtonAccumulator --- TouchButtonAccumulator::TouchButtonAccumulator() : mHaveBtnTouch(false), mHaveStylus(false) { clearButtons(); } void TouchButtonAccumulator::configure(InputDevice* device) { mHaveBtnTouch = device->hasKey(BTN_TOUCH); mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) || device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) || device->hasKey(BTN_TOOL_AIRBRUSH); } void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); } void TouchButtonAccumulator::clearButtons() { mBtnTouch = 0; mBtnStylus = 0; mBtnStylus2 = 0; mBtnToolFinger = 0; mBtnToolPen = 0; mBtnToolRubber = 0; mBtnToolBrush = 0; mBtnToolPencil = 0; mBtnToolAirbrush = 0; mBtnToolMouse = 0; mBtnToolLens = 0; mBtnToolDoubleTap = 0; mBtnToolTripleTap = 0; mBtnToolQuadTap = 0; } void TouchButtonAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_KEY) { switch (rawEvent->code) { case BTN_TOUCH: mBtnTouch = rawEvent->value; break; case BTN_STYLUS: mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: mBtnToolFinger = rawEvent->value; break; case BTN_TOOL_PEN: mBtnToolPen = rawEvent->value; break; case BTN_TOOL_RUBBER: mBtnToolRubber = rawEvent->value; break; case BTN_TOOL_BRUSH: mBtnToolBrush = rawEvent->value; break; case BTN_TOOL_PENCIL: mBtnToolPencil = rawEvent->value; break; case BTN_TOOL_AIRBRUSH: mBtnToolAirbrush = rawEvent->value; break; case BTN_TOOL_MOUSE: mBtnToolMouse = rawEvent->value; break; case BTN_TOOL_LENS: mBtnToolLens = rawEvent->value; break; case BTN_TOOL_DOUBLETAP: mBtnToolDoubleTap = rawEvent->value; break; case BTN_TOOL_TRIPLETAP: mBtnToolTripleTap = rawEvent->value; break; case BTN_TOOL_QUADTAP: mBtnToolQuadTap = rawEvent->value; break; } } } uint32_t TouchButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnStylus) { result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; } if (mBtnStylus2) { result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; } return result; } int32_t TouchButtonAccumulator::getToolType() const { if (mBtnToolMouse || mBtnToolLens) { return AMOTION_EVENT_TOOL_TYPE_MOUSE; } if (mBtnToolRubber) { return AMOTION_EVENT_TOOL_TYPE_ERASER; } if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { return AMOTION_EVENT_TOOL_TYPE_STYLUS; } if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { return AMOTION_EVENT_TOOL_TYPE_FINGER; } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } bool TouchButtonAccumulator::isToolActive() const { return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush || mBtnToolMouse || mBtnToolLens || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; } bool TouchButtonAccumulator::isHovering() const { return mHaveBtnTouch && !mBtnTouch; } bool TouchButtonAccumulator::hasStylus() const { return mHaveStylus; } // --- RawPointerAxes --- RawPointerAxes::RawPointerAxes() { clear(); } void RawPointerAxes::clear() { x.clear(); y.clear(); pressure.clear(); touchMajor.clear(); touchMinor.clear(); toolMajor.clear(); toolMinor.clear(); orientation.clear(); distance.clear(); tiltX.clear(); tiltY.clear(); trackingId.clear(); slot.clear(); } // --- RawPointerData --- RawPointerData::RawPointerData() { clear(); } void RawPointerData::clear() { pointerCount = 0; clearIdBits(); } void RawPointerData::copyFrom(const RawPointerData& other) { pointerCount = other.pointerCount; hoveringIdBits = other.hoveringIdBits; touchingIdBits = other.touchingIdBits; for (uint32_t i = 0; i < pointerCount; i++) { pointers[i] = other.pointers[i]; int id = pointers[i].id; idToIndex[id] = other.idToIndex[id]; } } void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { float x = 0, y = 0; uint32_t count = touchingIdBits.count(); if (count) { for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); const Pointer& pointer = pointerForId(id); x += pointer.x; y += pointer.y; } x /= count; y /= count; } *outX = x; *outY = y; } // --- CookedPointerData --- CookedPointerData::CookedPointerData() { clear(); } void CookedPointerData::clear() { pointerCount = 0; hoveringIdBits.clear(); touchingIdBits.clear(); } void CookedPointerData::copyFrom(const CookedPointerData& other) { pointerCount = other.pointerCount; hoveringIdBits = other.hoveringIdBits; touchingIdBits = other.touchingIdBits; for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); pointerCoords[i].copyFrom(other.pointerCoords[i]); int id = pointerProperties[i].id; idToIndex[id] = other.idToIndex[id]; } } // --- SingleTouchMotionAccumulator --- SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { clearAbsoluteAxes(); } void SingleTouchMotionAccumulator::reset(InputDevice* device) { mAbsX = device->getAbsoluteAxisValue(ABS_X); mAbsY = device->getAbsoluteAxisValue(ABS_Y); mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); } void SingleTouchMotionAccumulator::clearAbsoluteAxes() { mAbsX = 0; mAbsY = 0; mAbsPressure = 0; mAbsToolWidth = 0; mAbsDistance = 0; mAbsTiltX = 0; mAbsTiltY = 0; } void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { switch (rawEvent->code) { case ABS_X: mAbsX = rawEvent->value; break; case ABS_Y: mAbsY = rawEvent->value; break; case ABS_PRESSURE: mAbsPressure = rawEvent->value; break; case ABS_TOOL_WIDTH: mAbsToolWidth = rawEvent->value; break; case ABS_DISTANCE: mAbsDistance = rawEvent->value; break; case ABS_TILT_X: mAbsTiltX = rawEvent->value; break; case ABS_TILT_Y: mAbsTiltY = rawEvent->value; break; } } } // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false), mHaveStylus(false) { } MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { delete[] mSlots; } void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol) { mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); delete[] mSlots; mSlots = new Slot[slotCount]; } void MultiTouchMotionAccumulator::reset(InputDevice* device) { // Unfortunately there is no way to read the initial contents of the slots. // So when we reset the accumulator, we must assume they are all zeroes. if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot // before we start reading events from the device. It is possible that the // current slot index will not be the same as it was when the first event was // written into the evdev buffer, which means the input mapper could start // out of sync with the initial state of the events in the evdev buffer. // In the extremely unlikely case that this happens, the data from // two slots will be confused until the next ABS_MT_SLOT event is received. // This can cause the touch point to "jump", but at least there will be // no stuck touches. int32_t initialSlot; status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), ABS_MT_SLOT, &initialSlot); if (status) { ALOGD("Could not retrieve current multitouch slot index. status=%d", status); initialSlot = -1; } clearSlots(initialSlot); } else { clearSlots(-1); } } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { if (mSlots) { for (size_t i = 0; i < mSlotCount; i++) { mSlots[i].clear(); } } mCurrentSlot = initialSlot; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { #if DEBUG_POINTERS if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %d; ignoring this slot.", mCurrentSlot, mSlotCount - 1); } #endif } else { Slot* slot = &mSlots[mCurrentSlot]; switch (rawEvent->code) { case ABS_MT_POSITION_X: slot->mInUse = true; slot->mAbsMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y: slot->mInUse = true; slot->mAbsMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: slot->mInUse = true; slot->mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot->mInUse = true; slot->mAbsMTTouchMinor = rawEvent->value; slot->mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot->mInUse = true; slot->mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot->mInUse = true; slot->mAbsMTWidthMinor = rawEvent->value; slot->mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: slot->mInUse = true; slot->mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot->mInUse = false; } else { slot->mInUse = true; slot->mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot->mInUse = true; slot->mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot->mInUse = true; slot->mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot->mInUse = true; slot->mAbsMTToolType = rawEvent->value; slot->mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { clearSlots(-1); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } // --- MultiTouchMotionAccumulator::Slot --- MultiTouchMotionAccumulator::Slot::Slot() { clear(); } void MultiTouchMotionAccumulator::Slot::clear() { mInUse = false; mHaveAbsMTTouchMinor = false; mHaveAbsMTWidthMinor = false; mHaveAbsMTToolType = false; mAbsMTPositionX = 0; mAbsMTPositionY = 0; mAbsMTTouchMajor = 0; mAbsMTTouchMinor = 0; mAbsMTWidthMajor = 0; mAbsMTWidthMinor = 0; mAbsMTOrientation = 0; mAbsMTTrackingId = -1; mAbsMTPressure = 0; mAbsMTDistance = 0; mAbsMTToolType = 0; } int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } // --- InputMapper --- InputMapper::InputMapper(InputDevice* device) : mDevice(device), mContext(device->getContext()) { } InputMapper::~InputMapper() { } void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addSource(getSources()); } void InputMapper::dump(String8& dump) { } void InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { } void InputMapper::reset(nsecs_t when) { } void InputMapper::timeoutExpired(nsecs_t when) { } int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return AKEY_STATE_UNKNOWN; } int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return AKEY_STATE_UNKNOWN; } int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return AKEY_STATE_UNKNOWN; } bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { return false; } void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { } void InputMapper::cancelVibrate(int32_t token) { } void InputMapper::cancelTouch(nsecs_t when) { } int32_t InputMapper::getMetaState() { return 0; } void InputMapper::updateMetaState(int32_t keyCode) { } void InputMapper::updateExternalStylusState(const StylusState& state) { } void InputMapper::fadePointer() { } status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); } void InputMapper::bumpGeneration() { mDevice->bumpGeneration(); } void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name) { if (axis.valid) { dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); } else { dump.appendFormat(INDENT4 "%s: unknown range\n", name); } } void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); } // --- SwitchInputMapper --- SwitchInputMapper::SwitchInputMapper(InputDevice* device) : InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) { } SwitchInputMapper::~SwitchInputMapper() { } uint32_t SwitchInputMapper::getSources() { return AINPUT_SOURCE_SWITCH; } void SwitchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_SW: processSwitch(rawEvent->code, rawEvent->value); break; case EV_SYN: if (rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } } void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { if (switchCode >= 0 && switchCode < 32) { if (switchValue) { mSwitchValues |= 1 << switchCode; } else { mSwitchValues &= ~(1 << switchCode); } mUpdatedSwitchMask |= 1 << switchCode; } } void SwitchInputMapper::sync(nsecs_t when) { if (mUpdatedSwitchMask) { uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; NotifySwitchArgs args(when, 0, updatedSwitchValues, mUpdatedSwitchMask); getListener()->notifySwitch(&args); mUpdatedSwitchMask = 0; } } int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return getEventHub()->getSwitchState(getDeviceId(), switchCode); } void SwitchInputMapper::dump(String8& dump) { dump.append(INDENT2 "Switch Input Mapper:\n"); dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues); } // --- VibratorInputMapper --- VibratorInputMapper::VibratorInputMapper(InputDevice* device) : InputMapper(device), mVibrating(false) { } VibratorInputMapper::~VibratorInputMapper() { } uint32_t VibratorInputMapper::getSources() { return 0; } void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->setVibrator(true); } void VibratorInputMapper::process(const RawEvent* rawEvent) { // TODO: Handle FF_STATUS, although it does not seem to be widely supported. } void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { #if DEBUG_VIBRATOR String8 patternStr; for (size_t i = 0; i < patternSize; i++) { if (i != 0) { patternStr.append(", "); } patternStr.appendFormat("%lld", pattern[i]); } ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", getDeviceId(), patternStr.string(), repeat, token); #endif mVibrating = true; memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); mPatternSize = patternSize; mRepeat = repeat; mToken = token; mIndex = -1; nextStep(); } void VibratorInputMapper::cancelVibrate(int32_t token) { #if DEBUG_VIBRATOR ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); #endif if (mVibrating && mToken == token) { stopVibrating(); } } void VibratorInputMapper::timeoutExpired(nsecs_t when) { if (mVibrating) { if (when >= mNextStepTime) { nextStep(); } else { getContext()->requestTimeoutAtTime(mNextStepTime); } } } void VibratorInputMapper::nextStep() { mIndex += 1; if (size_t(mIndex) >= mPatternSize) { if (mRepeat < 0) { // We are done. stopVibrating(); return; } mIndex = mRepeat; } bool vibratorOn = mIndex & 1; nsecs_t duration = mPattern[mIndex]; if (vibratorOn) { #if DEBUG_VIBRATOR ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", getDeviceId(), duration); #endif getEventHub()->vibrate(getDeviceId(), duration); } else { #if DEBUG_VIBRATOR ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); #endif getEventHub()->cancelVibrate(getDeviceId()); } nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); mNextStepTime = now + duration; getContext()->requestTimeoutAtTime(mNextStepTime); #if DEBUG_VIBRATOR ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); #endif } void VibratorInputMapper::stopVibrating() { mVibrating = false; #if DEBUG_VIBRATOR ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); #endif getEventHub()->cancelVibrate(getDeviceId()); } void VibratorInputMapper::dump(String8& dump) { dump.append(INDENT2 "Vibrator Input Mapper:\n"); dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating)); } // --- KeyboardInputMapper --- KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) : InputMapper(device), mSource(source), mKeyboardType(keyboardType) { } KeyboardInputMapper::~KeyboardInputMapper() { } uint32_t KeyboardInputMapper::getSources() { return mSource; } void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->setKeyboardType(mKeyboardType); info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); } void KeyboardInputMapper::dump(String8& dump) { dump.append(INDENT2 "Keyboard Input Mapper:\n"); dumpParameters(dump); dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime); } void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only // Configure basic parameters. configureParameters(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { DisplayViewport v; if (config->getDisplayInfo(false /*external*/, &v)) { mOrientation = v.orientation; } else { mOrientation = DISPLAY_ORIENTATION_0; } } else { mOrientation = DISPLAY_ORIENTATION_0; } } } void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; if (mParameters.orientationAware) { mParameters.hasAssociatedDisplay = true; } mParameters.handlesKeyRepeat = false; getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); } void KeyboardInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", toString(mParameters.hasAssociatedDisplay)); dump.appendFormat(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat)); } void KeyboardInputMapper::reset(nsecs_t when) { mMetaState = AMETA_NONE; mDownTime = 0; mKeyDowns.clear(); mCurrentHidUsage = 0; resetLedState(); InputMapper::reset(when); } void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) { processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); } break; } case EV_MSC: { if (rawEvent->code == MSC_SCAN) { mCurrentHidUsage = rawEvent->value; } break; } case EV_SYN: { if (rawEvent->code == SYN_REPORT) { mCurrentHidUsage = 0; } } } } bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { return scanCode < BTN_MOUSE || scanCode >= KEY_OK || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); } void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { int32_t keyCode; int32_t keyMetaState; uint32_t policyFlags; if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode, &keyMetaState, &policyFlags)) { keyCode = AKEYCODE_UNKNOWN; keyMetaState = mMetaState; policyFlags = 0; } if (down) { // Rotate key codes according to orientation if needed. if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { keyCode = rotateKeyCode(keyCode, mOrientation); } // Add key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { return; } if (policyFlags & POLICY_FLAG_GESTURE) { mDevice->cancelTouch(when); } mKeyDowns.push(); KeyDown& keyDown = mKeyDowns.editTop(); keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; } mDownTime = when; } else { // Remove key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; mKeyDowns.removeAt(size_t(keyDownIndex)); } else { // key was not actually down ALOGI("Dropping key up from device %s because the key was not down. " "keyCode=%d, scanCode=%d", getDeviceName().string(), keyCode, scanCode); return; } } if (updateMetaStateIfNeeded(keyCode, down)) { // If global meta state changed send it along with the key. // If it has not changed then we'll use what keymap gave us, // since key replacement logic might temporarily reset a few // meta bits for given key. keyMetaState = mMetaState; } nsecs_t downTime = mDownTime; // Key down on external an keyboard should wake the device. // We don't do this for internal keyboards to prevent them from waking up in your pocket. // For internal keyboards, the key layout file should specify the policy flags for // each wake key individually. // TODO: Use the input device configuration to control this behavior more finely. if (down && getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE; } if (mParameters.handlesKeyRepeat) { policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } if (down && !isMetaKey(keyCode)) { getContext()->fadePointer(); } NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); getListener()->notifyKey(&args); } ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { size_t n = mKeyDowns.size(); for (size_t i = 0; i < n; i++) { if (mKeyDowns[i].scanCode == scanCode) { return i; } } return -1; } int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); } int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return getEventHub()->getScanCodeState(getDeviceId(), scanCode); } bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); } int32_t KeyboardInputMapper::getMetaState() { return mMetaState; } void KeyboardInputMapper::updateMetaState(int32_t keyCode) { updateMetaStateIfNeeded(keyCode, false); } bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) { int32_t oldMetaState = mMetaState; int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState); bool metaStateChanged = oldMetaState != newMetaState; if (metaStateChanged) { mMetaState = newMetaState; updateLedState(false); getContext()->updateGlobalMetaState(); } return metaStateChanged; } void KeyboardInputMapper::resetLedState() { initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK); initializeLedState(mNumLockLedState, ALED_NUM_LOCK); initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK); updateLedState(true); } void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { ledState.avail = getEventHub()->hasLed(getDeviceId(), led); ledState.on = false; } void KeyboardInputMapper::updateLedState(bool reset) { updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset); updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset); updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset); } void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset) { if (ledState.avail) { bool desiredState = (mMetaState & modifier) != 0; if (reset || ledState.on != desiredState) { getEventHub()->setLedState(getDeviceId(), led, desiredState); ledState.on = desiredState; } } } // --- CursorInputMapper --- CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) { } CursorInputMapper::~CursorInputMapper() { } uint32_t CursorInputMapper::getSources() { return mSource; } void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); if (mParameters.mode == Parameters::MODE_POINTER) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); } } else { info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); } info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); if (mCursorScrollAccumulator.haveRelativeVWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); } if (mCursorScrollAccumulator.haveRelativeHWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); } } void CursorInputMapper::dump(String8& dump) { dump.append(INDENT2 "Cursor Input Mapper:\n"); dumpParameters(dump); dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); dump.appendFormat(INDENT3 "HaveVWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeVWheel())); dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeHWheel())); dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime); } void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only mCursorScrollAccumulator.configure(getDevice()); // Configure basic parameters. configureParameters(); // Configure device mode. switch (mParameters.mode) { case Parameters::MODE_POINTER: mSource = AINPUT_SOURCE_MOUSE; mXPrecision = 1.0f; mYPrecision = 1.0f; mXScale = 1.0f; mYScale = 1.0f; mPointerController = getPolicy()->obtainPointerController(getDeviceId()); break; case Parameters::MODE_NAVIGATION: mSource = AINPUT_SOURCE_TRACKBALL; mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; break; } mVWheelScale = 1.0f; mHWheelScale = 1.0f; } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { DisplayViewport v; if (config->getDisplayInfo(false /*external*/, &v)) { mOrientation = v.orientation; } else { mOrientation = DISPLAY_ORIENTATION_0; } } else { mOrientation = DISPLAY_ORIENTATION_0; } bumpGeneration(); } } void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::MODE_POINTER; String8 cursorModeString; if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { if (cursorModeString == "navigation") { mParameters.mode = Parameters::MODE_NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); } } mParameters.orientationAware = false; getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { mParameters.hasAssociatedDisplay = true; } } void CursorInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", toString(mParameters.hasAssociatedDisplay)); switch (mParameters.mode) { case Parameters::MODE_POINTER: dump.append(INDENT4 "Mode: pointer\n"); break; case Parameters::MODE_NAVIGATION: dump.append(INDENT4 "Mode: navigation\n"); break; default: ALOG_ASSERT(false); } dump.appendFormat(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } void CursorInputMapper::reset(nsecs_t when) { mButtonState = 0; mDownTime = 0; mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); mCursorButtonAccumulator.reset(getDevice()); mCursorMotionAccumulator.reset(getDevice()); mCursorScrollAccumulator.reset(getDevice()); InputMapper::reset(when); } void CursorInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorMotionAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void CursorInputMapper::sync(nsecs_t when) { int32_t lastButtonState = mButtonState; int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); mButtonState = currentButtonState; bool wasDown = isPointerDown(lastButtonState); bool down = isPointerDown(currentButtonState); bool downChanged; if (!wasDown && down) { mDownTime = when; downChanged = true; } else if (wasDown && !down) { downChanged = true; } else { downChanged = false; } nsecs_t downTime = mDownTime; bool buttonsChanged = currentButtonState != lastButtonState; int32_t buttonsPressed = currentButtonState & ~lastButtonState; int32_t buttonsReleased = lastButtonState & ~currentButtonState; float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; bool moved = deltaX != 0 || deltaY != 0; // Rotate delta according to orientation if needed. if (mParameters.orientationAware && mParameters.hasAssociatedDisplay && (deltaX != 0.0f || deltaY != 0.0f)) { rotateDelta(mOrientation, &deltaX, &deltaY); } // Move the pointer. PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; PointerCoords pointerCoords; pointerCoords.clear(); float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); bool scrolled = vscroll != 0 || hscroll != 0; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); mPointerVelocityControl.move(when, &deltaX, &deltaY); int32_t displayId; if (mPointerController != NULL) { if (moved || scrolled || buttonsChanged) { mPointerController->setPresentation( PointerControllerInterface::PRESENTATION_POINTER); if (moved) { mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { mPointerController->setButtonState(currentButtonState); } mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } float x, y; mPointerController->getPosition(&x, &y); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); displayId = ADISPLAY_ID_DEFAULT; } else { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); displayId = ADISPLAY_ID_NONE; } pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); // Moving an external trackball or mouse should wake the device. // We don't do this for internal cursor devices to prevent them from waking up // the device in your pocket. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE; } // Synthesize key down from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { int32_t metaState = mContext->getGlobalMetaState(); int32_t buttonState = lastButtonState; int32_t motionEventAction; if (downChanged) { motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else if (down || mPointerController == NULL) { motionEventAction = AMOTION_EVENT_ACTION_MOVE; } else { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; } if (buttonsReleased) { BitSet32 released(buttonsReleased); while (!released.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&releaseArgs); } } NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&args); if (buttonsPressed) { BitSet32 pressed(buttonsPressed); while (!pressed.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&pressArgs); } } ALOG_ASSERT(buttonState == currentButtonState); // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && mPointerController != NULL) { NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&hoverArgs); } // Send scroll events. if (scrolled) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&scrollArgs); } } // Synthesize key up from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); mCursorMotionAccumulator.finishSync(); mCursorScrollAccumulator.finishSync(); } int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { return getEventHub()->getScanCodeState(getDeviceId(), scanCode); } else { return AKEY_STATE_UNKNOWN; } } void CursorInputMapper::fadePointer() { if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } // --- RotaryEncoderInputMapper --- RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) : InputMapper(device) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; } RotaryEncoderInputMapper::~RotaryEncoderInputMapper() { } uint32_t RotaryEncoderInputMapper::getSources() { return mSource; } void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { float res = 0.0f; if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), mScalingFactor)) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," "default to 1.0!\n"); mScalingFactor = 1.0f; } info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, res * mScalingFactor); } } void RotaryEncoderInputMapper::dump(String8& dump) { dump.append(INDENT2 "Rotary Encoder Input Mapper:\n"); dump.appendFormat(INDENT3 "HaveWheel: %s\n", toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); } void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { mRotaryEncoderScrollAccumulator.configure(getDevice()); } } void RotaryEncoderInputMapper::reset(nsecs_t when) { mRotaryEncoderScrollAccumulator.reset(getDevice()); InputMapper::reset(when); } void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { mRotaryEncoderScrollAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void RotaryEncoderInputMapper::sync(nsecs_t when) { PointerCoords pointerCoords; pointerCoords.clear(); PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); bool scrolled = scroll != 0; // This is not a pointer, so it's not associated with a display. int32_t displayId = ADISPLAY_ID_NONE; // Moving the rotary encoder should wake the device (if specified). uint32_t policyFlags = 0; if (scrolled && getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE; } // Send motion event. if (scrolled) { int32_t metaState = mContext->getGlobalMetaState(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, 0, 0, 0); getListener()->notifyMotion(&scrollArgs); } mRotaryEncoderScrollAccumulator.finishSync(); } // --- TouchInputMapper --- TouchInputMapper::TouchInputMapper(InputDevice* device) : InputMapper(device), mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), mSurfaceOrientation(DISPLAY_ORIENTATION_0) { } TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { return mSource; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); if (mDeviceMode != DEVICE_MODE_DISABLED) { info->addMotionRange(mOrientedRanges.x); info->addMotionRange(mOrientedRanges.y); info->addMotionRange(mOrientedRanges.pressure); if (mOrientedRanges.haveSize) { info->addMotionRange(mOrientedRanges.size); } if (mOrientedRanges.haveTouchSize) { info->addMotionRange(mOrientedRanges.touchMajor); info->addMotionRange(mOrientedRanges.touchMinor); } if (mOrientedRanges.haveToolSize) { info->addMotionRange(mOrientedRanges.toolMajor); info->addMotionRange(mOrientedRanges.toolMinor); } if (mOrientedRanges.haveOrientation) { info->addMotionRange(mOrientedRanges.orientation); } if (mOrientedRanges.haveDistance) { info->addMotionRange(mOrientedRanges.distance); } if (mOrientedRanges.haveTilt) { info->addMotionRange(mOrientedRanges.tilt); } if (mCursorScrollAccumulator.haveRelativeVWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); } if (mCursorScrollAccumulator.haveRelativeHWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); } if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, x.fuzz, x.resolution); info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, y.fuzz, y.resolution); info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, x.fuzz, x.resolution); info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz, y.resolution); } info->setButtonUnderPad(mParameters.hasButtonUnderPad); } } void TouchInputMapper::dump(String8& dump) { dump.append(INDENT2 "Touch Input Mapper:\n"); dumpParameters(dump); dumpVirtualKeys(dump); dumpRawPointerAxes(dump); dumpCalibration(dump); dumpAffineTransformation(dump); dumpSurface(dump); dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate); dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate); dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale); dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale); dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision); dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", mLastRawState.rawPointerData.pointerCount); for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " "toolType=%d, isHovering=%s\n", i, pointer.id, pointer.x, pointer.y, pointer.pressure, pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, pointer.toolType, toString(pointer.isHovering)); } dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", mLastCookedState.cookedPointerData.pointerCount); for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { const PointerProperties& pointerProperties = mLastCookedState.cookedPointerData.pointerProperties[i]; const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " "toolType=%d, isHovering=%s\n", i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, toString(mLastCookedState.cookedPointerData.isHovering(i))); } dump.append(INDENT3 "Stylus Fusion:\n"); dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", toString(mExternalStylusConnected)); dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", mExternalStylusFusionTimeout); dump.append(INDENT3 "External Stylus State:\n"); dumpStylusState(dump, mExternalStylusState); if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale); dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale); dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale); dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale); dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); } } void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); mConfig = *config; if (!changes) { // first time only // Configure basic parameters. configureParameters(); // Configure common accumulators. mCursorScrollAccumulator.configure(getDevice()); mTouchButtonAccumulator.configure(getDevice()); // Configure absolute axis information. configureRawPointerAxes(); // Prepare input device calibration. parseCalibration(); resolveCalibration(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { // Update location calibration to reflect current settings updateAffineTransformation(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { // Update pointer speed. mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); } bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); } if (changes && resetNeeded) { // Send reset, unless this is the first time the device has been configured, // in which case the reader will call reset itself after all mappers are ready. getDevice()->notifyReset(when); } } void TouchInputMapper::resolveExternalStylusPresence() { Vector devices; mContext->getExternalStylusDevices(devices); mExternalStylusConnected = !devices.isEmpty(); if (!mExternalStylusConnected) { resetExternalStylus(); } } void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately // locate two or more fingers on the touch pad. mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH; String8 gestureModeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), gestureModeString)) { if (gestureModeString == "single-touch") { mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; } else if (gestureModeString == "multi-touch") { mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH; } else if (gestureModeString != "default") { ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); } } if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { // The device is a touch screen. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { // The device is a pointing device like a track pad. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { // The device is a cursor device with a touch pad attached. // By default don't use the touch pad to move the pointer. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; } else { // The device is a touch pad of unknown purpose. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } mParameters.hasButtonUnderPad= getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); String8 deviceTypeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (deviceTypeString == "touchPad") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; } else if (deviceTypeString == "touchNavigation") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else if (deviceTypeString != "default") { ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); } } mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; mParameters.associatedDisplayIsExternal = false; if (mParameters.orientationAware || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { mParameters.hasAssociatedDisplay = true; mParameters.associatedDisplayIsExternal = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && getDevice()->isExternal(); } // Initial downs on external touch devices should wake the device. // Normally we don't do this for internal touch screens to prevent them from waking // up in your pocket but you can enable it using the input device configuration. mParameters.wake = getDevice()->isExternal(); getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); } void TouchInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); switch (mParameters.gestureMode) { case Parameters::GESTURE_MODE_SINGLE_TOUCH: dump.append(INDENT4 "GestureMode: single-touch\n"); break; case Parameters::GESTURE_MODE_MULTI_TOUCH: dump.append(INDENT4 "GestureMode: multi-touch\n"); break; default: assert(false); } switch (mParameters.deviceType) { case Parameters::DEVICE_TYPE_TOUCH_SCREEN: dump.append(INDENT4 "DeviceType: touchScreen\n"); break; case Parameters::DEVICE_TYPE_TOUCH_PAD: dump.append(INDENT4 "DeviceType: touchPad\n"); break; case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: dump.append(INDENT4 "DeviceType: touchNavigation\n"); break; case Parameters::DEVICE_TYPE_POINTER: dump.append(INDENT4 "DeviceType: pointer\n"); break; default: ALOG_ASSERT(false); } dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n", toString(mParameters.hasAssociatedDisplay), toString(mParameters.associatedDisplayIsExternal)); dump.appendFormat(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } void TouchInputMapper::configureRawPointerAxes() { mRawPointerAxes.clear(); } void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dump.append(INDENT3 "Raw Touch Axes:\n"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } bool TouchInputMapper::hasExternalStylus() const { return mExternalStylusConnected; } void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; resolveExternalStylusPresence(); // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { mSource = AINPUT_SOURCE_MOUSE; mDeviceMode = DEVICE_MODE_POINTER; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && mParameters.hasAssociatedDisplay) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } if (hasExternalStylus()) { mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; mDeviceMode = DEVICE_MODE_NAVIGATION; } else { mSource = AINPUT_SOURCE_TOUCHPAD; mDeviceMode = DEVICE_MODE_UNSCALED; } // Ensure we have valid X and Y axes. if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " "The device will be inoperable.", getDeviceName().string()); mDeviceMode = DEVICE_MODE_DISABLED; return; } // Raw width and height in the natural orientation. int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; // Get associated display dimensions. DisplayViewport newViewport; if (mParameters.hasAssociatedDisplay) { if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) { ALOGI(INDENT "Touch device '%s' could not query the properties of its associated " "display. The device will be inoperable until the display size " "becomes available.", getDeviceName().string()); mDeviceMode = DEVICE_MODE_DISABLED; return; } } else { newViewport.setNonDisplayViewport(rawWidth, rawHeight); } bool viewportChanged = mViewport != newViewport; if (viewportChanged) { mViewport = newViewport; if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { // Convert rotated viewport to natural surface coordinates. int32_t naturalLogicalWidth, naturalLogicalHeight; int32_t naturalPhysicalWidth, naturalPhysicalHeight; int32_t naturalPhysicalLeft, naturalPhysicalTop; int32_t naturalDeviceWidth, naturalDeviceHeight; switch (mViewport.orientation) { case DISPLAY_ORIENTATION_90: naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; naturalPhysicalTop = mViewport.physicalLeft; naturalDeviceWidth = mViewport.deviceHeight; naturalDeviceHeight = mViewport.deviceWidth; break; case DISPLAY_ORIENTATION_180: naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; naturalDeviceWidth = mViewport.deviceWidth; naturalDeviceHeight = mViewport.deviceHeight; break; case DISPLAY_ORIENTATION_270: naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalLeft = mViewport.physicalTop; naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; naturalDeviceWidth = mViewport.deviceHeight; naturalDeviceHeight = mViewport.deviceWidth; break; case DISPLAY_ORIENTATION_0: default: naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; naturalPhysicalLeft = mViewport.physicalLeft; naturalPhysicalTop = mViewport.physicalTop; naturalDeviceWidth = mViewport.deviceWidth; naturalDeviceHeight = mViewport.deviceHeight; break; } mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0; } else { mSurfaceWidth = rawWidth; mSurfaceHeight = rawHeight; mSurfaceLeft = 0; mSurfaceTop = 0; mSurfaceOrientation = DISPLAY_ORIENTATION_0; } } // If moving between pointer modes, need to reset some state. bool deviceModeChanged = mDeviceMode != oldDeviceMode; if (deviceModeChanged) { mOrientedRanges.clear(); } // Create pointer controller if needed. if (mDeviceMode == DEVICE_MODE_POINTER || (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { if (mPointerController == NULL) { mPointerController = getPolicy()->obtainPointerController(getDeviceId()); } } else { mPointerController.clear(); } if (viewportChanged || deviceModeChanged) { ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " "display id %d", getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight, mSurfaceOrientation, mDeviceMode, mViewport.displayId); // Configure X and Y factors. mXScale = float(mSurfaceWidth) / rawWidth; mYScale = float(mSurfaceHeight) / rawHeight; mXTranslate = -mSurfaceLeft; mYTranslate = -mSurfaceTop; mXPrecision = 1.0f / mXScale; mYPrecision = 1.0f / mYScale; mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; mOrientedRanges.x.source = mSource; mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; mOrientedRanges.y.source = mSource; configureVirtualKeys(); // Scale factor for terms that are not oriented in a particular axis. // If the pixels are square then xScale == yScale otherwise we fake it // by choosing an average. mGeometricScale = avg(mXScale, mYScale); // Size of diagonal axis. float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); // Size factors. if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; } else { mSizeScale = 0.0f; } mOrientedRanges.haveTouchSize = true; mOrientedRanges.haveToolSize = true; mOrientedRanges.haveSize = true; mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; mOrientedRanges.touchMajor.source = mSource; mOrientedRanges.touchMajor.min = 0; mOrientedRanges.touchMajor.max = diagonalSize; mOrientedRanges.touchMajor.flat = 0; mOrientedRanges.touchMajor.fuzz = 0; mOrientedRanges.touchMajor.resolution = 0; mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; mOrientedRanges.toolMajor.source = mSource; mOrientedRanges.toolMajor.min = 0; mOrientedRanges.toolMajor.max = diagonalSize; mOrientedRanges.toolMajor.flat = 0; mOrientedRanges.toolMajor.fuzz = 0; mOrientedRanges.toolMajor.resolution = 0; mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; mOrientedRanges.size.source = mSource; mOrientedRanges.size.min = 0; mOrientedRanges.size.max = 1.0; mOrientedRanges.size.flat = 0; mOrientedRanges.size.fuzz = 0; mOrientedRanges.size.resolution = 0; } else { mSizeScale = 0.0f; } // Pressure factors. mPressureScale = 0; if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL || mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { if (mCalibration.havePressureScale) { mPressureScale = mCalibration.pressureScale; } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; } } mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; mOrientedRanges.pressure.source = mSource; mOrientedRanges.pressure.min = 0; mOrientedRanges.pressure.max = 1.0; mOrientedRanges.pressure.flat = 0; mOrientedRanges.pressure.fuzz = 0; mOrientedRanges.pressure.resolution = 0; // Tilt mTiltXCenter = 0; mTiltXScale = 0; mTiltYCenter = 0; mTiltYScale = 0; mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; if (mHaveTilt) { mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); mTiltXScale = M_PI / 180; mTiltYScale = M_PI / 180; mOrientedRanges.haveTilt = true; mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; mOrientedRanges.tilt.source = mSource; mOrientedRanges.tilt.min = 0; mOrientedRanges.tilt.max = M_PI_2; mOrientedRanges.tilt.flat = 0; mOrientedRanges.tilt.fuzz = 0; mOrientedRanges.tilt.resolution = 0; } // Orientation mOrientationScale = 0; if (mHaveTilt) { mOrientedRanges.haveOrientation = true; mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; mOrientedRanges.orientation.source = mSource; mOrientedRanges.orientation.min = -M_PI; mOrientedRanges.orientation.max = M_PI; mOrientedRanges.orientation.flat = 0; mOrientedRanges.orientation.fuzz = 0; mOrientedRanges.orientation.resolution = 0; } else if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { if (mRawPointerAxes.orientation.valid) { if (mRawPointerAxes.orientation.maxValue > 0) { mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; } else if (mRawPointerAxes.orientation.minValue < 0) { mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; } else { mOrientationScale = 0; } } } mOrientedRanges.haveOrientation = true; mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; mOrientedRanges.orientation.source = mSource; mOrientedRanges.orientation.min = -M_PI_2; mOrientedRanges.orientation.max = M_PI_2; mOrientedRanges.orientation.flat = 0; mOrientedRanges.orientation.fuzz = 0; mOrientedRanges.orientation.resolution = 0; } // Distance mDistanceScale = 0; if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) { if (mCalibration.haveDistanceScale) { mDistanceScale = mCalibration.distanceScale; } else { mDistanceScale = 1.0f; } } mOrientedRanges.haveDistance = true; mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; mOrientedRanges.distance.source = mSource; mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; mOrientedRanges.distance.flat = 0; mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; mOrientedRanges.distance.resolution = 0; } // Compute oriented precision, scales and ranges. // Note that the maximum value reported is an inclusive maximum value so it is one // unit less than the total width or height of surface. switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: mOrientedXPrecision = mYPrecision; mOrientedYPrecision = mXPrecision; mOrientedRanges.x.min = mYTranslate; mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; mOrientedRanges.y.min = mXTranslate; mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; break; default: mOrientedXPrecision = mXPrecision; mOrientedYPrecision = mYPrecision; mOrientedRanges.x.min = mXTranslate; mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = 0; mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; mOrientedRanges.y.min = mYTranslate; mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = 0; mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; break; } // Location updateAffineTransformation(); if (mDeviceMode == DEVICE_MODE_POINTER) { // Compute pointer gesture detection parameters. float rawDiagonal = hypotf(rawWidth, rawHeight); float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display when no acceleration // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mPointerYMovementScale = mPointerXMovementScale; // Scale zooms to cover a smaller range of the display than movements do. // This value determines the area around the pointer that is affected by freeform // pointer gestures. mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mPointerYZoomScale = mPointerXZoomScale; // Max width between pointers to detect a swipe gesture is more than some fraction // of the diagonal axis of the touch pad. Touches that are wider than this are // translated into freeform gestures. mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; // Abort current pointer usages because the state has changed. abortPointerUsage(when, 0 /*policyFlags*/); } // Inform the dispatcher about the changes. *outResetNeeded = true; bumpGeneration(); } } void TouchInputMapper::dumpSurface(String8& dump) { dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, " "logicalFrame=[%d, %d, %d, %d], " "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d]\n", mViewport.displayId, mViewport.orientation, mViewport.logicalLeft, mViewport.logicalTop, mViewport.logicalRight, mViewport.logicalBottom, mViewport.physicalLeft, mViewport.physicalTop, mViewport.physicalRight, mViewport.physicalBottom, mViewport.deviceWidth, mViewport.deviceHeight); dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); } void TouchInputMapper::configureVirtualKeys() { Vector virtualKeyDefinitions; getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); mVirtualKeys.clear(); if (virtualKeyDefinitions.size() == 0) { return; } mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); int32_t touchScreenLeft = mRawPointerAxes.x.minValue; int32_t touchScreenTop = mRawPointerAxes.y.minValue; int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; mVirtualKeys.add(); VirtualKey& virtualKey = mVirtualKeys.editTop(); virtualKey.scanCode = virtualKeyDefinition.scanCode; int32_t keyCode; int32_t dummyKeyMetaState; uint32_t flags; if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, &keyCode, &dummyKeyMetaState, &flags)) { ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); mVirtualKeys.pop(); // drop the key continue; } virtualKey.keyCode = keyCode; virtualKey.flags = flags; // convert the key definition's display coordinates into touch coordinates for a hit box int32_t halfWidth = virtualKeyDefinition.width / 2; int32_t halfHeight = virtualKeyDefinition.height / 2; virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; } } void TouchInputMapper::dumpVirtualKeys(String8& dump) { if (!mVirtualKeys.isEmpty()) { dump.append(INDENT3 "Virtual Keys:\n"); for (size_t i = 0; i < mVirtualKeys.size(); i++) { const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, " "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); } } } void TouchInputMapper::parseCalibration() { const PropertyMap& in = getDevice()->getConfiguration(); Calibration& out = mCalibration; // Size out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; String8 sizeCalibrationString; if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { if (sizeCalibrationString == "none") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; } else if (sizeCalibrationString == "geometric") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; } else if (sizeCalibrationString == "diameter") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; } else if (sizeCalibrationString == "box") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; } else if (sizeCalibrationString != "default") { ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); } } out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); // Pressure out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; String8 pressureCalibrationString; if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { if (pressureCalibrationString == "none") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; } else if (pressureCalibrationString == "physical") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; } else if (pressureCalibrationString == "amplitude") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", pressureCalibrationString.string()); } } out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); // Orientation out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; String8 orientationCalibrationString; if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { if (orientationCalibrationString == "none") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; } else if (orientationCalibrationString == "interpolated") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; } else if (orientationCalibrationString == "vector") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", orientationCalibrationString.string()); } } // Distance out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; String8 distanceCalibrationString; if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { if (distanceCalibrationString == "none") { out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; } else if (distanceCalibrationString == "scaled") { out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", distanceCalibrationString.string()); } } out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; String8 coverageCalibrationString; if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { if (coverageCalibrationString == "none") { out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; } else if (coverageCalibrationString == "box") { out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; } else if (coverageCalibrationString != "default") { ALOGW("Invalid value for touch.coverage.calibration: '%s'", coverageCalibrationString.string()); } } } void TouchInputMapper::resolveCalibration() { // Size if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; } } else { mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; } // Pressure if (mRawPointerAxes.pressure.valid) { if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; } } else { mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; } // Orientation if (mRawPointerAxes.orientation.valid) { if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; } } else { mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; } // Distance if (mRawPointerAxes.distance.valid) { if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; } } else { mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; } // Coverage if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; } } void TouchInputMapper::dumpCalibration(String8& dump) { dump.append(INDENT3 "Calibration:\n"); // Size switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_NONE: dump.append(INDENT4 "touch.size.calibration: none\n"); break; case Calibration::SIZE_CALIBRATION_GEOMETRIC: dump.append(INDENT4 "touch.size.calibration: geometric\n"); break; case Calibration::SIZE_CALIBRATION_DIAMETER: dump.append(INDENT4 "touch.size.calibration: diameter\n"); break; case Calibration::SIZE_CALIBRATION_BOX: dump.append(INDENT4 "touch.size.calibration: box\n"); break; case Calibration::SIZE_CALIBRATION_AREA: dump.append(INDENT4 "touch.size.calibration: area\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.haveSizeScale) { dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); } if (mCalibration.haveSizeBias) { dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); } if (mCalibration.haveSizeIsSummed) { dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n", toString(mCalibration.sizeIsSummed)); } // Pressure switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_NONE: dump.append(INDENT4 "touch.pressure.calibration: none\n"); break; case Calibration::PRESSURE_CALIBRATION_PHYSICAL: dump.append(INDENT4 "touch.pressure.calibration: physical\n"); break; case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.havePressureScale) { dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); } // Orientation switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_NONE: dump.append(INDENT4 "touch.orientation.calibration: none\n"); break; case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: dump.append(INDENT4 "touch.orientation.calibration: vector\n"); break; default: ALOG_ASSERT(false); } // Distance switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_NONE: dump.append(INDENT4 "touch.distance.calibration: none\n"); break; case Calibration::DISTANCE_CALIBRATION_SCALED: dump.append(INDENT4 "touch.distance.calibration: scaled\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.haveDistanceScale) { dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); } switch (mCalibration.coverageCalibration) { case Calibration::COVERAGE_CALIBRATION_NONE: dump.append(INDENT4 "touch.coverage.calibration: none\n"); break; case Calibration::COVERAGE_CALIBRATION_BOX: dump.append(INDENT4 "touch.coverage.calibration: box\n"); break; default: ALOG_ASSERT(false); } } void TouchInputMapper::dumpAffineTransformation(String8& dump) { dump.append(INDENT3 "Affine Transformation:\n"); dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); } void TouchInputMapper::updateAffineTransformation() { mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), mSurfaceOrientation); } void TouchInputMapper::reset(nsecs_t when) { mCursorButtonAccumulator.reset(getDevice()); mCursorScrollAccumulator.reset(getDevice()); mTouchButtonAccumulator.reset(getDevice()); mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); mRawStatesPending.clear(); mCurrentRawState.clear(); mCurrentCookedState.clear(); mLastRawState.clear(); mLastCookedState.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; mHavePointerIds = false; mCurrentMotionAborted = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); resetExternalStylus(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->clearSpots(); } InputMapper::reset(when); } void TouchInputMapper::resetExternalStylus() { mExternalStylusState.clear(); mExternalStylusId = -1; mExternalStylusFusionTimeout = LLONG_MAX; mExternalStylusDataPending = false; } void TouchInputMapper::clearStylusDataPendingFlags() { mExternalStylusDataPending = false; mExternalStylusFusionTimeout = LLONG_MAX; } void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void TouchInputMapper::sync(nsecs_t when) { const RawState* last = mRawStatesPending.isEmpty() ? &mCurrentRawState : &mRawStatesPending.top(); // Push a new state. mRawStatesPending.push(); RawState* next = &mRawStatesPending.editTop(); next->clear(); next->when = when; // Sync button state. next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); // Sync scroll next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); // Sync touch syncTouch(when, next); // Assign pointer ids. if (!mHavePointerIds) { assignPointerIds(last, next); } #if DEBUG_RAW_EVENTS ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " "hovering ids 0x%08x -> 0x%08x", last->rawPointerData.pointerCount, next->rawPointerData.pointerCount, last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value, last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value); #endif processRawTouches(false /*timeout*/); } void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. mCurrentRawState.clear(); mRawStatesPending.clear(); return; } // Drain any pending touch states. The invariant here is that the mCurrentRawState is always // valid and must go through the full cook and dispatch cycle. This ensures that anything // touching the current state will only observe the events that have been dispatched to the // rest of the pipeline. const size_t N = mRawStatesPending.size(); size_t count; for(count = 0; count < N; count++) { const RawState& next = mRawStatesPending[count]; // A failure to assign the stylus id means that we're waiting on stylus data // and so should defer the rest of the pipeline. if (assignExternalStylusId(next, timeout)) { break; } // All ready to go. clearStylusDataPendingFlags(); mCurrentRawState.copyFrom(next); if (mCurrentRawState.when < mLastRawState.when) { mCurrentRawState.when = mLastRawState.when; } cookAndDispatch(mCurrentRawState.when); } if (count != 0) { mRawStatesPending.removeItemsAt(0, count); } if (mExternalStylusDataPending) { if (timeout) { nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; clearStylusDataPendingFlags(); mCurrentRawState.copyFrom(mLastRawState); #if DEBUG_STYLUS_FUSION ALOGD("Timeout expired, synthesizing event with new stylus data"); #endif cookAndDispatch(when); } else if (mExternalStylusFusionTimeout == LLONG_MAX) { mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); } } } void TouchInputMapper::cookAndDispatch(nsecs_t when) { // Always start with a clean state. mCurrentCookedState.clear(); // Apply stylus buttons to current raw state. applyExternalStylusButtonState(when); // Handle policy on initial down or hover events. bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && mCurrentRawState.rawPointerData.pointerCount != 0; uint32_t policyFlags = 0; bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; if (initialDown || buttonsPressed) { // If this is a touch screen, hide the pointer on an initial down. if (mDeviceMode == DEVICE_MODE_DIRECT) { getContext()->fadePointer(); } if (mParameters.wake) { policyFlags |= POLICY_FLAG_WAKE; } } // Consume raw off-screen touches before cooking pointer data. // If touches are consumed, subsequent code will not receive any pointer data. if (consumeRawTouches(when, policyFlags)) { mCurrentRawState.rawPointerData.clear(); } // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure // with cooked pointer data that has the same ids and indices as the raw data. // The following code can use either the raw or cooked data, as needed. cookPointerData(); // Apply stylus pressure to current cooked state. applyExternalStylusTouchState(when); // Synthesize key down from raw buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Dispatch the touches either directly or by translation through a pointer on screen. if (mDeviceMode == DEVICE_MODE_POINTER) { for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { mCurrentCookedState.stylusIdBits.markBit(id); } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { mCurrentCookedState.fingerIdBits.markBit(id); } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { mCurrentCookedState.mouseIdBits.markBit(id); } } for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { mCurrentCookedState.stylusIdBits.markBit(id); } } // Stylus takes precedence over all tools, then mouse, then finger. PointerUsage pointerUsage = mPointerUsage; if (!mCurrentCookedState.stylusIdBits.isEmpty()) { mCurrentCookedState.mouseIdBits.clear(); mCurrentCookedState.fingerIdBits.clear(); pointerUsage = POINTER_USAGE_STYLUS; } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { mCurrentCookedState.fingerIdBits.clear(); pointerUsage = POINTER_USAGE_MOUSE; } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || isPointerDown(mCurrentRawState.buttonState)) { pointerUsage = POINTER_USAGE_GESTURES; } dispatchPointerUsage(when, policyFlags, pointerUsage); } else { if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && mPointerController != NULL) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.touchingIdBits); } if (!mCurrentMotionAborted) { dispatchButtonRelease(when, policyFlags); dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); dispatchButtonPress(when, policyFlags); } if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { mCurrentMotionAborted = false; } } // Synthesize key up from raw buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Clear some transient state. mCurrentRawState.rawVScroll = 0; mCurrentRawState.rawHScroll = 0; // Copy current touch to last touch in preparation for the next cycle. mLastRawState.copyFrom(mCurrentRawState); mLastCookedState.copyFrom(mCurrentCookedState); } void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { mCurrentRawState.buttonState |= mExternalStylusState.buttons; } } void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { float pressure = mExternalStylusState.pressure; if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); } PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); PointerProperties& properties = currentPointerData.editPointerPropertiesWithId(mExternalStylusId); if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { properties.toolType = mExternalStylusState.toolType; } } } bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { return false; } const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && state.rawPointerData.pointerCount != 0; if (initialDown) { if (mExternalStylusState.pressure != 0.0f) { #if DEBUG_STYLUS_FUSION ALOGD("Have both stylus and touch data, beginning fusion"); #endif mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); } else if (timeout) { #if DEBUG_STYLUS_FUSION ALOGD("Timeout expired, assuming touch is not a stylus."); #endif resetExternalStylus(); } else { if (mExternalStylusFusionTimeout == LLONG_MAX) { mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; } #if DEBUG_STYLUS_FUSION ALOGD("No stylus data but stylus is connected, requesting timeout " "(%" PRId64 "ms)", mExternalStylusFusionTimeout); #endif getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); return true; } } // Check if the stylus pointer has gone up. if (mExternalStylusId != -1 && !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { #if DEBUG_STYLUS_FUSION ALOGD("Stylus pointer is going up"); #endif mExternalStylusId = -1; } return false; } void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mDeviceMode == DEVICE_MODE_POINTER) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } } else if (mDeviceMode == DEVICE_MODE_DIRECT) { if (mExternalStylusFusionTimeout < when) { processRawTouches(true /*timeout*/); } else if (mExternalStylusFusionTimeout != LLONG_MAX) { getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); } } } void TouchInputMapper::updateExternalStylusState(const StylusState& state) { mExternalStylusState.copyFrom(state); if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { // We're either in the middle of a fused stream of data or we're waiting on data before // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus // data. mExternalStylusDataPending = true; processRawTouches(false /*timeout*/); } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); } return true; } if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. return true; } } // Pointer left virtual key area or another pointer also went down. // Send key cancellation but do not consume the touch yet. // This is useful when the user swipes through from the virtual key area // into the main display surface. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED); } } if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; mCurrentVirtualKey.downTime = when; mCurrentVirtualKey.keyCode = virtualKey->keyCode; mCurrentVirtualKey.scanCode = virtualKey->scanCode; mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); } } } return true; } } // Disable all virtual key touches that happen within a short time interval of the // most recent touch within the screen area. The idea is to filter out stray // virtual key presses when interacting with the touch screen. // // Problems we're trying to solve: // // 1. While scrolling a list or dragging the window shade, the user swipes down into a // virtual key area that is implemented by a separate touch panel and accidentally // triggers a virtual key. // // 2. While typing in the on screen keyboard, the user taps slightly outside the screen // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; } void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags) { int32_t keyCode = mCurrentVirtualKey.keyCode; int32_t scanCode = mCurrentVirtualKey.scanCode; nsecs_t downTime = mCurrentVirtualKey.downTime; int32_t metaState = mContext->getGlobalMetaState(); policyFlags |= POLICY_FLAG_VIRTUAL; NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); getListener()->notifyKey(&args); } void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; if (!currentIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mCurrentMotionAborted = true; } } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } else { // There may be pointers going up and pointers going down and pointers moving // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); BitSet32 dispatchedIdBits(lastIdBits.value); // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, moveIdBits); if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } // Dispatch pointer up events. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded && !moveIdBits.isEmpty()) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.clearFirstMarkedBit(); dispatchedIdBits.markBit(downId); if (dispatchedIdBits.count() == 1) { // First pointer is going down. Set down time. mDownTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } } void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); const int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mLastCookedState.buttonState; while (!releasedButtons.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); buttonState &= ~actionButton; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); const int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mLastCookedState.buttonState; while (!pressedButtons.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); buttonState |= actionButton; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { if (!cookedPointerData.touchingIdBits.isEmpty()) { return cookedPointerData.touchingIdBits; } return cookedPointerData.hoveringIdBits; } void TouchInputMapper::cookPointerData() { uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; mCurrentCookedState.cookedPointerData.clear(); mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; mCurrentCookedState.cookedPointerData.hoveringIdBits = mCurrentRawState.rawPointerData.hoveringIdBits; mCurrentCookedState.cookedPointerData.touchingIdBits = mCurrentRawState.rawPointerData.touchingIdBits; if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { mCurrentCookedState.buttonState = 0; } else { mCurrentCookedState.buttonState = mCurrentRawState.buttonState; } // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_GEOMETRIC: case Calibration::SIZE_CALIBRATION_DIAMETER: case Calibration::SIZE_CALIBRATION_BOX: case Calibration::SIZE_CALIBRATION_AREA: if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { touchMajor = in.touchMajor; touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; toolMajor = in.toolMajor; toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.touchMajor.valid) { toolMajor = touchMajor = in.touchMajor; toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.toolMajor.valid) { touchMajor = toolMajor = in.toolMajor; touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; } else { ALOG_ASSERT(false, "No touch or tool axes. " "Size calibration should have been resolved to NONE."); touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; toolMajor /= touchingCount; toolMinor /= touchingCount; size /= touchingCount; } } if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { touchMajor *= mGeometricScale; touchMinor *= mGeometricScale; toolMajor *= mGeometricScale; toolMinor *= mGeometricScale; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; touchMinor = touchMajor; toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; toolMinor = toolMajor; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { touchMinor = touchMajor; toolMinor = toolMajor; } mCalibration.applySizeScaleAndBias(&touchMajor); mCalibration.applySizeScaleAndBias(&touchMinor); mCalibration.applySizeScaleAndBias(&toolMajor); mCalibration.applySizeScaleAndBias(&toolMinor); size *= mSizeScale; break; default: touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; break; } // Pressure float pressure; switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_PHYSICAL: case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: pressure = in.pressure * mPressureScale; break; default: pressure = in.isHovering ? 0 : 1; break; } // Tilt and Orientation float tilt; float orientation; if (mHaveTilt) { float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); } else { tilt = 0; switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: orientation = in.orientation * mOrientationScale; break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: { int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); int32_t c2 = signExtendNybble(in.orientation & 0x0f); if (c1 != 0 || c2 != 0) { orientation = atan2f(c1, c2) * 0.5f; float confidence = hypotf(c1, c2); float scale = 1.0f + confidence / 16.0f; touchMajor *= scale; touchMinor /= scale; toolMajor *= scale; toolMinor /= scale; } else { orientation = 0; } break; } default: orientation = 0; } } // Distance float distance; switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_SCALED: distance = in.distance * mDistanceScale; break; default: distance = 0; } // Coverage int32_t rawLeft, rawTop, rawRight, rawBottom; switch (mCalibration.coverageCalibration) { case Calibration::COVERAGE_CALIBRATION_BOX: rawLeft = (in.toolMinor & 0xffff0000) >> 16; rawRight = in.toolMinor & 0x0000ffff; rawBottom = in.toolMajor & 0x0000ffff; rawTop = (in.toolMajor & 0xffff0000) >> 16; break; default: rawLeft = rawTop = rawRight = rawBottom = 0; break; } // Adjust X,Y coords for device calibration // TODO: Adjust coverage coords? float xTransformed = in.x, yTransformed = in.y; mAffineTransform.applyTo(xTransformed, yTransformed); // Adjust X, Y, and coverage coords for surface orientation. float x, y; float left, top, right, bottom; switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; orientation -= M_PI_2; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; case DISPLAY_ORIENTATION_180: x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; orientation -= M_PI; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; case DISPLAY_ORIENTATION_270: x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; orientation += M_PI_2; if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) { orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; default: x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; break; } // Write output coords. PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); } else { out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); } // Write output properties. PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } } void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage) { if (pointerUsage != mPointerUsage) { abortPointerUsage(when, policyFlags); mPointerUsage = pointerUsage; } switch (mPointerUsage) { case POINTER_USAGE_GESTURES: dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); break; case POINTER_USAGE_STYLUS: dispatchPointerStylus(when, policyFlags); break; case POINTER_USAGE_MOUSE: dispatchPointerMouse(when, policyFlags); break; default: break; } } void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { switch (mPointerUsage) { case POINTER_USAGE_GESTURES: abortPointerGestures(when, policyFlags); break; case POINTER_USAGE_STYLUS: abortPointerStylus(when, policyFlags); break; case POINTER_USAGE_MOUSE: abortPointerMouse(when, policyFlags); break; default: break; } mPointerUsage = POINTER_USAGE_NONE; } void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { // Update current gesture coordinates. bool cancelPreviousGesture, finishPreviousGesture; bool sendEvents = preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout); if (!sendEvents) { return; } if (finishPreviousGesture) { cancelPreviousGesture = false; } // Update the pointer presentation and spots. if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); if (finishPreviousGesture || cancelPreviousGesture) { mPointerController->clearSpots(); } if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { mPointerController->setSpots(mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, mPointerGesture.currentGestureIdBits); } } else { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); } // Show or hide the pointer if needed. switch (mPointerGesture.currentGestureMode) { case PointerGesture::NEUTRAL: case PointerGesture::QUIET: if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH && mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) { // Remind the user of where the pointer is after finishing a gesture with spots. mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); } break; case PointerGesture::TAP: case PointerGesture::TAP_DRAG: case PointerGesture::BUTTON_CLICK_OR_DRAG: case PointerGesture::HOVER: case PointerGesture::PRESS: case PointerGesture::SWIPE: // Unfade the pointer when the current gesture manipulates the // area directly under the pointer. mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); break; case PointerGesture::FREEFORM: // Fade the pointer when the current gesture manipulates a different // area and there are spots to guide the user experience. if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } else { mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } break; } // Send events! int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG || mPointerGesture.currentGestureMode == PointerGesture::PRESS || mPointerGesture.currentGestureMode == PointerGesture::SWIPE || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; bool moveNeeded = false; if (down && !cancelPreviousGesture && !finishPreviousGesture && !mPointerGesture.lastGestureIdBits.isEmpty() && !mPointerGesture.currentGestureIdBits.isEmpty()) { BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value & mPointerGesture.lastGestureIdBits.value); moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } } // Send motion events for all pointers that went up or were canceled. BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); dispatchedGestureIdBits.clear(); } else { BitSet32 upGestureIdBits; if (finishPreviousGesture) { upGestureIdBits = dispatchedGestureIdBits; } else { upGestureIdBits.value = dispatchedGestureIdBits.value & ~mPointerGesture.currentGestureIdBits.value; } while (!upGestureIdBits.isEmpty()) { uint32_t id = upGestureIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, 0, mPointerGesture.downTime); dispatchedGestureIdBits.clearBit(id); } } } // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); } // Send motion events for all pointers that went down. if (down) { BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value & ~dispatchedGestureIdBits.value); while (!downGestureIdBits.isEmpty()) { uint32_t id = downGestureIdBits.clearFirstMarkedBit(); dispatchedGestureIdBits.markBit(id); if (dispatchedGestureIdBits.count() == 1) { mPointerGesture.downTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, 0, mPointerGesture.downTime); } } // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) { // Synthesize a hover move event after all pointers go up to indicate that // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. float x, y; mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; PointerCoords pointerCoords; pointerCoords.clear(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mViewport.displayId, 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime); getListener()->notifyMotion(&args); } // Update state. mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; if (!down) { mPointerGesture.lastGestureIdBits.clear(); } else { mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; mPointerGesture.lastGestureProperties[index].copyFrom( mPointerGesture.currentGestureProperties[index]); mPointerGesture.lastGestureCoords[index].copyFrom( mPointerGesture.currentGestureCoords[index]); mPointerGesture.lastGestureIdToIndex[id] = index; } } } void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentRawState.buttonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1, 0, 0, mPointerGesture.downTime); } // Reset the current pointer gesture. mPointerGesture.reset(); mPointerVelocityControl.reset(); // Remove any current spots. if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->clearSpots(); } } bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { *outCancelPreviousGesture = false; *outFinishPreviousGesture = false; // Handle TAP timeout. if (isTimeout) { #if DEBUG_GESTURES ALOGD("Gestures: Processing timeout"); #endif if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { // The tap/drag timeout has not yet expired. getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval); } else { // The tap is finished. #if DEBUG_GESTURES ALOGD("Gestures: TAP finished"); #endif *outFinishPreviousGesture = true; mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); return true; } } // We did not handle this timeout. return false; } const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits, positions); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning // to NEUTRAL, then we should not generate tap event. if (mPointerGesture.lastGestureMode != PointerGesture::HOVER && mPointerGesture.lastGestureMode != PointerGesture::TAP && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { mPointerGesture.resetTap(); } // Pick a new active touch id if needed. // Choose an arbitrary pointer that just went down, if there is one. // Otherwise choose an arbitrary remaining pointer. // This guarantees we always have an active touch id when there is at least one pointer. // We keep the same active touch id for as long as possible. bool activeTouchChanged = false; int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = mCurrentCookedState.fingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } } // Determine whether we are in quiet time. bool isQuietTime = false; if (activeTouchId < 0) { mPointerGesture.resetQuietTime(); } else { isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; if (!isQuietTime) { if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || mPointerGesture.lastGestureMode == PointerGesture::SWIPE || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) && currentFingerCount < 2) { // Enter quiet time when exiting swipe or freeform state. // This is to prevent accidentally entering the hover state and flinging the // pointer when finishing a swipe and there is still one pointer left onscreen. isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. isQuietTime = true; } if (isQuietTime) { mPointerGesture.quietTime = when; } } } // Switch states based on button and pointer state. if (isQuietTime) { // Case 1: Quiet time. (QUIET) #if DEBUG_GESTURES ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f); #endif if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { *outFinishPreviousGesture = true; } mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); } else if (isPointerDown(mCurrentRawState.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. // // Only the active touch matters; other fingers are ignored. This policy helps // to handle the case where the user places a second finger on the touch pad // to apply the necessary force to depress an integrated button below the surface. // We don't want the second finger to be delivered to applications. // // For this to work well, we need to make sure to track the pointer that is really // active. If the user first puts one finger down to click then adds another // finger to drag then the active pointer should switch to the finger that is // being dragged. #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " "currentFingerCount=%d", activeTouchId, currentFingerCount); #endif // Reset state when just starting. if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { *outFinishPreviousGesture = true; mPointerGesture.activeGestureId = 0; } // Switch pointers if needed. // Find the fastest pointer and follow it. if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { float speed = hypotf(vx, vy); if (speed > bestSpeed) { bestId = id; bestSpeed = speed; } } } if (bestId >= 0 && bestId != activeTouchId) { mPointerGesture.activeTouchId = activeTouchId = bestId; activeTouchChanged = true; #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); #endif } } float deltaX = 0, deltaY = 0; if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawState.rawPointerData.pointerForId(activeTouchId); deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } float x, y; mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); } else if (currentFingerCount == 0) { // Case 3. No fingers down and button is not pressed. (NEUTRAL) if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { *outFinishPreviousGesture = true; } // Watch for taps coming out of HOVER or TAP_DRAG mode. // Checking for taps after TAP_DRAG allows us to detect double-taps. bool tapped = false; if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { float x, y; mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES ALOGD("Gestures: TAP"); #endif mPointerGesture.tapUpTime = when; getContext()->requestTimeoutAtTime(when + mConfig.pointerGestureTapDragInterval); mPointerGesture.activeGestureId = 0; mPointerGesture.currentGestureMode = PointerGesture::TAP; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit( mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[ mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); tapped = true; } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, y - mPointerGesture.tapY); #endif } } else { #if DEBUG_GESTURES if (mPointerGesture.tapDownTime != LLONG_MIN) { ALOGD("Gestures: Not a TAP, %0.3fms since down", (when - mPointerGesture.tapDownTime) * 0.000001f); } else { ALOGD("Gestures: Not a TAP, incompatible mode transitions"); } #endif } } mPointerVelocityControl.reset(); if (!tapped) { #if DEBUG_GESTURES ALOGD("Gestures: NEUTRAL"); #endif mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); } } else if (currentFingerCount == 1) { // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) // The pointer follows the active touch point. // When in HOVER, emit HOVER_MOVE events at the pointer location. // When in TAP_DRAG, emit MOVE events at the pointer location. ALOG_ASSERT(activeTouchId >= 0); mPointerGesture.currentGestureMode = PointerGesture::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { float x, y; mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, y - mPointerGesture.tapY); #endif } } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", (when - mPointerGesture.tapUpTime) * 0.000001f); #endif } } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } float deltaX = 0, deltaY = 0; if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawState.rawPointerData.pointerForId(activeTouchId); deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } bool down; if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { #if DEBUG_GESTURES ALOGD("Gestures: TAP_DRAG"); #endif down = true; } else { #if DEBUG_GESTURES ALOGD("Gestures: HOVER"); #endif if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { *outFinishPreviousGesture = true; } mPointerGesture.activeGestureId = 0; down = false; } float x, y; mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); if (lastFingerCount == 0 && currentFingerCount != 0) { mPointerGesture.resetTap(); mPointerGesture.tapDownTime = when; mPointerGesture.tapX = x; mPointerGesture.tapY = y; } } else { // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) // We need to provide feedback for each finger that goes down so we cannot wait // for the fingers to move before deciding what to do. // // The ambiguous case is deciding what to do when there are two fingers down but they // have not moved enough to determine whether they are part of a drag or part of a // freeform gesture, or just a press or long-press at the pointer location. // // When there are two fingers we start with the PRESS hypothesis and we generate a // down at the pointer location. // // When the two fingers move enough or when additional fingers are added, we make // a decision to transition into SWIPE or FREEFORM mode accordingly. ALOG_ASSERT(activeTouchId >= 0); bool settled = when >= mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; } else if (!settled && currentFingerCount > lastFingerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif *outCancelPreviousGesture = true; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (*outFinishPreviousGesture || *outCancelPreviousGesture) { mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; mPointerGesture.referenceIdBits.clear(); mPointerVelocityControl.reset(); // Use the centroid and pointer location as the reference points for the gesture. #if DEBUG_GESTURES ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; if (first) { commonDeltaX = delta.dx; commonDeltaY = delta.dy; } else { commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); } } // Consider transitions from PRESS to SWIPE or MULTITOUCH. if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { float dist[MAX_POINTER_ID + 1]; int32_t distOverThreshold = 0; for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale); if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { distOverThreshold += 1; } } // Only transition when at least two pointers have moved further than // the minimum distance threshold. if (distOverThreshold >= 2) { if (currentFingerCount > 2) { // There are more than two pointers, switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. BitSet32 idBits(mCurrentCookedState.fingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); const RawPointerData::Pointer& p1 = mCurrentRawState.rawPointerData.pointerForId(id1); const RawPointerData::Pointer& p2 = mCurrentRawState.rawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, // switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", mutualDistance, mPointerGestureMaxSwipeWidth); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are two pointers. Wait for both pointers to start moving // before deciding whether this is a SWIPE or FREEFORM gesture. float dist1 = dist[id1]; float dist2 = dist[id2]; if (dist1 >= mConfig.pointerGestureMultitouchMinDistance && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { // Calculate the dot product of the displacement vectors. // When the vectors are oriented in approximately the same direction, // the angle betweeen them is near zero and the cosine of the angle // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; float dx1 = delta1.dx * mPointerXZoomScale; float dy1 = delta1.dy * mPointerYZoomScale; float dx2 = delta2.dx * mPointerXZoomScale; float dy2 = delta2.dy * mPointerYZoomScale; float dot = dx1 * dx2 + dy1 * dy2; float cosine = dot / (dist1 * dist2); // denominator always > 0 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { // Pointers are moving in the same direction. Switch to SWIPE. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to SWIPE, " "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " "cosine %0.3f >= %0.3f", dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, mConfig.pointerGestureMultitouchMinDistance, cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); #endif mPointerGesture.currentGestureMode = PointerGesture::SWIPE; } else { // Pointers are moving in different directions. Switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, " "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " "cosine %0.3f < %0.3f", dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, mConfig.pointerGestureMultitouchMinDistance, cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } } } } } } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // Switch from SWIPE to FREEFORM if additional pointers go down. // Cancel previous gesture. if (currentFingerCount > 2) { #if DEBUG_GESTURES ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } } // Move the reference points based on the overall group motion of the fingers // except in PRESS mode while waiting for a transition to occur. if (mPointerGesture.currentGestureMode != PointerGesture::PRESS && (commonDeltaX || commonDeltaY)) { for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx = 0; delta.dy = 0; } mPointerGesture.referenceTouchX += commonDeltaX; mPointerGesture.referenceTouchY += commonDeltaY; commonDeltaX *= mPointerXMovementScale; commonDeltaY *= mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; mPointerGesture.referenceGestureY += commonDeltaY; } // Report gestures. if (mPointerGesture.currentGestureMode == PointerGesture::PRESS || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // PRESS or SWIPE mode. #if DEBUG_GESTURES ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, commonDeltaX); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, commonDeltaY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { // FREEFORM mode. #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIdBits.clear(); BitSet32 mappedTouchIdBits; BitSet32 usedGestureIdBits; if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { // Initially, assign the active gesture id to the active touch point // if there is one. No other touch id bits are mapped yet. if (!*outCancelPreviousGesture) { mappedTouchIdBits.markBit(activeTouchId); usedGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = mPointerGesture.activeGestureId; } else { mPointerGesture.activeGestureId = -1; } } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value & mCurrentCookedState.fingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value & ~mCurrentCookedState.fingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { mPointerGesture.activeGestureId = -1; break; } } } #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM follow up " "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " "activeGestureId=%d", mappedTouchIdBits.value, usedGestureIdBits.value, mPointerGesture.activeGestureId); #endif BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; if (!mappedTouchIdBits.hasBit(touchId)) { gestureId = usedGestureIdBits.markFirstUnmarkedBit(); mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM " "new mapping for touch id %d -> gesture id %d", touchId, gestureId); #endif } else { gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM " "existing mapping for touch id %d -> gesture id %d", touchId, gestureId); #endif } mPointerGesture.currentGestureIdBits.markBit(gestureId); mPointerGesture.currentGestureIdToIndex[gestureId] = i; const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerGesture.currentGestureProperties[i].clear(); mPointerGesture.currentGestureProperties[i].id = gestureId; mPointerGesture.currentGestureProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[i].clear(); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); } if (mPointerGesture.activeGestureId < 0) { mPointerGesture.activeGestureId = mPointerGesture.currentGestureIdBits.firstMarkedBit(); #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM new " "activeGestureId=%d", mPointerGesture.activeGestureId); #endif } } } mPointerController->setButtonState(mCurrentRawState.buttonState); #if DEBUG_GESTURES ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " "currentGestureMode=%d, currentGestureIdBits=0x%08x, " "lastGestureMode=%d, lastGestureIdBits=0x%08x", toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " "x=%0.3f, y=%0.3f, pressure=%0.3f", id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " "x=%0.3f, y=%0.3f, pressure=%0.3f", id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } #endif return true; } void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); bool down, hovering; if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; } dispatchPointerSimple(when, policyFlags, down, hovering); } void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { abortPointerSimple(when, policyFlags); } void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); bool down, hovering; if (!mCurrentCookedState.mouseIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; float deltaX = 0, deltaY = 0; if (mLastCookedState.mouseIdBits.hasBit(id)) { uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x - mLastRawState.rawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y - mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); down = false; hovering = false; } dispatchPointerSimple(when, policyFlags, down, hovering); } void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { abortPointerSimple(when, policyFlags); mPointerVelocityControl.reset(); } void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering) { int32_t metaState = getContext()->getGlobalMetaState(); if (mPointerController != NULL) { if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } if (mPointerSimple.down && !down) { mPointerSimple.down = false; // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (mPointerSimple.hovering && !hovering) { mPointerSimple.hovering = false; // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (down) { if (!mPointerSimple.down) { mPointerSimple.down = true; mPointerSimple.downTime = when; // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (hovering) { if (!mPointerSimple.hovering) { mPointerSimple.hovering = true; // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { float vscroll = mCurrentRawState.rawVScroll; float hscroll = mCurrentRawState.rawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); // Send scroll. PointerCoords pointerCoords; pointerCoords.copyFrom(mPointerSimple.currentCoords); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Save state. if (down || hovering) { mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); } else { mPointerSimple.reset(); } } void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); dispatchPointerSimple(when, policyFlags, false, false); } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = idToIndex[id]; pointerProperties[pointerCount].copyFrom(properties[index]); pointerCoords[pointerCount].copyFrom(coords[index]); if (changedId >= 0 && id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } pointerCount += 1; } ALOG_ASSERT(pointerCount != 0); if (changedId >= 0 && pointerCount == 1) { // Replace initial down and final up action. // We can compare the action without masking off the changed pointer index // because we know the index is 0. if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { action = AMOTION_EVENT_ACTION_DOWN; } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { action = AMOTION_EVENT_ACTION_UP; } else { // Can't happen. ALOG_ASSERT(false); } } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); } bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, const uint32_t* inIdToIndex, PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const { bool changed = false; while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t inIndex = inIdToIndex[id]; uint32_t outIndex = outIdToIndex[id]; const PointerProperties& curInProperties = inProperties[inIndex]; const PointerCoords& curInCoords = inCoords[inIndex]; PointerProperties& curOutProperties = outProperties[outIndex]; PointerCoords& curOutCoords = outCoords[outIndex]; if (curInProperties != curOutProperties) { curOutProperties.copyFrom(curInProperties); changed = true; } if (curInCoords != curOutCoords) { curOutCoords.copyFrom(curInCoords); changed = true; } } return changed; } void TouchInputMapper::fadePointer() { if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } void TouchInputMapper::cancelTouch(nsecs_t when) { abortPointerUsage(when, 0 /*policyFlags*/); abortTouches(when, 0 /* policyFlags*/); } bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; } const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( int32_t x, int32_t y) { size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " "left=%d, top=%d, right=%d, bottom=%d", x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, virtualKey.hitTop, virtualKey.hitRight, virtualKey.hitBottom); #endif if (virtualKey.isHit(x, y)) { return & virtualKey; } } return NULL; } void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { uint32_t currentPointerCount = current->rawPointerData.pointerCount; uint32_t lastPointerCount = last->rawPointerData.pointerCount; current->rawPointerData.clearIdBits(); if (currentPointerCount == 0) { // No pointers to assign. return; } if (lastPointerCount == 0) { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; current->rawPointerData.pointers[i].id = id; current->rawPointerData.idToIndex[id] = i; current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 && current->rawPointerData.pointers[0].toolType == last->rawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. uint32_t id = last->rawPointerData.pointers[0].id; current->rawPointerData.pointers[0].id = id; current->rawPointerData.idToIndex[id] = 0; current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); return; } // General case. // We build a heap of squared euclidean distances between current and last pointers // associated with the current and last pointer indices. Then, we find the best // match (by distance) for each current pointer. // The pointers must have the same tool type but it is possible for them to // transition from hovering to touching or vice-versa while retaining the same id. PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; uint32_t heapSize = 0; for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; currentPointerIndex++) { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = current->rawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = last->rawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); // Insert new element into the heap (sift up). heap[heapSize].currentPointerIndex = currentPointerIndex; heap[heapSize].lastPointerIndex = lastPointerIndex; heap[heapSize].distance = distance; heapSize += 1; } } } // Heapify for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { startIndex -= 1; for (uint32_t parentIndex = startIndex; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } } #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif // Pull matches out by increasing order of distance. // To avoid reassigning pointers that have already been matched, the loop keeps track // of which last and current pointers have been matched using the matchedXXXBits variables. // It also tracks the used pointer id bits. BitSet32 matchedLastBits(0); BitSet32 matchedCurrentBits(0); BitSet32 usedIdBits(0); bool first = true; for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { while (heapSize > 0) { if (first) { // The first time through the loop, we just consume the root element of // the heap (the one with smallest distance). first = false; } else { // Previous iterations consumed the root element of the heap. // Pop root element off of the heap (sift down). heap[0] = heap[heapSize]; for (uint32_t parentIndex = 0; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif } heapSize -= 1; uint32_t currentPointerIndex = heap[0].currentPointerIndex; if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched uint32_t lastPointerIndex = heap[0].lastPointerIndex; if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; current->rawPointerData.pointers[currentPointerIndex].id = id; current->rawPointerData.idToIndex[id] = currentPointerIndex; current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", lastPointerIndex, currentPointerIndex, id, heap[0].distance); #endif break; } } // Assign fresh ids to pointers that were not matched in the process. for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); current->rawPointerData.pointers[currentPointerIndex].id = id; current->rawPointerData.idToIndex[id] = currentPointerIndex; current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", currentPointerIndex, id); #endif } } int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { return AKEY_STATE_VIRTUAL; } size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; if (virtualKey.keyCode == keyCode) { return AKEY_STATE_UP; } } return AKEY_STATE_UNKNOWN; } int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { return AKEY_STATE_VIRTUAL; } size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; if (virtualKey.scanCode == scanCode) { return AKEY_STATE_UP; } } return AKEY_STATE_UNKNOWN; } bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; for (size_t i = 0; i < numCodes; i++) { if (virtualKey.keyCode == keyCodes[i]) { outFlags[i] = 1; } } } return true; } // --- SingleTouchInputMapper --- SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { } SingleTouchInputMapper::~SingleTouchInputMapper() { } void SingleTouchInputMapper::reset(nsecs_t when) { mSingleTouchMotionAccumulator.reset(getDevice()); TouchInputMapper::reset(when); } void SingleTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mSingleTouchMotionAccumulator.process(rawEvent); } void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { if (mTouchButtonAccumulator.isToolActive()) { outState->rawPointerData.pointerCount = 1; outState->rawPointerData.idToIndex[0] = 0; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); outState->rawPointerData.markIdBit(0, isHovering); RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; outPointer.id = 0; outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); outPointer.touchMajor = 0; outPointer.touchMinor = 0; outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); outPointer.orientation = 0; outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } outPointer.isHovering = isHovering; } } void SingleTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); } bool SingleTouchInputMapper::hasStylus() const { return mTouchButtonAccumulator.hasStylus(); } // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { } MultiTouchInputMapper::~MultiTouchInputMapper() { } void MultiTouchInputMapper::reset(nsecs_t when) { mMultiTouchMotionAccumulator.reset(getDevice()); mPointerIdBits.clear(); TouchInputMapper::reset(when); } void MultiTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); } void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { const MultiTouchMotionAccumulator::Slot* inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); if (!inSlot->isInUse()) { continue; } if (outCount >= MAX_POINTERS) { #if DEBUG_POINTERS ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " "ignoring the rest.", getDeviceName().string(), MAX_POINTERS); #endif break; // too many fingers! } RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); outPointer.touchMajor = inSlot->getTouchMajor(); outPointer.touchMinor = inSlot->getTouchMinor(); outPointer.toolMajor = inSlot->getToolMajor(); outPointer.toolMinor = inSlot->getToolMinor(); outPointer.orientation = inSlot->getOrientation(); outPointer.distance = inSlot->getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } } bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. mHavePointerIds = true; int32_t trackingId = inSlot->getTrackingId(); int32_t id = -1; if (trackingId >= 0) { for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { uint32_t n = idBits.clearFirstMarkedBit(); if (mPointerTrackingIdMap[n] == trackingId) { id = n; } } if (id < 0 && !mPointerIdBits.isFull()) { id = mPointerIdBits.markFirstUnmarkedBit(); mPointerTrackingIdMap[id] = trackingId; } } if (id < 0) { mHavePointerIds = false; outState->rawPointerData.clearIdBits(); newPointerIdBits.clear(); } else { outPointer.id = id; outState->rawPointerData.idToIndex[id] = outCount; outState->rawPointerData.markIdBit(id, isHovering); newPointerIdBits.markBit(id); } outCount += 1; } outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); } void MultiTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { size_t slotCount = mRawPointerAxes.slot.maxValue + 1; if (slotCount > MAX_SLOTS) { ALOGW("MultiTouch Device %s reported %zu slots but the framework " "only supports a maximum of %zu slots at this time.", getDeviceName().string(), slotCount, MAX_SLOTS); slotCount = MAX_SLOTS; } mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); } else { mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, false /*usingSlotsProtocol*/); } } bool MultiTouchInputMapper::hasStylus() const { return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus(); } // --- ExternalStylusInputMapper ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : InputMapper(device) { } uint32_t ExternalStylusInputMapper::getSources() { return AINPUT_SOURCE_STYLUS; } void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); } void ExternalStylusInputMapper::dump(String8& dump) { dump.append(INDENT2 "External Stylus Input Mapper:\n"); dump.append(INDENT3 "Raw Stylus Axes:\n"); dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); dump.append(INDENT3 "Stylus State:\n"); dumpStylusState(dump, mStylusState); } void ExternalStylusInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); mTouchButtonAccumulator.configure(getDevice()); } void ExternalStylusInputMapper::reset(nsecs_t when) { InputDevice* device = getDevice(); mSingleTouchMotionAccumulator.reset(device); mTouchButtonAccumulator.reset(device); InputMapper::reset(when); } void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { mSingleTouchMotionAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void ExternalStylusInputMapper::sync(nsecs_t when) { mStylusState.clear(); mStylusState.when = when; mStylusState.toolType = mTouchButtonAccumulator.getToolType(); if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; } int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); if (mRawPressureAxis.valid) { mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; } else if (mTouchButtonAccumulator.isToolActive()) { mStylusState.pressure = 1.0f; } else { mStylusState.pressure = 0.0f; } mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); mContext->dispatchExternalStylusState(mStylusState); } // --- JoystickInputMapper --- JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) { } JoystickInputMapper::~JoystickInputMapper() { } uint32_t JoystickInputMapper::getSources() { return AINPUT_SOURCE_JOYSTICK; } void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); for (size_t i = 0; i < mAxes.size(); i++) { const Axis& axis = mAxes.valueAt(i); addMotionRange(axis.axisInfo.axis, axis, info); if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { addMotionRange(axis.axisInfo.highAxis, axis, info); } } } void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info) { info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); /* In order to ease the transition for developers from using the old axes * to the newer, more semantically correct axes, we'll continue to register * the old axes as duplicates of their corresponding new ones. */ int32_t compatAxis = getCompatAxis(axisId); if (compatAxis >= 0) { info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); } } /* A mapping from axes the joystick actually has to the axes that should be * artificially created for compatibility purposes. * Returns -1 if no compatibility axis is needed. */ int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { switch(axis) { case AMOTION_EVENT_AXIS_LTRIGGER: return AMOTION_EVENT_AXIS_BRAKE; case AMOTION_EVENT_AXIS_RTRIGGER: return AMOTION_EVENT_AXIS_GAS; } return -1; } void JoystickInputMapper::dump(String8& dump) { dump.append(INDENT2 "Joystick Input Mapper:\n"); dump.append(INDENT3 "Axes:\n"); size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); const char* label = getAxisLabel(axis.axisInfo.axis); if (label) { dump.appendFormat(INDENT4 "%s", label); } else { dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); } if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { label = getAxisLabel(axis.axisInfo.highAxis); if (label) { dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); } else { dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, axis.axisInfo.splitValue); } } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { dump.append(" (invert)"); } dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " "highScale=%0.5f, highOffset=%0.5f\n", axis.scale, axis.offset, axis.highScale, axis.highOffset); dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); } } void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only // Collect all axes. for (int32_t abs = 0; abs <= ABS_MAX; abs++) { if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) & INPUT_DEVICE_CLASS_JOYSTICK)) { continue; // axis must be claimed by a different device } RawAbsoluteAxisInfo rawAxisInfo; getAbsoluteAxisInfo(abs, &rawAxisInfo); if (rawAxisInfo.valid) { // Map axis. AxisInfo axisInfo; bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); if (!explicitlyMapped) { // Axis is not explicitly mapped, will choose a generic axis later. axisInfo.mode = AxisInfo::MODE_NORMAL; axisInfo.axis = -1; } // Apply flat override. int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride; // Calculate scaling factors and limits. Axis axis; if (axisInfo.mode == AxisInfo::MODE_SPLIT) { float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale, 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, rawAxisInfo.resolution * scale); } else if (isCenteredAxis(axisInfo.axis)) { float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale, offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, rawAxisInfo.resolution * scale); } else { float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale, 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, rawAxisInfo.resolution * scale); } // To eliminate noise while the joystick is at rest, filter out small variations // in axis values up front. axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f; mAxes.add(abs, axis); } } // If there are too many axes, start dropping them. // Prefer to keep explicitly mapped axes. if (mAxes.size() > PointerCoords::MAX_AXES) { ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); pruneAxes(true); pruneAxes(false); } // Assign generic axis ids to remaining axes. int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); if (axis.axisInfo.axis < 0) { while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && haveAxis(nextGenericAxisId)) { nextGenericAxisId += 1; } if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { axis.axisInfo.axis = nextGenericAxisId; nextGenericAxisId += 1; } else { ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " "have already been assigned to other axes.", getDeviceName().string(), mAxes.keyAt(i)); mAxes.removeItemsAt(i--); numAxes -= 1; } } } } } bool JoystickInputMapper::haveAxis(int32_t axisId) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); if (axis.axisInfo.axis == axisId || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) { return true; } } return false; } void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { size_t i = mAxes.size(); while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { continue; } ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", getDeviceName().string(), mAxes.keyAt(i)); mAxes.removeItemsAt(i); } } bool JoystickInputMapper::isCenteredAxis(int32_t axis) { switch (axis) { case AMOTION_EVENT_AXIS_X: case AMOTION_EVENT_AXIS_Y: case AMOTION_EVENT_AXIS_Z: case AMOTION_EVENT_AXIS_RX: case AMOTION_EVENT_AXIS_RY: case AMOTION_EVENT_AXIS_RZ: case AMOTION_EVENT_AXIS_HAT_X: case AMOTION_EVENT_AXIS_HAT_Y: case AMOTION_EVENT_AXIS_ORIENTATION: case AMOTION_EVENT_AXIS_RUDDER: case AMOTION_EVENT_AXIS_WHEEL: return true; default: return false; } } void JoystickInputMapper::reset(nsecs_t when) { // Recenter all axes. size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); axis.resetValue(); } InputMapper::reset(when); } void JoystickInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_ABS: { ssize_t index = mAxes.indexOfKey(rawEvent->code); if (index >= 0) { Axis& axis = mAxes.editValueAt(index); float newValue, highNewValue; switch (axis.axisInfo.mode) { case AxisInfo::MODE_INVERT: newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) * axis.scale + axis.offset; highNewValue = 0.0f; break; case AxisInfo::MODE_SPLIT: if (rawEvent->value < axis.axisInfo.splitValue) { newValue = (axis.axisInfo.splitValue - rawEvent->value) * axis.scale + axis.offset; highNewValue = 0.0f; } else if (rawEvent->value > axis.axisInfo.splitValue) { newValue = 0.0f; highNewValue = (rawEvent->value - axis.axisInfo.splitValue) * axis.highScale + axis.highOffset; } else { newValue = 0.0f; highNewValue = 0.0f; } break; default: newValue = rawEvent->value * axis.scale + axis.offset; highNewValue = 0.0f; break; } axis.newValue = newValue; axis.highNewValue = highNewValue; } break; } case EV_SYN: switch (rawEvent->code) { case SYN_REPORT: sync(rawEvent->when, false /*force*/); break; } break; } } void JoystickInputMapper::sync(nsecs_t when, bool force) { if (!filterAxes(force)) { return; } int32_t metaState = mContext->getGlobalMetaState(); int32_t buttonState = 0; PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; PointerCoords pointerCoords; pointerCoords.clear(); size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, axis.highCurrentValue); } } // Moving a joystick axis should not wake the device because joysticks can // be fairly noisy even when not in use. On the other hand, pushing a gamepad // button will likely wake the device. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); getListener()->notifyMotion(&args); } void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, float value) { pointerCoords->setAxisValue(axis, value); /* In order to ease the transition for developers from using the old axes * to the newer, more semantically correct axes, we'll continue to produce * values for the old axes as mirrors of the value of their corresponding * new axes. */ int32_t compatAxis = getCompatAxis(axis); if (compatAxis >= 0) { pointerCoords->setAxisValue(compatAxis, value); } } bool JoystickInputMapper::filterAxes(bool force) { bool atLeastOneSignificantChange = force; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); if (force || hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min, axis.max)) { axis.currentValue = axis.newValue; atLeastOneSignificantChange = true; } if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { if (force || hasValueChangedSignificantly(axis.filter, axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { axis.highCurrentValue = axis.highNewValue; atLeastOneSignificantChange = true; } } } return atLeastOneSignificantChange; } bool JoystickInputMapper::hasValueChangedSignificantly( float filter, float newValue, float currentValue, float min, float max) { if (newValue != currentValue) { // Filter out small changes in value unless the value is converging on the axis // bounds or center point. This is intended to reduce the amount of information // sent to applications by particularly noisy joysticks (such as PS3). if (fabs(newValue - currentValue) > filter || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { return true; } } return false; } bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( float filter, float newValue, float currentValue, float thresholdValue) { float newDistance = fabs(newValue - thresholdValue); if (newDistance < filter) { float oldDistance = fabs(currentValue - thresholdValue); if (newDistance < oldDistance) { return true; } } return false; } } // namespace android services/inputflinger/InputReader.h0100644 0000000 0000000 00000205555 13077405420 016547 0ustar000000000 0000000 /* * Copyright (C) 2010 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 _UI_INPUT_READER_H #define _UI_INPUT_READER_H #include "EventHub.h" #include "PointerControllerInterface.h" #include "InputListener.h" #include #include #include #include #include #include #include #include #include #include #include #include // Maximum supported size of a vibration pattern. // Must be at least 2. #define MAX_VIBRATE_PATTERN_SIZE 100 // Maximum allowable delay value in a vibration pattern before // which the delay will be truncated. #define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL) namespace android { class InputDevice; class InputMapper; /* * Describes how coordinates are mapped on a physical display. * See com.android.server.display.DisplayViewport. */ struct DisplayViewport { int32_t displayId; // -1 if invalid int32_t orientation; int32_t logicalLeft; int32_t logicalTop; int32_t logicalRight; int32_t logicalBottom; int32_t physicalLeft; int32_t physicalTop; int32_t physicalRight; int32_t physicalBottom; int32_t deviceWidth; int32_t deviceHeight; DisplayViewport() : displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0), logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0), physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0), deviceWidth(0), deviceHeight(0) { } bool operator==(const DisplayViewport& other) const { return displayId == other.displayId && orientation == other.orientation && logicalLeft == other.logicalLeft && logicalTop == other.logicalTop && logicalRight == other.logicalRight && logicalBottom == other.logicalBottom && physicalLeft == other.physicalLeft && physicalTop == other.physicalTop && physicalRight == other.physicalRight && physicalBottom == other.physicalBottom && deviceWidth == other.deviceWidth && deviceHeight == other.deviceHeight; } bool operator!=(const DisplayViewport& other) const { return !(*this == other); } inline bool isValid() const { return displayId >= 0; } void setNonDisplayViewport(int32_t width, int32_t height) { displayId = ADISPLAY_ID_NONE; orientation = DISPLAY_ORIENTATION_0; logicalLeft = 0; logicalTop = 0; logicalRight = width; logicalBottom = height; physicalLeft = 0; physicalTop = 0; physicalRight = width; physicalBottom = height; deviceWidth = width; deviceHeight = height; } }; /* * Input reader configuration. * * Specifies various options that modify the behavior of the input reader. */ struct InputReaderConfiguration { // Describes changes that have occurred. enum { // The pointer speed changed. CHANGE_POINTER_SPEED = 1 << 0, // The pointer gesture control changed. CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, // The display size or orientation changed. CHANGE_DISPLAY_INFO = 1 << 2, // The visible touches option changed. CHANGE_SHOW_TOUCHES = 1 << 3, // The keyboard layouts must be reloaded. CHANGE_KEYBOARD_LAYOUTS = 1 << 4, // The device name alias supplied by the may have changed for some devices. CHANGE_DEVICE_ALIAS = 1 << 5, // The location calibration matrix changed. CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6, // The presence of an external stylus has changed. CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; // Gets the amount of time to disable virtual keys after the screen is touched // in order to filter out accidental virtual key presses due to swiping gestures // or taps near the edge of the display. May be 0 to disable the feature. nsecs_t virtualKeyQuietTime; // The excluded device names for the platform. // Devices with these names will be ignored. Vector excludedDeviceNames; // Velocity control parameters for mouse pointer movements. VelocityControlParameters pointerVelocityControlParameters; // Velocity control parameters for mouse wheel movements. VelocityControlParameters wheelVelocityControlParameters; // True if pointer gestures are enabled. bool pointerGesturesEnabled; // Quiet time between certain pointer gesture transitions. // Time to allow for all fingers or buttons to settle into a stable state before // starting a new gesture. nsecs_t pointerGestureQuietInterval; // The minimum speed that a pointer must travel for us to consider switching the active // touch pointer to it during a drag. This threshold is set to avoid switching due // to noise from a finger resting on the touch pad (perhaps just pressing it down). float pointerGestureDragMinSwitchSpeed; // in pixels per second // Tap gesture delay time. // The time between down and up must be less than this to be considered a tap. nsecs_t pointerGestureTapInterval; // Tap drag gesture delay time. // The time between the previous tap's up and the next down must be less than // this to be considered a drag. Otherwise, the previous tap is finished and a // new tap begins. // // Note that the previous tap will be held down for this entire duration so this // interval must be shorter than the long press timeout. nsecs_t pointerGestureTapDragInterval; // The distance in pixels that the pointer is allowed to move from initial down // to up and still be called a tap. float pointerGestureTapSlop; // in pixels // Time after the first touch points go down to settle on an initial centroid. // This is intended to be enough time to handle cases where the user puts down two // fingers at almost but not quite exactly the same time. nsecs_t pointerGestureMultitouchSettleInterval; // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when // at least two pointers have moved at least this far from their starting place. float pointerGestureMultitouchMinDistance; // in pixels // The transition from PRESS to SWIPE gesture mode can only occur when the // cosine of the angle between the two vectors is greater than or equal to than this value // which indicates that the vectors are oriented in the same direction. // When the vectors are oriented in the exactly same direction, the cosine is 1.0. // (In exactly opposite directions, the cosine is -1.0.) float pointerGestureSwipeTransitionAngleCosine; // The transition from PRESS to SWIPE gesture mode can only occur when the // fingers are no more than this far apart relative to the diagonal size of // the touch pad. For example, a ratio of 0.5 means that the fingers must be // no more than half the diagonal size of the touch pad apart. float pointerGestureSwipeMaxWidthRatio; // The gesture movement speed factor relative to the size of the display. // Movement speed applies when the fingers are moving in the same direction. // Without acceleration, a full swipe of the touch pad diagonal in movement mode // will cover this portion of the display diagonal. float pointerGestureMovementSpeedRatio; // The gesture zoom speed factor relative to the size of the display. // Zoom speed applies when the fingers are mostly moving relative to each other // to execute a scale gesture or similar. // Without acceleration, a full swipe of the touch pad diagonal in zoom mode // will cover this portion of the display diagonal. float pointerGestureZoomSpeedRatio; // True to show the location of touches on the touch screen as spots. bool showTouches; InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), pointerGesturesEnabled(true), pointerGestureQuietInterval(100 * 1000000LL), // 100 ms pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second pointerGestureTapInterval(150 * 1000000LL), // 150 ms pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms pointerGestureTapSlop(10.0f), // 10 pixels pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms pointerGestureMultitouchMinDistance(15), // 15 pixels pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees pointerGestureSwipeMaxWidthRatio(0.25f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f), showTouches(false) { } bool getDisplayInfo(bool external, DisplayViewport* outViewport) const; void setDisplayInfo(bool external, const DisplayViewport& viewport); private: DisplayViewport mInternalDisplay; DisplayViewport mExternalDisplay; }; struct TouchAffineTransformation { float x_scale; float x_ymix; float x_offset; float y_xmix; float y_scale; float y_offset; TouchAffineTransformation() : x_scale(1.0f), x_ymix(0.0f), x_offset(0.0f), y_xmix(0.0f), y_scale(1.0f), y_offset(0.0f) { } TouchAffineTransformation(float xscale, float xymix, float xoffset, float yxmix, float yscale, float yoffset) : x_scale(xscale), x_ymix(xymix), x_offset(xoffset), y_xmix(yxmix), y_scale(yscale), y_offset(yoffset) { } void applyTo(float& x, float& y) const; }; /* * Input reader policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager * and other system components. * * The actual implementation is partially supported by callbacks into the DVM * via JNI. This interface is also mocked in the unit tests. * * These methods must NOT re-enter the input reader since they may be called while * holding the input reader lock. */ class InputReaderPolicyInterface : public virtual RefBase { protected: InputReaderPolicyInterface() { } virtual ~InputReaderPolicyInterface() { } public: /* Gets the input reader configuration. */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp obtainPointerController(int32_t deviceId) = 0; /* Notifies the input reader policy that some input devices have changed * and provides information about all current input devices. */ virtual void notifyInputDevicesChanged(const Vector& inputDevices) = 0; /* Gets the keyboard layout for a particular input device. */ virtual sp getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier) = 0; /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; /* Gets the affine calibration associated with the specified device. */ virtual TouchAffineTransformation getTouchAffineTransformation( const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0; }; /* Processes raw input events and sends cooked event data to an input listener. */ class InputReaderInterface : public virtual RefBase { protected: InputReaderInterface() { } virtual ~InputReaderInterface() { } public: /* Dumps the state of the input reader. * * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; /* Runs a single iteration of the processing loop. * Nominally reads and processes one incoming message from the EventHub. * * This method should be called on the input reader thread. */ virtual void loopOnce() = 0; /* Gets information about all input devices. * * This method may be called on any thread (usually by the input manager). */ virtual void getInputDevices(Vector& outInputDevices) = 0; /* Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) = 0; virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) = 0; virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) = 0; /* Toggle Caps Lock */ virtual void toggleCapsLockState(int32_t deviceId) = 0; /* Determine whether physical keys exist for the given framework-domain key codes. */ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; /* Requests that a reconfiguration of all input devices. * The changes flag is a bitfield that indicates what has changed and whether * the input devices must all be reopened. */ virtual void requestRefreshConfiguration(uint32_t changes) = 0; /* Controls the vibrator of a particular input device. */ virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) = 0; virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; struct StylusState { /* Time the stylus event was received. */ nsecs_t when; /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ float pressure; /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ uint32_t buttons; /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ int32_t toolType; void copyFrom(const StylusState& other) { when = other.when; pressure = other.pressure; buttons = other.buttons; toolType = other.toolType; } void clear() { when = LLONG_MAX; pressure = 0.f; buttons = 0; toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } }; /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. */ class InputReaderContext { public: InputReaderContext() { } virtual ~InputReaderContext() { } virtual void updateGlobalMetaState() = 0; virtual int32_t getGlobalMetaState() = 0; virtual void disableVirtualKeysUntil(nsecs_t time) = 0; virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; virtual void fadePointer() = 0; virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; virtual void getExternalStylusDevices(Vector& outDevices) = 0; virtual void dispatchExternalStylusState(const StylusState& outState) = 0; virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; }; /* The input reader reads raw event data from the event hub and processes it into input events * that it sends to the input listener. Some functions of the input reader, such as early * event filtering in low power states, are controlled by a separate policy object. * * The InputReader owns a collection of InputMappers. Most of the work it does happens * on the input reader thread but the InputReader can receive queries from other system * components running on arbitrary threads. To keep things manageable, the InputReader * uses a single Mutex to guard its state. The Mutex may be held while calling into the * EventHub or the InputReaderPolicy but it is never held while calling into the * InputListener. */ class InputReader : public InputReaderInterface { public: InputReader(const sp& eventHub, const sp& policy, const sp& listener); virtual ~InputReader(); virtual void dump(String8& dump); virtual void monitor(); virtual void loopOnce(); virtual void getInputDevices(Vector& outInputDevices); virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode); virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw); virtual void toggleCapsLockState(int32_t deviceId); virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void requestRefreshConfiguration(uint32_t changes); virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t deviceId, int32_t token); protected: // These members are protected so they can be instrumented by test cases. virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes); class ContextImpl : public InputReaderContext { InputReader* mReader; public: ContextImpl(InputReader* reader); virtual void updateGlobalMetaState(); virtual int32_t getGlobalMetaState(); virtual void disableVirtualKeysUntil(nsecs_t time); virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); virtual void getExternalStylusDevices(Vector& outDevices); virtual void dispatchExternalStylusState(const StylusState& outState); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); } mContext; friend class ContextImpl; private: Mutex mLock; Condition mReaderIsAliveCondition; sp mEventHub; sp mPolicy; sp mQueuedListener; InputReaderConfiguration mConfig; // The event queue. static const int EVENT_BUFFER_SIZE = 256; RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; KeyedVector mDevices; // low-level input event decoding and device management void processEventsLocked(const RawEvent* rawEvents, size_t count); void addDeviceLocked(nsecs_t when, int32_t deviceId); void removeDeviceLocked(nsecs_t when, int32_t deviceId); void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); void timeoutExpiredLocked(nsecs_t when); void handleConfigurationChangedLocked(nsecs_t when); int32_t mGlobalMetaState; void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); void notifyExternalStylusPresenceChanged(); void getExternalStylusDevicesLocked(Vector& outDevices); void dispatchExternalStylusState(const StylusState& state); void fadePointerLocked(); int32_t mGeneration; int32_t bumpGenerationLocked(); void getInputDevicesLocked(Vector& outInputDevices); nsecs_t mDisableVirtualKeysTimeout; void disableVirtualKeysUntilLocked(nsecs_t time); bool shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); nsecs_t mNextTimeout; void requestTimeoutAtTimeLocked(nsecs_t when); uint32_t mConfigurationChangesToRefresh; void refreshConfigurationLocked(uint32_t changes); // state queries typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); }; /* Reads raw events from the event hub and processes them, endlessly. */ class InputReaderThread : public Thread { public: InputReaderThread(const sp& reader); virtual ~InputReaderThread(); private: sp mReader; virtual bool threadLoop(); }; /* Represents the state of a single input device. */ class InputDevice { public: InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes); ~InputDevice(); inline InputReaderContext* getContext() { return mContext; } inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } inline int32_t getGeneration() const { return mGeneration; } inline const String8& getName() const { return mIdentifier.name; } inline const String8& getDescriptor() { return mIdentifier.descriptor; } inline uint32_t getClasses() const { return mClasses; } inline uint32_t getSources() const { return mSources; } inline bool isExternal() { return mIsExternal; } inline void setExternal(bool external) { mIsExternal = external; } inline void setMic(bool hasMic) { mHasMic = hasMic; } inline bool hasMic() const { return mHasMic; } inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); void addMapper(InputMapper* mapper); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); void updateExternalStylusState(const StylusState& state); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); void cancelTouch(nsecs_t when); int32_t getMetaState(); void updateMetaState(int32_t keyCode); void fadePointer(); void bumpGeneration(); void notifyReset(nsecs_t when); inline const PropertyMap& getConfiguration() { return mConfiguration; } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } bool hasKey(int32_t code) { return getEventHub()->hasScanCode(mId, code); } bool hasAbsoluteAxis(int32_t code) { RawAbsoluteAxisInfo info; getEventHub()->getAbsoluteAxisInfo(mId, code, &info); return info.valid; } bool isKeyPressed(int32_t code) { return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; } int32_t getAbsoluteAxisValue(int32_t code) { int32_t value; getEventHub()->getAbsoluteAxisValue(mId, code, &value); return value; } private: InputReaderContext* mContext; int32_t mId; int32_t mGeneration; int32_t mControllerNumber; InputDeviceIdentifier mIdentifier; String8 mAlias; uint32_t mClasses; Vector mMappers; uint32_t mSources; bool mIsExternal; bool mHasMic; bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); PropertyMap mConfiguration; }; /* Keeps track of the state of mouse or touch pad buttons. */ class CursorButtonAccumulator { public: CursorButtonAccumulator(); void reset(InputDevice* device); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; private: bool mBtnLeft; bool mBtnRight; bool mBtnMiddle; bool mBtnBack; bool mBtnSide; bool mBtnForward; bool mBtnExtra; bool mBtnTask; void clearButtons(); }; /* Keeps track of cursor movements. */ class CursorMotionAccumulator { public: CursorMotionAccumulator(); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); inline int32_t getRelativeX() const { return mRelX; } inline int32_t getRelativeY() const { return mRelY; } private: int32_t mRelX; int32_t mRelY; void clearRelativeAxes(); }; /* Keeps track of cursor scrolling motions. */ class CursorScrollAccumulator { public: CursorScrollAccumulator(); void configure(InputDevice* device); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); inline bool haveRelativeVWheel() const { return mHaveRelWheel; } inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } inline int32_t getRelativeX() const { return mRelX; } inline int32_t getRelativeY() const { return mRelY; } inline int32_t getRelativeVWheel() const { return mRelWheel; } inline int32_t getRelativeHWheel() const { return mRelHWheel; } private: bool mHaveRelWheel; bool mHaveRelHWheel; int32_t mRelX; int32_t mRelY; int32_t mRelWheel; int32_t mRelHWheel; void clearRelativeAxes(); }; /* Keeps track of the state of touch, stylus and tool buttons. */ class TouchButtonAccumulator { public: TouchButtonAccumulator(); void configure(InputDevice* device); void reset(InputDevice* device); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; int32_t getToolType() const; bool isToolActive() const; bool isHovering() const; bool hasStylus() const; private: bool mHaveBtnTouch; bool mHaveStylus; bool mBtnTouch; bool mBtnStylus; bool mBtnStylus2; bool mBtnToolFinger; bool mBtnToolPen; bool mBtnToolRubber; bool mBtnToolBrush; bool mBtnToolPencil; bool mBtnToolAirbrush; bool mBtnToolMouse; bool mBtnToolLens; bool mBtnToolDoubleTap; bool mBtnToolTripleTap; bool mBtnToolQuadTap; void clearButtons(); }; /* Raw axis information from the driver. */ struct RawPointerAxes { RawAbsoluteAxisInfo x; RawAbsoluteAxisInfo y; RawAbsoluteAxisInfo pressure; RawAbsoluteAxisInfo touchMajor; RawAbsoluteAxisInfo touchMinor; RawAbsoluteAxisInfo toolMajor; RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; RawAbsoluteAxisInfo distance; RawAbsoluteAxisInfo tiltX; RawAbsoluteAxisInfo tiltY; RawAbsoluteAxisInfo trackingId; RawAbsoluteAxisInfo slot; RawPointerAxes(); void clear(); }; /* Raw data for a collection of pointers including a pointer id mapping table. */ struct RawPointerData { struct Pointer { uint32_t id; int32_t x; int32_t y; int32_t pressure; int32_t touchMajor; int32_t touchMinor; int32_t toolMajor; int32_t toolMinor; int32_t orientation; int32_t distance; int32_t tiltX; int32_t tiltY; int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant bool isHovering; }; uint32_t pointerCount; Pointer pointers[MAX_POINTERS]; BitSet32 hoveringIdBits, touchingIdBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; RawPointerData(); void clear(); void copyFrom(const RawPointerData& other); void getCentroidOfTouchingPointers(float* outX, float* outY) const; inline void markIdBit(uint32_t id, bool isHovering) { if (isHovering) { hoveringIdBits.markBit(id); } else { touchingIdBits.markBit(id); } } inline void clearIdBits() { hoveringIdBits.clear(); touchingIdBits.clear(); } inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; } inline bool isHovering(uint32_t pointerIndex) { return pointers[pointerIndex].isHovering; } }; /* Cooked data for a collection of pointers including a pointer id mapping table. */ struct CookedPointerData { uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; BitSet32 hoveringIdBits, touchingIdBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; CookedPointerData(); void clear(); void copyFrom(const CookedPointerData& other); inline const PointerCoords& pointerCoordsForId(uint32_t id) const { return pointerCoords[idToIndex[id]]; } inline PointerCoords& editPointerCoordsWithId(uint32_t id) { return pointerCoords[idToIndex[id]]; } inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { return pointerProperties[idToIndex[id]]; } inline bool isHovering(uint32_t pointerIndex) const { return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); } inline bool isTouching(uint32_t pointerIndex) const { return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); } }; /* Keeps track of the state of single-touch protocol. */ class SingleTouchMotionAccumulator { public: SingleTouchMotionAccumulator(); void process(const RawEvent* rawEvent); void reset(InputDevice* device); inline int32_t getAbsoluteX() const { return mAbsX; } inline int32_t getAbsoluteY() const { return mAbsY; } inline int32_t getAbsolutePressure() const { return mAbsPressure; } inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } inline int32_t getAbsoluteDistance() const { return mAbsDistance; } inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } private: int32_t mAbsX; int32_t mAbsY; int32_t mAbsPressure; int32_t mAbsToolWidth; int32_t mAbsDistance; int32_t mAbsTiltX; int32_t mAbsTiltY; void clearAbsoluteAxes(); }; /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMTPositionX; } inline int32_t getY() const { return mAbsMTPositionY; } inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } inline int32_t getOrientation() const { return mAbsMTOrientation; } inline int32_t getTrackingId() const { return mAbsMTTrackingId; } inline int32_t getPressure() const { return mAbsMTPressure; } inline int32_t getDistance() const { return mAbsMTDistance; } inline int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse; bool mHaveAbsMTTouchMinor; bool mHaveAbsMTWidthMinor; bool mHaveAbsMTToolType; int32_t mAbsMTPositionX; int32_t mAbsMTPositionY; int32_t mAbsMTTouchMajor; int32_t mAbsMTTouchMinor; int32_t mAbsMTWidthMajor; int32_t mAbsMTWidthMinor; int32_t mAbsMTOrientation; int32_t mAbsMTTrackingId; int32_t mAbsMTPressure; int32_t mAbsMTDistance; int32_t mAbsMTToolType; Slot(); void clear(); }; MultiTouchMotionAccumulator(); ~MultiTouchMotionAccumulator(); void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlotCount; } inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } private: int32_t mCurrentSlot; Slot* mSlots; size_t mSlotCount; bool mUsingSlotsProtocol; bool mHaveStylus; void clearSlots(int32_t initialSlot); }; /* An input mapper transforms raw input events into cooked event data. * A single input device can have multiple associated input mappers in order to interpret * different classes of events. * * InputMapper lifecycle: * - create * - configure with 0 changes * - reset * - process, process, process (may occasionally reconfigure with non-zero changes or reset) * - reset * - destroy */ class InputMapper { public: InputMapper(InputDevice* device); virtual ~InputMapper(); inline InputDevice* getDevice() { return mDevice; } inline int32_t getDeviceId() { return mDevice->getId(); } inline const String8 getDeviceName() { return mDevice->getName(); } inline InputReaderContext* getContext() { return mContext; } inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } inline InputListenerInterface* getListener() { return mContext->getListener(); } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent) = 0; virtual void timeoutExpired(nsecs_t when); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual void cancelTouch(nsecs_t when); virtual int32_t getMetaState(); virtual void updateMetaState(int32_t keyCode); virtual void updateExternalStylusState(const StylusState& state); virtual void fadePointer(); protected: InputDevice* mDevice; InputReaderContext* mContext; status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); void bumpGeneration(); static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); static void dumpStylusState(String8& dump, const StylusState& state); }; class SwitchInputMapper : public InputMapper { public: SwitchInputMapper(InputDevice* device); virtual ~SwitchInputMapper(); virtual uint32_t getSources(); virtual void process(const RawEvent* rawEvent); virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); virtual void dump(String8& dump); private: uint32_t mSwitchValues; uint32_t mUpdatedSwitchMask; void processSwitch(int32_t switchCode, int32_t switchValue); void sync(nsecs_t when); }; class VibratorInputMapper : public InputMapper { public: VibratorInputMapper(InputDevice* device); virtual ~VibratorInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void process(const RawEvent* rawEvent); virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual void timeoutExpired(nsecs_t when); virtual void dump(String8& dump); private: bool mVibrating; nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; size_t mPatternSize; ssize_t mRepeat; int32_t mToken; ssize_t mIndex; nsecs_t mNextStepTime; void nextStep(); void stopVibrating(); }; class KeyboardInputMapper : public InputMapper { public: KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); virtual ~KeyboardInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual int32_t getMetaState(); virtual void updateMetaState(int32_t keyCode); private: struct KeyDown { int32_t keyCode; int32_t scanCode; }; uint32_t mSource; int32_t mKeyboardType; int32_t mOrientation; // orientation for dpad keys Vector mKeyDowns; // keys that are down int32_t mMetaState; nsecs_t mDownTime; // time of most recent key down int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none struct LedState { bool avail; // led is available bool on; // we think the led is currently on }; LedState mCapsLockLedState; LedState mNumLockLedState; LedState mScrollLockLedState; // Immutable configuration parameters. struct Parameters { bool hasAssociatedDisplay; bool orientationAware; bool handlesKeyRepeat; } mParameters; void configureParameters(); void dumpParameters(String8& dump); bool isKeyboardOrGamepadKey(int32_t scanCode); void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); bool updateMetaStateIfNeeded(int32_t keyCode, bool down); ssize_t findKeyDown(int32_t scanCode); void resetLedState(); void initializeLedState(LedState& ledState, int32_t led); void updateLedState(bool reset); void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); }; class CursorInputMapper : public InputMapper { public: CursorInputMapper(InputDevice* device); virtual ~CursorInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual void fadePointer(); private: // Amount that trackball needs to move in order to generate a key event. static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; // Immutable configuration parameters. struct Parameters { enum Mode { MODE_POINTER, MODE_NAVIGATION, }; Mode mode; bool hasAssociatedDisplay; bool orientationAware; } mParameters; CursorButtonAccumulator mCursorButtonAccumulator; CursorMotionAccumulator mCursorMotionAccumulator; CursorScrollAccumulator mCursorScrollAccumulator; int32_t mSource; float mXScale; float mYScale; float mXPrecision; float mYPrecision; float mVWheelScale; float mHWheelScale; // Velocity controls for mouse pointer and wheel movements. // The controls for X and Y wheel movements are separate to keep them decoupled. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; int32_t mOrientation; sp mPointerController; int32_t mButtonState; nsecs_t mDownTime; void configureParameters(); void dumpParameters(String8& dump); void sync(nsecs_t when); }; class RotaryEncoderInputMapper : public InputMapper { public: RotaryEncoderInputMapper(InputDevice* device); virtual ~RotaryEncoderInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); private: CursorScrollAccumulator mRotaryEncoderScrollAccumulator; int32_t mSource; float mScalingFactor; void sync(nsecs_t when); }; class TouchInputMapper : public InputMapper { public: TouchInputMapper(InputDevice* device); virtual ~TouchInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void fadePointer(); virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); virtual void updateExternalStylusState(const StylusState& state); protected: CursorButtonAccumulator mCursorButtonAccumulator; CursorScrollAccumulator mCursorScrollAccumulator; TouchButtonAccumulator mTouchButtonAccumulator; struct VirtualKey { int32_t keyCode; int32_t scanCode; uint32_t flags; // computed hit box, specified in touch screen coords based on known display size int32_t hitLeft; int32_t hitTop; int32_t hitRight; int32_t hitBottom; inline bool isHit(int32_t x, int32_t y) const { return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; } }; // Input sources and device mode. uint32_t mSource; enum DeviceMode { DEVICE_MODE_DISABLED, // input is disabled DEVICE_MODE_DIRECT, // direct mapping (touchscreen) DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) DEVICE_MODE_POINTER, // pointer mapping (pointer) }; DeviceMode mDeviceMode; // The reader's configuration. InputReaderConfiguration mConfig; // Immutable configuration parameters. struct Parameters { enum DeviceType { DEVICE_TYPE_TOUCH_SCREEN, DEVICE_TYPE_TOUCH_PAD, DEVICE_TYPE_TOUCH_NAVIGATION, DEVICE_TYPE_POINTER, }; DeviceType deviceType; bool hasAssociatedDisplay; bool associatedDisplayIsExternal; bool orientationAware; bool hasButtonUnderPad; enum GestureMode { GESTURE_MODE_SINGLE_TOUCH, GESTURE_MODE_MULTI_TOUCH, }; GestureMode gestureMode; bool wake; } mParameters; // Immutable calibration parameters in parsed form. struct Calibration { // Size enum SizeCalibration { SIZE_CALIBRATION_DEFAULT, SIZE_CALIBRATION_NONE, SIZE_CALIBRATION_GEOMETRIC, SIZE_CALIBRATION_DIAMETER, SIZE_CALIBRATION_BOX, SIZE_CALIBRATION_AREA, }; SizeCalibration sizeCalibration; bool haveSizeScale; float sizeScale; bool haveSizeBias; float sizeBias; bool haveSizeIsSummed; bool sizeIsSummed; // Pressure enum PressureCalibration { PRESSURE_CALIBRATION_DEFAULT, PRESSURE_CALIBRATION_NONE, PRESSURE_CALIBRATION_PHYSICAL, PRESSURE_CALIBRATION_AMPLITUDE, }; PressureCalibration pressureCalibration; bool havePressureScale; float pressureScale; // Orientation enum OrientationCalibration { ORIENTATION_CALIBRATION_DEFAULT, ORIENTATION_CALIBRATION_NONE, ORIENTATION_CALIBRATION_INTERPOLATED, ORIENTATION_CALIBRATION_VECTOR, }; OrientationCalibration orientationCalibration; // Distance enum DistanceCalibration { DISTANCE_CALIBRATION_DEFAULT, DISTANCE_CALIBRATION_NONE, DISTANCE_CALIBRATION_SCALED, }; DistanceCalibration distanceCalibration; bool haveDistanceScale; float distanceScale; enum CoverageCalibration { COVERAGE_CALIBRATION_DEFAULT, COVERAGE_CALIBRATION_NONE, COVERAGE_CALIBRATION_BOX, }; CoverageCalibration coverageCalibration; inline void applySizeScaleAndBias(float* outSize) const { if (haveSizeScale) { *outSize *= sizeScale; } if (haveSizeBias) { *outSize += sizeBias; } if (*outSize < 0) { *outSize = 0; } } } mCalibration; // Affine location transformation/calibration struct TouchAffineTransformation mAffineTransform; RawPointerAxes mRawPointerAxes; struct RawState { nsecs_t when; // Raw pointer sample data. RawPointerData rawPointerData; int32_t buttonState; // Scroll state. int32_t rawVScroll; int32_t rawHScroll; void copyFrom(const RawState& other) { when = other.when; rawPointerData.copyFrom(other.rawPointerData); buttonState = other.buttonState; rawVScroll = other.rawVScroll; rawHScroll = other.rawHScroll; } void clear() { when = 0; rawPointerData.clear(); buttonState = 0; rawVScroll = 0; rawHScroll = 0; } }; struct CookedState { // Cooked pointer sample data. CookedPointerData cookedPointerData; // Id bits used to differentiate fingers, stylus and mouse tools. BitSet32 fingerIdBits; BitSet32 stylusIdBits; BitSet32 mouseIdBits; int32_t buttonState; void copyFrom(const CookedState& other) { cookedPointerData.copyFrom(other.cookedPointerData); fingerIdBits = other.fingerIdBits; stylusIdBits = other.stylusIdBits; mouseIdBits = other.mouseIdBits; buttonState = other.buttonState; } void clear() { cookedPointerData.clear(); fingerIdBits.clear(); stylusIdBits.clear(); mouseIdBits.clear(); buttonState = 0; } }; Vector mRawStatesPending; RawState mCurrentRawState; CookedState mCurrentCookedState; RawState mLastRawState; CookedState mLastCookedState; // State provided by an external stylus StylusState mExternalStylusState; int64_t mExternalStylusId; nsecs_t mExternalStylusFusionTimeout; bool mExternalStylusDataPending; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; // Have we assigned pointer IDs for this stream bool mHavePointerIds; // Is the current stream of direct touch events aborted bool mCurrentMotionAborted; // The time the primary pointer last went down. nsecs_t mDownTime; // The pointer controller, or null if the device is not a pointer. sp mPointerController; Vector mVirtualKeys; virtual void configureParameters(); virtual void dumpParameters(String8& dump); virtual void configureRawPointerAxes(); virtual void dumpRawPointerAxes(String8& dump); virtual void configureSurface(nsecs_t when, bool* outResetNeeded); virtual void dumpSurface(String8& dump); virtual void configureVirtualKeys(); virtual void dumpVirtualKeys(String8& dump); virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); virtual void updateAffineTransformation(); virtual void dumpAffineTransformation(String8& dump); virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; virtual bool hasExternalStylus() const; virtual void syncTouch(nsecs_t when, RawState* outState) = 0; private: // The current viewport. // The components of the viewport are specified in the display's rotated orientation. DisplayViewport mViewport; // The surface orientation, width and height set by configureSurface(). // The width and height are derived from the viewport but are specified // in the natural orientation. // The surface origin specifies how the surface coordinates should be translated // to align with the logical display coordinate space. // The orientation may be different from the viewport orientation as it specifies // the rotation of the surface coordinates required to produce the viewport's // requested orientation, so it will depend on whether the device is orientation aware. int32_t mSurfaceWidth; int32_t mSurfaceHeight; int32_t mSurfaceLeft; int32_t mSurfaceTop; int32_t mSurfaceOrientation; // Translation and scaling factors, orientation-independent. float mXTranslate; float mXScale; float mXPrecision; float mYTranslate; float mYScale; float mYPrecision; float mGeometricScale; float mPressureScale; float mSizeScale; float mOrientationScale; float mDistanceScale; bool mHaveTilt; float mTiltXCenter; float mTiltXScale; float mTiltYCenter; float mTiltYScale; bool mExternalStylusConnected; // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; InputDeviceInfo::MotionRange y; InputDeviceInfo::MotionRange pressure; bool haveSize; InputDeviceInfo::MotionRange size; bool haveTouchSize; InputDeviceInfo::MotionRange touchMajor; InputDeviceInfo::MotionRange touchMinor; bool haveToolSize; InputDeviceInfo::MotionRange toolMajor; InputDeviceInfo::MotionRange toolMinor; bool haveOrientation; InputDeviceInfo::MotionRange orientation; bool haveDistance; InputDeviceInfo::MotionRange distance; bool haveTilt; InputDeviceInfo::MotionRange tilt; OrientedRanges() { clear(); } void clear() { haveSize = false; haveTouchSize = false; haveToolSize = false; haveOrientation = false; haveDistance = false; haveTilt = false; } } mOrientedRanges; // Oriented dimensions and precision. float mOrientedXPrecision; float mOrientedYPrecision; struct CurrentVirtualKeyState { bool down; bool ignored; nsecs_t downTime; int32_t keyCode; int32_t scanCode; } mCurrentVirtualKey; // Scale factor for gesture or mouse based pointer movements. float mPointerXMovementScale; float mPointerYMovementScale; // Scale factor for gesture based zooming and other freeform motions. float mPointerXZoomScale; float mPointerYZoomScale; // The maximum swipe width. float mPointerGestureMaxSwipeWidth; struct PointerDistanceHeapElement { uint32_t currentPointerIndex : 8; uint32_t lastPointerIndex : 8; uint64_t distance : 48; // squared distance }; enum PointerUsage { POINTER_USAGE_NONE, POINTER_USAGE_GESTURES, POINTER_USAGE_STYLUS, POINTER_USAGE_MOUSE, }; PointerUsage mPointerUsage; struct PointerGesture { enum Mode { // No fingers, button is not pressed. // Nothing happening. NEUTRAL, // No fingers, button is not pressed. // Tap detected. // Emits DOWN and UP events at the pointer location. TAP, // Exactly one finger dragging following a tap. // Pointer follows the active finger. // Emits DOWN, MOVE and UP events at the pointer location. // // Detect double-taps when the finger goes up while in TAP_DRAG mode. TAP_DRAG, // Button is pressed. // Pointer follows the active finger if there is one. Other fingers are ignored. // Emits DOWN, MOVE and UP events at the pointer location. BUTTON_CLICK_OR_DRAG, // Exactly one finger, button is not pressed. // Pointer follows the active finger. // Emits HOVER_MOVE events at the pointer location. // // Detect taps when the finger goes up while in HOVER mode. HOVER, // Exactly two fingers but neither have moved enough to clearly indicate // whether a swipe or freeform gesture was intended. We consider the // pointer to be pressed so this enables clicking or long-pressing on buttons. // Pointer does not move. // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. PRESS, // Exactly two fingers moving in the same direction, button is not pressed. // Pointer does not move. // Emits DOWN, MOVE and UP events with a single pointer coordinate that // follows the midpoint between both fingers. SWIPE, // Two or more fingers moving in arbitrary directions, button is not pressed. // Pointer does not move. // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow // each finger individually relative to the initial centroid of the finger. FREEFORM, // Waiting for quiet time to end before starting the next gesture. QUIET, }; // Time the first finger went down. nsecs_t firstTouchTime; // The active pointer id from the raw touch data. int32_t activeTouchId; // -1 if none // The active pointer id from the gesture last delivered to the application. int32_t activeGestureId; // -1 if none // Pointer coords and ids for the current and previous pointer gesture. Mode currentGestureMode; BitSet32 currentGestureIdBits; uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; PointerProperties currentGestureProperties[MAX_POINTERS]; PointerCoords currentGestureCoords[MAX_POINTERS]; Mode lastGestureMode; BitSet32 lastGestureIdBits; uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; PointerProperties lastGestureProperties[MAX_POINTERS]; PointerCoords lastGestureCoords[MAX_POINTERS]; // Time the pointer gesture last went down. nsecs_t downTime; // Time when the pointer went down for a TAP. nsecs_t tapDownTime; // Time when the pointer went up for a TAP. nsecs_t tapUpTime; // Location of initial tap. float tapX, tapY; // Time we started waiting for quiescence. nsecs_t quietTime; // Reference points for multitouch gestures. float referenceTouchX; // reference touch X/Y coordinates in surface units float referenceTouchY; float referenceGestureX; // reference gesture X/Y coordinates in pixels float referenceGestureY; // Distance that each pointer has traveled which has not yet been // subsumed into the reference gesture position. BitSet32 referenceIdBits; struct Delta { float dx, dy; }; Delta referenceDeltas[MAX_POINTER_ID + 1]; // Describes how touch ids are mapped to gesture ids for freeform gestures. uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; activeGestureId = -1; currentGestureMode = NEUTRAL; currentGestureIdBits.clear(); lastGestureMode = NEUTRAL; lastGestureIdBits.clear(); downTime = 0; velocityTracker.clear(); resetTap(); resetQuietTime(); } void resetTap() { tapDownTime = LLONG_MIN; tapUpTime = LLONG_MIN; } void resetQuietTime() { quietTime = LLONG_MIN; } } mPointerGesture; struct PointerSimple { PointerCoords currentCoords; PointerProperties currentProperties; PointerCoords lastCoords; PointerProperties lastProperties; // True if the pointer is down. bool down; // True if the pointer is hovering. bool hovering; // Time the pointer last went down. nsecs_t downTime; void reset() { currentCoords.clear(); currentProperties.clear(); lastCoords.clear(); lastProperties.clear(); down = false; hovering = false; downTime = 0; } } mPointerSimple; // The pointer and scroll velocity controls. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; void resetExternalStylus(); void clearStylusDataPendingFlags(); void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); void processRawTouches(bool timeout); void cookAndDispatch(nsecs_t when); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); void cookPointerData(); void abortTouches(nsecs_t when, uint32_t policyFlags); void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); void abortPointerUsage(nsecs_t when, uint32_t policyFlags); void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); void abortPointerGestures(nsecs_t when, uint32_t policyFlags); bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout); void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); void abortPointerStylus(nsecs_t when, uint32_t policyFlags); void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); void abortPointerMouse(nsecs_t when, uint32_t policyFlags); void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); bool assignExternalStylusId(const RawState& state, bool timeout); void applyExternalStylusButtonState(nsecs_t when); void applyExternalStylusTouchState(nsecs_t when); // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP // it is the first / last pointer to go down / up. void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); // Updates pointer coords and properties for pointers with specified ids that have moved. // Returns true if any of them changed. bool updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, const uint32_t* inIdToIndex, PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const; bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); static void assignPointerIds(const RawState* last, RawState* current); }; class SingleTouchInputMapper : public TouchInputMapper { public: SingleTouchInputMapper(InputDevice* device); virtual ~SingleTouchInputMapper(); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; private: SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; }; class MultiTouchInputMapper : public TouchInputMapper { public: MultiTouchInputMapper(InputDevice* device); virtual ~MultiTouchInputMapper(); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; private: MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; // Specifies the pointer id bits that are in use, and their associated tracking id. BitSet32 mPointerIdBits; int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; }; class ExternalStylusInputMapper : public InputMapper { public: ExternalStylusInputMapper(InputDevice* device); virtual ~ExternalStylusInputMapper() = default; virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual void sync(nsecs_t when); private: SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; RawAbsoluteAxisInfo mRawPressureAxis; TouchButtonAccumulator mTouchButtonAccumulator; StylusState mStylusState; }; class JoystickInputMapper : public InputMapper { public: JoystickInputMapper(InputDevice* device); virtual ~JoystickInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); private: struct Axis { RawAbsoluteAxisInfo rawAxisInfo; AxisInfo axisInfo; bool explicitlyMapped; // true if the axis was explicitly assigned an axis id float scale; // scale factor from raw to normalized values float offset; // offset to add after scaling for normalization float highScale; // scale factor from raw to normalized values of high split float highOffset; // offset to add after scaling for normalization of high split float min; // normalized inclusive minimum float max; // normalized inclusive maximum float flat; // normalized flat region size float fuzz; // normalized error tolerance float resolution; // normalized resolution in units/mm float filter; // filter out small variations of this size float currentValue; // current value float newValue; // most recent value float highCurrentValue; // current value of high split float highNewValue; // most recent value of high split void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, bool explicitlyMapped, float scale, float offset, float highScale, float highOffset, float min, float max, float flat, float fuzz, float resolution) { this->rawAxisInfo = rawAxisInfo; this->axisInfo = axisInfo; this->explicitlyMapped = explicitlyMapped; this->scale = scale; this->offset = offset; this->highScale = highScale; this->highOffset = highOffset; this->min = min; this->max = max; this->flat = flat; this->fuzz = fuzz; this->resolution = resolution; this->filter = 0; resetValue(); } void resetValue() { this->currentValue = 0; this->newValue = 0; this->highCurrentValue = 0; this->highNewValue = 0; } }; // Axes indexed by raw ABS_* axis index. KeyedVector mAxes; void sync(nsecs_t when, bool force); bool haveAxis(int32_t axisId); void pruneAxes(bool ignoreExplicitlyMappedAxes); bool filterAxes(bool force); static bool hasValueChangedSignificantly(float filter, float newValue, float currentValue, float min, float max); static bool hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, float currentValue, float thresholdValue); static bool isCenteredAxis(int32_t axis); static int32_t getCompatAxis(int32_t axis); static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, float value); }; } // namespace android #endif // _UI_INPUT_READER_H services/inputflinger/InputWindow.cpp0100644 0000000 0000000 00000004512 13077405420 017135 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "InputWindow" #define LOG_NDEBUG 0 #include "InputWindow.h" #include #include #include namespace android { // --- InputWindowInfo --- void InputWindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { return touchableRegion.contains(x,y); } bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; } bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR || layoutParamsType == TYPE_NAVIGATION_BAR || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY || layoutParamsType == TYPE_DOCK_DIVIDER; } bool InputWindowInfo::supportsSplitTouch() const { return layoutParamsFlags & FLAG_SPLIT_TOUCH; } bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; } // --- InputWindowHandle --- InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : inputApplicationHandle(inputApplicationHandle), mInfo(NULL) { } InputWindowHandle::~InputWindowHandle() { delete mInfo; } void InputWindowHandle::releaseInfo() { if (mInfo) { delete mInfo; mInfo = NULL; } } } // namespace android services/inputflinger/InputWindow.h0100644 0000000 0000000 00000016003 13077405420 016600 0ustar000000000 0000000 /* * 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 _UI_INPUT_WINDOW_H #define _UI_INPUT_WINDOW_H #include #include #include #include #include #include #include #include "InputApplication.h" namespace android { /* * Describes the properties of a window that can receive input. */ struct InputWindowInfo { // Window flags from WindowManager.LayoutParams enum { FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, FLAG_DIM_BEHIND = 0x00000002, FLAG_BLUR_BEHIND = 0x00000004, FLAG_NOT_FOCUSABLE = 0x00000008, FLAG_NOT_TOUCHABLE = 0x00000010, FLAG_NOT_TOUCH_MODAL = 0x00000020, FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, FLAG_KEEP_SCREEN_ON = 0x00000080, FLAG_LAYOUT_IN_SCREEN = 0x00000100, FLAG_LAYOUT_NO_LIMITS = 0x00000200, FLAG_FULLSCREEN = 0x00000400, FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, FLAG_DITHER = 0x00001000, FLAG_SECURE = 0x00002000, FLAG_SCALED = 0x00004000, FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, FLAG_LAYOUT_INSET_DECOR = 0x00010000, FLAG_ALT_FOCUSABLE_IM = 0x00020000, FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, FLAG_SHOW_WHEN_LOCKED = 0x00080000, FLAG_SHOW_WALLPAPER = 0x00100000, FLAG_TURN_SCREEN_ON = 0x00200000, FLAG_DISMISS_KEYGUARD = 0x00400000, FLAG_SPLIT_TOUCH = 0x00800000, FLAG_SLIPPERY = 0x20000000, FLAG_NEEDS_MENU_KEY = 0x40000000, }; // Window types from WindowManager.LayoutParams enum { FIRST_APPLICATION_WINDOW = 1, TYPE_BASE_APPLICATION = 1, TYPE_APPLICATION = 2, TYPE_APPLICATION_STARTING = 3, LAST_APPLICATION_WINDOW = 99, FIRST_SUB_WINDOW = 1000, TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, LAST_SUB_WINDOW = 1999, FIRST_SYSTEM_WINDOW = 2000, TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+22, TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34, LAST_SYSTEM_WINDOW = 2999, }; enum { INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001, INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, }; sp inputChannel; String8 name; int32_t layoutParamsFlags; int32_t layoutParamsType; nsecs_t dispatchingTimeout; int32_t frameLeft; int32_t frameTop; int32_t frameRight; int32_t frameBottom; float scaleFactor; Region touchableRegion; bool visible; bool canReceiveKeys; bool hasFocus; bool hasWallpaper; bool paused; int32_t layer; int32_t ownerPid; int32_t ownerUid; int32_t inputFeatures; int32_t displayId; void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; bool frameContainsPoint(int32_t x, int32_t y) const; /* Returns true if the window is of a trusted type that is allowed to silently * overlay other windows for the purpose of implementing the secure views feature. * Trusted overlays, such as IME windows, can partly obscure other windows without causing * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ bool isTrustedOverlay() const; bool supportsSplitTouch() const; bool overlaps(const InputWindowInfo* other) const; }; /* * Handle for a window that can receive input. * * Used by the native input dispatcher to indirectly refer to the window manager objects * that describe a window. */ class InputWindowHandle : public RefBase { public: const sp inputApplicationHandle; inline const InputWindowInfo* getInfo() const { return mInfo; } inline sp getInputChannel() const { return mInfo ? mInfo->inputChannel : NULL; } inline String8 getName() const { return mInfo ? mInfo->name : String8(""); } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { return mInfo ? mInfo->dispatchingTimeout : defaultValue; } /** * Requests that the state of this object be updated to reflect * the most current available information about the application. * * This method should only be called from within the input dispatcher's * critical section. * * Returns true on success, or false if the handle is no longer valid. */ virtual bool updateInfo() = 0; /** * Releases the storage used by the associated information when it is * no longer needed. */ void releaseInfo(); protected: InputWindowHandle(const sp& inputApplicationHandle); virtual ~InputWindowHandle(); InputWindowInfo* mInfo; }; } // namespace android #endif // _UI_INPUT_WINDOW_H services/inputflinger/PointerControllerInterface.h0100644 0000000 0000000 00000007150 13077405420 021621 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H #define _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H #include #include #include namespace android { /** * Interface for tracking a mouse / touch pad pointer and touch pad spots. * * The spots are sprites on screen that visually represent the positions of * fingers * * The pointer controller is responsible for providing synchronization and for tracking * display orientation changes if needed. */ class PointerControllerInterface : public virtual RefBase { protected: PointerControllerInterface() { } virtual ~PointerControllerInterface() { } public: /* Gets the bounds of the region that the pointer can traverse. * Returns true if the bounds are available. */ virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const = 0; /* Move the pointer. */ virtual void move(float deltaX, float deltaY) = 0; /* Sets a mask that indicates which buttons are pressed. */ virtual void setButtonState(int32_t buttonState) = 0; /* Gets a mask that indicates which buttons are pressed. */ virtual int32_t getButtonState() const = 0; /* Sets the absolute location of the pointer. */ virtual void setPosition(float x, float y) = 0; /* Gets the absolute location of the pointer. */ virtual void getPosition(float* outX, float* outY) const = 0; enum Transition { // Fade/unfade immediately. TRANSITION_IMMEDIATE, // Fade/unfade gradually. TRANSITION_GRADUAL, }; /* Fades the pointer out now. */ virtual void fade(Transition transition) = 0; /* Makes the pointer visible if it has faded out. * The pointer never unfades itself automatically. This method must be called * by the client whenever the pointer is moved or a button is pressed and it * wants to ensure that the pointer becomes visible again. */ virtual void unfade(Transition transition) = 0; enum Presentation { // Show the mouse pointer. PRESENTATION_POINTER, // Show spots and a spot anchor in place of the mouse pointer. PRESENTATION_SPOT, }; /* Sets the mode of the pointer controller. */ virtual void setPresentation(Presentation presentation) = 0; /* Sets the spots for the current gesture. * The spots are not subject to the inactivity timeout like the pointer * itself it since they are expected to remain visible for so long as * the fingers are on the touch pad. * * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. * For spotCoords, pressure != 0 indicates that the spot's location is being * pressed (not hovering). */ virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) = 0; /* Removes all spots. */ virtual void clearSpots() = 0; }; } // namespace android #endif // _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H services/inputflinger/host/0040755 0000000 0000000 00000000000 13077405420 015120 5ustar000000000 0000000 services/inputflinger/host/Android.mk0100644 0000000 0000000 00000002732 13077405420 017032 0ustar000000000 0000000 # Copyright (C) 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_SRC_FILES:= \ InputFlinger.cpp \ InputDriver.cpp \ InputHost.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ libcrypto \ libcutils \ libinput \ liblog \ libutils \ libhardware # TODO: Move inputflinger to its own process and mark it hidden #LOCAL_CFLAGS += -fvisibility=hidden LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) LOCAL_MODULE := libinputflingerhost include $(BUILD_SHARED_LIBRARY) ######################################################################## # build input flinger executable include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_SRC_FILES:= \ main.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ libinputflingerhost \ libutils LOCAL_MODULE := inputflinger LOCAL_INIT_RC := inputflinger.rc include $(BUILD_EXECUTABLE) services/inputflinger/host/InputDriver.cpp0100644 0000000 0000000 00000033672 13077405420 020107 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #define LOG_TAG "InputDriver" #define LOG_NDEBUG 0 #include "InputDriver.h" #include "InputHost.h" #include #include #include #include #include #define INDENT2 " " struct input_property_map { android::PropertyMap* propertyMap; }; struct input_property { android::String8 key; android::String8 value; }; struct input_device_identifier { const char* name; const char* uniqueId; input_bus_t bus; int32_t vendorId; int32_t productId; int32_t version; }; struct input_device_definition { std::vector reportDefs; }; struct input_device_handle { input_device_identifier_t* id; input_device_definition_t* def; }; struct input_int_usage { input_usage_t usage; int32_t min; int32_t max; float resolution; }; struct input_collection { int32_t arity; std::vector intUsages; std::vector boolUsages; }; struct InputCollectionIdHasher { std::size_t operator()(const input_collection_id& id) const { return std::hash()(static_cast(id)); } }; struct input_report_definition { std::unordered_map collections; }; namespace android { static input_host_callbacks_t kCallbacks = { .create_device_identifier = create_device_identifier, .create_device_definition = create_device_definition, .create_input_report_definition = create_input_report_definition, .create_output_report_definition = create_output_report_definition, .free_report_definition = free_report_definition, .input_device_definition_add_report = input_device_definition_add_report, .input_report_definition_add_collection = input_report_definition_add_collection, .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int, .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool, .register_device = register_device, .input_allocate_report = input_allocate_report, .input_report_set_usage_int = input_report_set_usage_int, .input_report_set_usage_bool = input_report_set_usage_bool, .report_event = report_event, .input_get_device_property_map = input_get_device_property_map, .input_get_device_property = input_get_device_property, .input_get_property_key = input_get_property_key, .input_get_property_value = input_get_property_value, .input_free_device_property = input_free_device_property, .input_free_device_property_map = input_free_device_property_map, }; InputDriver::InputDriver(const char* name) : mName(String8(name)) { const hw_module_t* module; int err = input_open(&module, name); LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name); mHal = reinterpret_cast(module); } void InputDriver::init() { mHal->init(mHal, static_cast(this), kCallbacks); } input_device_identifier_t* InputDriver::createDeviceIdentifier( const char* name, int32_t productId, int32_t vendorId, input_bus_t bus, const char* uniqueId) { auto identifier = new ::input_device_identifier { .name = name, .productId = productId, .vendorId = vendorId, .bus = bus, .uniqueId = uniqueId, }; // TODO: store this identifier somewhere return identifier; } input_device_definition_t* InputDriver::createDeviceDefinition() { return new ::input_device_definition; } input_report_definition_t* InputDriver::createInputReportDefinition() { return new ::input_report_definition; } input_report_definition_t* InputDriver::createOutputReportDefinition() { return new ::input_report_definition; } void InputDriver::freeReportDefinition(input_report_definition_t* reportDef) { delete reportDef; } void InputDriver::inputDeviceDefinitionAddReport(input_device_definition_t* d, input_report_definition_t* r) { d->reportDefs.push_back(r); } void InputDriver::inputReportDefinitionAddCollection(input_report_definition_t* report, input_collection_id_t id, int32_t arity) { report->collections[id] = {.arity = arity}; } void InputDriver::inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, float resolution) { if (report->collections.find(id) != report->collections.end()) { report->collections[id].intUsages.push_back({ .usage = usage, .min = min, .max = max, .resolution = resolution}); } } void InputDriver::inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, input_collection_id_t id, input_usage_t* usage, size_t usageCount) { if (report->collections.find(id) != report->collections.end()) { for (size_t i = 0; i < usageCount; ++i) { report->collections[id].boolUsages.push_back(usage[i]); } } } input_device_handle_t* InputDriver::registerDevice(input_device_identifier_t* id, input_device_definition_t* d) { ALOGD("Registering device %s with %zu input reports", id->name, d->reportDefs.size()); // TODO: save this device handle return new input_device_handle{ .id = id, .def = d }; } void InputDriver::unregisterDevice(input_device_handle_t* handle) { delete handle; } input_report_t* InputDriver::inputAllocateReport(input_report_definition_t* r) { ALOGD("Allocating input report for definition %p", r); return nullptr; } void InputDriver::inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { } void InputDriver::inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { } void InputDriver::reportEvent(input_device_handle_t* d, input_report_t* report) { ALOGD("report_event %p for handle %p", report, d); } input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identifier_t* id) { InputDeviceIdentifier idi; idi.name = id->name; idi.uniqueId = id->uniqueId; idi.bus = id->bus; idi.vendor = id->vendorId; idi.product = id->productId; idi.version = id->version; String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (configFile.isEmpty()) { ALOGD("No input device configuration file found for device '%s'.", idi.name.string()); } else { auto propMap = new input_property_map_t(); status_t status = PropertyMap::load(configFile, &propMap->propertyMap); if (status) { ALOGE("Error loading input device configuration file for device '%s'. " "Using default configuration.", idi.name.string()); delete propMap; return nullptr; } return propMap; } return nullptr; } input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { String8 keyString(key); if (map != nullptr) { if (map->propertyMap->hasProperty(keyString)) { auto prop = new input_property_t(); if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { delete prop; return nullptr; } prop->key = keyString; return prop; } } return nullptr; } const char* InputDriver::inputGetPropertyKey(input_property_t* property) { if (property != nullptr) { return property->key.string(); } return nullptr; } const char* InputDriver::inputGetPropertyValue(input_property_t* property) { if (property != nullptr) { return property->value.string(); } return nullptr; } void InputDriver::inputFreeDeviceProperty(input_property_t* property) { if (property != nullptr) { delete property; } } void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) { if (map != nullptr) { delete map->propertyMap; delete map; } } void InputDriver::dump(String8& result) { result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); } } // namespace android // HAL wrapper functions namespace android { ::input_device_identifier_t* create_device_identifier(input_host_t* host, const char* name, int32_t product_id, int32_t vendor_id, input_bus_t bus, const char* unique_id) { auto driver = static_cast(host); return driver->createDeviceIdentifier(name, product_id, vendor_id, bus, unique_id); } input_device_definition_t* create_device_definition(input_host_t* host) { auto driver = static_cast(host); return driver->createDeviceDefinition(); } input_report_definition_t* create_input_report_definition(input_host_t* host) { auto driver = static_cast(host); return driver->createInputReportDefinition(); } input_report_definition_t* create_output_report_definition(input_host_t* host) { auto driver = static_cast(host); return driver->createOutputReportDefinition(); } void free_report_definition(input_host_t* host, input_report_definition_t* report_def) { auto driver = static_cast(host); driver->freeReportDefinition(report_def); } void input_device_definition_add_report(input_host_t* host, input_device_definition_t* d, input_report_definition_t* r) { auto driver = static_cast(host); driver->inputDeviceDefinitionAddReport(d, r); } void input_report_definition_add_collection(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, int32_t arity) { auto driver = static_cast(host); driver->inputReportDefinitionAddCollection(report, id, arity); } void input_report_definition_declare_usage_int(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, float resolution) { auto driver = static_cast(host); driver->inputReportDefinitionDeclareUsageInt(report, id, usage, min, max, resolution); } void input_report_definition_declare_usages_bool(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, input_usage_t* usage, size_t usage_count) { auto driver = static_cast(host); driver->inputReportDefinitionDeclareUsagesBool(report, id, usage, usage_count); } input_device_handle_t* register_device(input_host_t* host, input_device_identifier_t* id, input_device_definition_t* d) { auto driver = static_cast(host); return driver->registerDevice(id, d); } void unregister_device(input_host_t* host, input_device_handle_t* handle) { auto driver = static_cast(host); driver->unregisterDevice(handle); } input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) { auto driver = static_cast(host); return driver->inputAllocateReport(r); } void input_report_set_usage_int(input_host_t* host, input_report_t* r, input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { auto driver = static_cast(host); driver->inputReportSetUsageInt(r, id, usage, value, arity_index); } void input_report_set_usage_bool(input_host_t* host, input_report_t* r, input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { auto driver = static_cast(host); driver->inputReportSetUsageBool(r, id, usage, value, arity_index); } void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { auto driver = static_cast(host); driver->reportEvent(d, report); } input_property_map_t* input_get_device_property_map(input_host_t* host, input_device_identifier_t* id) { auto driver = static_cast(host); return driver->inputGetDevicePropertyMap(id); } input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, const char* key) { auto driver = static_cast(host); return driver->inputGetDeviceProperty(map, key); } const char* input_get_property_key(input_host_t* host, input_property_t* property) { auto driver = static_cast(host); return driver->inputGetPropertyKey(property); } const char* input_get_property_value(input_host_t* host, input_property_t* property) { auto driver = static_cast(host); return driver->inputGetPropertyValue(property); } void input_free_device_property(input_host_t* host, input_property_t* property) { auto driver = static_cast(host); driver->inputFreeDeviceProperty(property); } void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { auto driver = static_cast(host); driver->inputFreeDevicePropertyMap(map); } } // namespace android services/inputflinger/host/InputDriver.h0100644 0000000 0000000 00000021131 13077405420 017537 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_INPUT_DRIVER_H #define ANDROID_INPUT_DRIVER_H #include #include #include "InputHost.h" #include #include #include // Declare a concrete type for the HAL struct input_host { }; namespace android { class InputDriverInterface : public input_host_t, public virtual RefBase { protected: InputDriverInterface() = default; virtual ~InputDriverInterface() = default; public: virtual void init() = 0; virtual input_device_identifier_t* createDeviceIdentifier( const char* name, int32_t productId, int32_t vendorId, input_bus_t bus, const char* uniqueId) = 0; virtual input_device_definition_t* createDeviceDefinition() = 0; virtual input_report_definition_t* createInputReportDefinition() = 0; virtual input_report_definition_t* createOutputReportDefinition() = 0; virtual void freeReportDefinition(input_report_definition_t* reportDef) = 0; virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d, input_report_definition_t* r) = 0; virtual void inputReportDefinitionAddCollection(input_report_definition_t* report, input_collection_id_t id, int32_t arity) = 0; virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, float resolution) = 0; virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, input_collection_id_t id, input_usage_t* usage, size_t usageCount) = 0; virtual input_device_handle_t* registerDevice(input_device_identifier_t* id, input_device_definition_t* d) = 0; virtual void unregisterDevice(input_device_handle_t* handle) = 0; virtual input_report_t* inputAllocateReport(input_report_definition_t* r) = 0; virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) = 0; virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) = 0; virtual void reportEvent(input_device_handle_t* d, input_report_t* report) = 0; virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) = 0; virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map, const char* key) = 0; virtual const char* inputGetPropertyKey(input_property_t* property) = 0; virtual const char* inputGetPropertyValue(input_property_t* property) = 0; virtual void inputFreeDeviceProperty(input_property_t* property) = 0; virtual void inputFreeDevicePropertyMap(input_property_map_t* map) = 0; virtual void dump(String8& result) = 0; }; class InputDriver : public InputDriverInterface { public: InputDriver(const char* name); virtual ~InputDriver() = default; virtual void init() override; virtual input_device_identifier_t* createDeviceIdentifier( const char* name, int32_t productId, int32_t vendorId, input_bus_t bus, const char* uniqueId) override; virtual input_device_definition_t* createDeviceDefinition() override; virtual input_report_definition_t* createInputReportDefinition() override; virtual input_report_definition_t* createOutputReportDefinition() override; virtual void freeReportDefinition(input_report_definition_t* reportDef) override; virtual void inputDeviceDefinitionAddReport(input_device_definition_t* d, input_report_definition_t* r) override; virtual void inputReportDefinitionAddCollection(input_report_definition_t* report, input_collection_id_t id, int32_t arity) override; virtual void inputReportDefinitionDeclareUsageInt(input_report_definition_t* report, input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, float resolution) override; virtual void inputReportDefinitionDeclareUsagesBool(input_report_definition_t* report, input_collection_id_t id, input_usage_t* usage, size_t usageCount) override; virtual input_device_handle_t* registerDevice(input_device_identifier_t* id, input_device_definition_t* d) override; virtual void unregisterDevice(input_device_handle_t* handle) override; virtual input_report_t* inputAllocateReport(input_report_definition_t* r) override; virtual void inputReportSetUsageInt(input_report_t* r, input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) override; virtual void inputReportSetUsageBool(input_report_t* r, input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) override; virtual void reportEvent(input_device_handle_t* d, input_report_t* report) override; virtual input_property_map_t* inputGetDevicePropertyMap(input_device_identifier_t* id) override; virtual input_property_t* inputGetDeviceProperty(input_property_map_t* map, const char* key) override; virtual const char* inputGetPropertyKey(input_property_t* property) override; virtual const char* inputGetPropertyValue(input_property_t* property) override; virtual void inputFreeDeviceProperty(input_property_t* property) override; virtual void inputFreeDevicePropertyMap(input_property_map_t* map) override; virtual void dump(String8& result) override; private: String8 mName; const input_module_t* mHal; }; extern "C" { input_device_identifier_t* create_device_identifier(input_host_t* host, const char* name, int32_t product_id, int32_t vendor_id, input_bus_t bus, const char* unique_id); input_device_definition_t* create_device_definition(input_host_t* host); input_report_definition_t* create_input_report_definition(input_host_t* host); input_report_definition_t* create_output_report_definition(input_host_t* host); void free_report_definition(input_host_t* host, input_report_definition_t* report_def); void input_device_definition_add_report(input_host_t* host, input_device_definition_t* d, input_report_definition_t* r); void input_report_definition_add_collection(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, int32_t arity); void input_report_definition_declare_usage_int(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, input_usage_t usage, int32_t min, int32_t max, float resolution); void input_report_definition_declare_usages_bool(input_host_t* host, input_report_definition_t* report, input_collection_id_t id, input_usage_t* usage, size_t usage_count); input_device_handle_t* register_device(input_host_t* host, input_device_identifier_t* id, input_device_definition_t* d); void unregister_device(input_host_t* host, input_device_handle_t* handle); input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r); void input_report_set_usage_int(input_host_t* host, input_report_t* r, input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index); void input_report_set_usage_bool(input_host_t* host, input_report_t* r, input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index); void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report); input_property_map_t* input_get_device_property_map(input_host_t* host, input_device_identifier_t* id); input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, const char* key); const char* input_get_property_key(input_host_t* host, input_property_t* property); const char* input_get_property_value(input_host_t* host, input_property_t* property); void input_free_device_property(input_host_t* host, input_property_t* property); void input_free_device_property_map(input_host_t* host, input_property_map_t* map); } } // namespace android #endif // ANDROID_INPUT_DRIVER_H services/inputflinger/host/InputFlinger.cpp0100644 0000000 0000000 00000004050 13077405420 020226 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define LOG_TAG "InputFlinger" #include #include #include #include "InputFlinger.h" #include "InputDriver.h" #include #include #include #include #include namespace android { const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER"); const String16 sDumpPermission("android.permission.DUMP"); InputFlinger::InputFlinger() : BnInputFlinger() { ALOGI("InputFlinger is starting"); mHost = new InputHost(); mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV)); } InputFlinger::~InputFlinger() { } status_t InputFlinger::dump(int fd, const Vector& args) { String8 result; const IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) { result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); } else { dumpInternal(result); } write(fd, result.string(), result.size()); return OK; } void InputFlinger::dumpInternal(String8& result) { result.append("INPUT FLINGER (dumpsys inputflinger)\n"); mHost->dump(result); } }; // namespace android services/inputflinger/host/InputFlinger.h0100644 0000000 0000000 00000002502 13077405420 017673 0ustar000000000 0000000 /* * Copyright (C) 2013 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_INPUT_FLINGER_H #define ANDROID_INPUT_FLINGER_H #include #include #include "InputHost.h" #include #include #include #include #include namespace android { class InputFlinger : public BnInputFlinger { public: static char const* getServiceName() ANDROID_API { return "inputflinger"; } InputFlinger() ANDROID_API; virtual status_t dump(int fd, const Vector& args); private: virtual ~InputFlinger(); void dumpInternal(String8& result); sp mHost; }; } // namespace android #endif // ANDROID_INPUT_FLINGER_H services/inputflinger/host/InputHost.cpp0100644 0000000 0000000 00000002261 13077405420 017557 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "InputDriver.h" #include "InputHost.h" #include #include #define INDENT " " namespace android { void InputHost::registerInputDriver(InputDriverInterface* driver) { LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!"); driver->init(); mDrivers.push_back(driver); } void InputHost::dump(String8& result) { result.append(INDENT "Input Drivers:\n"); for (size_t i = 0; i < mDrivers.size(); i++) { mDrivers[i]->dump(result); } } } // namespace android services/inputflinger/host/InputHost.h0100644 0000000 0000000 00000002727 13077405420 017233 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_INPUT_HOST_H #define ANDROID_INPUT_HOST_H #include #include #include #include #include #include "InputDriver.h" namespace android { class InputDriverInterface; class InputHostInterface : public virtual RefBase { protected: InputHostInterface() = default; virtual ~InputHostInterface() = default; public: virtual void registerInputDriver(InputDriverInterface* driver) = 0; virtual void dump(String8& result) = 0; }; class InputHost : public InputHostInterface { public: InputHost() = default; virtual void registerInputDriver(InputDriverInterface* driver) override; virtual void dump(String8& result) override; private: std::vector> mDrivers; }; } // namespace android #endif // ANDRIOD_INPUT_HOST_H services/inputflinger/host/inputflinger.rc0100644 0000000 0000000 00000000204 13077405420 020145 0ustar000000000 0000000 service inputflinger /system/bin/inputflinger class main user system group input wakelock # onrestart restart zygote services/inputflinger/host/main.cpp0100644 0000000 0000000 00000001547 13077405420 016554 0ustar000000000 0000000 /* * Copyright (C) 2013 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 #include "InputFlinger.h" using namespace android; int main(int, char**) { ProcessState::self()->setThreadPoolMaxThreadCount(4); BinderService::publishAndJoinThreadPool(true); return 0; } services/inputflinger/tests/0040755 0000000 0000000 00000000000 13077405420 015305 5ustar000000000 0000000 services/inputflinger/tests/Android.mk0100644 0000000 0000000 00000001666 13077405420 017224 0ustar000000000 0000000 # Build the unit tests. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ InputReader_test.cpp \ InputDispatcher_test.cpp shared_libraries := \ libcutils \ liblog \ libutils \ libhardware \ libhardware_legacy \ libui \ libskia \ libinput \ libinputflinger \ libinputservice c_includes := \ external/skia/include/core module_tags := tests $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ $(eval LOCAL_C_INCLUDES := $(c_includes)) \ $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ $(eval include $(BUILD_NATIVE_TEST)) \ ) # Build the manual test programs. include $(call all-makefiles-under, $(LOCAL_PATH)) services/inputflinger/tests/InputDispatcher_test.cpp0100644 0000000 0000000 00000024121 13077405420 022153 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "../InputDispatcher.h" #include #include namespace android { // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; // An arbitrary device id. static const int32_t DEVICE_ID = 1; // An arbitrary display id. static const int32_t DISPLAY_ID = 0; // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; static const int32_t INJECTOR_UID = 1001; // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; protected: virtual ~FakeInputDispatcherPolicy() { } public: FakeInputDispatcherPolicy() { } private: virtual void notifyConfigurationChanged(nsecs_t) { } virtual nsecs_t notifyANR(const sp&, const sp&, const String8&) { return 0; } virtual void notifyInputChannelBroken(const sp&) { } virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { *outConfig = mConfig; } virtual bool filterInputEvent(const InputEvent*, uint32_t) { return true; } virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) { } virtual void interceptMotionBeforeQueueing(nsecs_t, uint32_t&) { } virtual nsecs_t interceptKeyBeforeDispatching(const sp&, const KeyEvent*, uint32_t) { return 0; } virtual bool dispatchUnhandledKey(const sp&, const KeyEvent*, uint32_t, KeyEvent*) { return false; } virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) { } virtual void pokeUserActivity(nsecs_t, int32_t) { } virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) { return false; } }; // --- InputDispatcherTest --- class InputDispatcherTest : public testing::Test { protected: sp mFakePolicy; sp mDispatcher; virtual void SetUp() { mFakePolicy = new FakeInputDispatcherPolicy(); mDispatcher = new InputDispatcher(mFakePolicy); } virtual void TearDown() { mFakePolicy.clear(); mDispatcher.clear(); } }; TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; // Rejects undefined key actions. event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject key events with undefined action."; // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject key events with ACTION_MULTIPLE."; } TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { MotionEvent event; PointerProperties pointerProperties[MAX_POINTERS + 1]; PointerCoords pointerCoords[MAX_POINTERS + 1]; for (int i = 0; i <= MAX_POINTERS; i++) { pointerProperties[i].clear(); pointerProperties[i].id = i; pointerCoords[i].clear(); } // Rejects undefined motion actions. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with undefined action."; // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too small."; // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with more than MAX_POINTERS pointers."; // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; // Rejects motion events with duplicate pointer ids. pointerProperties[0].id = 1; pointerProperties[1].id = 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with duplicate pointer ids."; } } // namespace android services/inputflinger/tests/InputReader_test.cpp0100644 0000000 0000000 00000664512 13077405420 021305 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "../InputReader.h" #include #include #include namespace android { // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; // Arbitrary display properties. static const int32_t DISPLAY_ID = 0; static const int32_t DISPLAY_WIDTH = 480; static const int32_t DISPLAY_HEIGHT = 800; // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; template static inline T min(T a, T b) { return a < b ? a : b; } static inline float avg(float x, float y) { return (x + y) / 2; } // --- FakePointerController --- class FakePointerController : public PointerControllerInterface { bool mHaveBounds; float mMinX, mMinY, mMaxX, mMaxY; float mX, mY; int32_t mButtonState; protected: virtual ~FakePointerController() { } public: FakePointerController() : mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0), mButtonState(0) { } void setBounds(float minX, float minY, float maxX, float maxY) { mHaveBounds = true; mMinX = minX; mMinY = minY; mMaxX = maxX; mMaxY = maxY; } virtual void setPosition(float x, float y) { mX = x; mY = y; } virtual void setButtonState(int32_t buttonState) { mButtonState = buttonState; } virtual int32_t getButtonState() const { return mButtonState; } virtual void getPosition(float* outX, float* outY) const { *outX = mX; *outY = mY; } private: virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { *outMinX = mMinX; *outMinY = mMinY; *outMaxX = mMaxX; *outMaxY = mMaxY; return mHaveBounds; } virtual void move(float deltaX, float deltaY) { mX += deltaX; if (mX < mMinX) mX = mMinX; if (mX > mMaxX) mX = mMaxX; mY += deltaY; if (mY < mMinY) mY = mMinY; if (mY > mMaxY) mY = mMaxY; } virtual void fade(Transition) { } virtual void unfade(Transition) { } virtual void setPresentation(Presentation) { } virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32) { } virtual void clearSpots() { } }; // --- FakeInputReaderPolicy --- class FakeInputReaderPolicy : public InputReaderPolicyInterface { InputReaderConfiguration mConfig; KeyedVector > mPointerControllers; Vector mInputDevices; TouchAffineTransformation transform; protected: virtual ~FakeInputReaderPolicy() { } public: FakeInputReaderPolicy() { } void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { // Set the size of both the internal and external display at the same time. bool isRotated = (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270); DisplayViewport v; v.displayId = displayId; v.orientation = orientation; v.logicalLeft = 0; v.logicalTop = 0; v.logicalRight = isRotated ? height : width; v.logicalBottom = isRotated ? width : height; v.physicalLeft = 0; v.physicalTop = 0; v.physicalRight = isRotated ? height : width; v.physicalBottom = isRotated ? width : height; v.deviceWidth = isRotated ? height : width; v.deviceHeight = isRotated ? width : height; mConfig.setDisplayInfo(false /*external*/, v); mConfig.setDisplayInfo(true /*external*/, v); } void addExcludedDeviceName(const String8& deviceName) { mConfig.excludedDeviceNames.push(deviceName); } void setPointerController(int32_t deviceId, const sp& controller) { mPointerControllers.add(deviceId, controller); } const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; } const Vector& getInputDevices() const { return mInputDevices; } TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor, int32_t surfaceRotation) { return transform; } void setTouchAffineTransformation(const TouchAffineTransformation t) { transform = t; } private: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } virtual sp obtainPointerController(int32_t deviceId) { return mPointerControllers.valueFor(deviceId); } virtual void notifyInputDevicesChanged(const Vector& inputDevices) { mInputDevices = inputDevices; } virtual sp getKeyboardLayoutOverlay(const InputDeviceIdentifier&) { return NULL; } virtual String8 getDeviceAlias(const InputDeviceIdentifier&) { return String8::empty(); } }; // --- FakeInputListener --- class FakeInputListener : public InputListenerInterface { private: List mNotifyConfigurationChangedArgsQueue; List mNotifyDeviceResetArgsQueue; List mNotifyKeyArgsQueue; List mNotifyMotionArgsQueue; List mNotifySwitchArgsQueue; protected: virtual ~FakeInputListener() { } public: FakeInputListener() { } void assertNotifyConfigurationChangedWasCalled( NotifyConfigurationChangedArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty()) << "Expected notifyConfigurationChanged() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin(); } mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); } void assertNotifyDeviceResetWasCalled( NotifyDeviceResetArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) << "Expected notifyDeviceReset() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyDeviceResetArgsQueue.begin(); } mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); } void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyKeyArgsQueue.begin(); } mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin()); } void assertNotifyKeyWasNotCalled() { ASSERT_TRUE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to not have been called."; } void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyMotionArgsQueue.begin(); } mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin()); } void assertNotifyMotionWasNotCalled() { ASSERT_TRUE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to not have been called."; } void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifySwitchArgsQueue.empty()) << "Expected notifySwitch() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifySwitchArgsQueue.begin(); } mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin()); } private: virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { mNotifyConfigurationChangedArgsQueue.push_back(*args); } virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) { mNotifyDeviceResetArgsQueue.push_back(*args); } virtual void notifyKey(const NotifyKeyArgs* args) { mNotifyKeyArgsQueue.push_back(*args); } virtual void notifyMotion(const NotifyMotionArgs* args) { mNotifyMotionArgsQueue.push_back(*args); } virtual void notifySwitch(const NotifySwitchArgs* args) { mNotifySwitchArgsQueue.push_back(*args); } }; // --- FakeEventHub --- class FakeEventHub : public EventHubInterface { struct KeyInfo { int32_t keyCode; uint32_t flags; }; struct Device { InputDeviceIdentifier identifier; uint32_t classes; PropertyMap configuration; KeyedVector absoluteAxes; KeyedVector relativeAxes; KeyedVector keyCodeStates; KeyedVector scanCodeStates; KeyedVector switchStates; KeyedVector absoluteAxisValue; KeyedVector keysByScanCode; KeyedVector keysByUsageCode; KeyedVector leds; Vector virtualKeys; Device(uint32_t classes) : classes(classes) { } }; KeyedVector mDevices; Vector mExcludedDevices; List mEvents; protected: virtual ~FakeEventHub() { for (size_t i = 0; i < mDevices.size(); i++) { delete mDevices.valueAt(i); } } public: FakeEventHub() { } void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { Device* device = new Device(classes); device->identifier.name = name; mDevices.add(deviceId, device); enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); } void removeDevice(int32_t deviceId) { delete mDevices.valueFor(deviceId); mDevices.removeItem(deviceId); enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); } void finishDeviceScan() { enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { Device* device = getDevice(deviceId); device->configuration.addProperty(key, value); } void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { Device* device = getDevice(deviceId); device->configuration.addAll(configuration); } void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) { Device* device = getDevice(deviceId); RawAbsoluteAxisInfo info; info.valid = true; info.minValue = minValue; info.maxValue = maxValue; info.flat = flat; info.fuzz = fuzz; info.resolution = resolution; device->absoluteAxes.add(axis, info); } void addRelativeAxis(int32_t deviceId, int32_t axis) { Device* device = getDevice(deviceId); device->relativeAxes.add(axis, true); } void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { Device* device = getDevice(deviceId); device->keyCodeStates.replaceValueFor(keyCode, state); } void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { Device* device = getDevice(deviceId); device->scanCodeStates.replaceValueFor(scanCode, state); } void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { Device* device = getDevice(deviceId); device->switchStates.replaceValueFor(switchCode, state); } void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { Device* device = getDevice(deviceId); device->absoluteAxisValue.replaceValueFor(axis, value); } void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, uint32_t flags) { Device* device = getDevice(deviceId); KeyInfo info; info.keyCode = keyCode; info.flags = flags; if (scanCode) { device->keysByScanCode.add(scanCode, info); } if (usageCode) { device->keysByUsageCode.add(usageCode, info); } } void addLed(int32_t deviceId, int32_t led, bool initialState) { Device* device = getDevice(deviceId); device->leds.add(led, initialState); } bool getLedState(int32_t deviceId, int32_t led) { Device* device = getDevice(deviceId); return device->leds.valueFor(led); } Vector& getExcludedDevices() { return mExcludedDevices; } void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { Device* device = getDevice(deviceId); device->virtualKeys.push(definition); } void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, int32_t code, int32_t value) { RawEvent event; event.when = when; event.deviceId = deviceId; event.type = type; event.code = code; event.value = value; mEvents.push_back(event); if (type == EV_ABS) { setAbsoluteAxisValue(deviceId, code, value); } } void assertQueueIsEmpty() { ASSERT_EQ(size_t(0), mEvents.size()) << "Expected the event queue to be empty (fully consumed)."; } private: Device* getDevice(int32_t deviceId) const { ssize_t index = mDevices.indexOfKey(deviceId); return index >= 0 ? mDevices.valueAt(index) : NULL; } virtual uint32_t getDeviceClasses(int32_t deviceId) const { Device* device = getDevice(deviceId); return device ? device->classes : 0; } virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const { Device* device = getDevice(deviceId); return device ? device->identifier : InputDeviceIdentifier(); } virtual int32_t getDeviceControllerNumber(int32_t) const { return 0; } virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { Device* device = getDevice(deviceId); if (device) { *outConfiguration = device->configuration; } } virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->absoluteAxes.indexOfKey(axis); if (index >= 0) { *outAxisInfo = device->absoluteAxes.valueAt(index); return OK; } } outAxisInfo->clear(); return -1; } virtual bool hasRelativeAxis(int32_t deviceId, int axis) const { Device* device = getDevice(deviceId); if (device) { return device->relativeAxes.indexOfKey(axis) >= 0; } return false; } virtual bool hasInputProperty(int32_t, int) const { return false; } virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const { Device* device = getDevice(deviceId); if (device) { const KeyInfo* key = getKey(device, scanCode, usageCode); if (key) { if (outKeycode) { *outKeycode = key->keyCode; } if (outFlags) { *outFlags = key->flags; } if (outMetaState) { *outMetaState = metaState; } return OK; } } return NAME_NOT_FOUND; } const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const { if (usageCode) { ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); if (index >= 0) { return &device->keysByUsageCode.valueAt(index); } } if (scanCode) { ssize_t index = device->keysByScanCode.indexOfKey(scanCode); if (index >= 0) { return &device->keysByScanCode.valueAt(index); } } return NULL; } virtual status_t mapAxis(int32_t, int32_t, AxisInfo*) const { return NAME_NOT_FOUND; } virtual void setExcludedDevices(const Vector& devices) { mExcludedDevices = devices; } virtual size_t getEvents(int, RawEvent* buffer, size_t) { if (mEvents.empty()) { return 0; } *buffer = *mEvents.begin(); mEvents.erase(mEvents.begin()); return 1; } virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->scanCodeStates.indexOfKey(scanCode); if (index >= 0) { return device->scanCodeStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->keyCodeStates.indexOfKey(keyCode); if (index >= 0) { return device->keyCodeStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->switchStates.indexOfKey(sw); if (index >= 0) { return device->switchStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->absoluteAxisValue.indexOfKey(axis); if (index >= 0) { *outValue = device->absoluteAxisValue.valueAt(index); return OK; } } *outValue = 0; return -1; } virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { bool result = false; Device* device = getDevice(deviceId); if (device) { for (size_t i = 0; i < numCodes; i++) { for (size_t j = 0; j < device->keysByScanCode.size(); j++) { if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { outFlags[i] = 1; result = true; } } for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { outFlags[i] = 1; result = true; } } } } return result; } virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->keysByScanCode.indexOfKey(scanCode); return index >= 0; } return false; } virtual bool hasLed(int32_t deviceId, int32_t led) const { Device* device = getDevice(deviceId); return device && device->leds.indexOfKey(led) >= 0; } virtual void setLedState(int32_t deviceId, int32_t led, bool on) { Device* device = getDevice(deviceId); if (device) { ssize_t index = device->leds.indexOfKey(led); if (index >= 0) { device->leds.replaceValueAt(led, on); } else { ADD_FAILURE() << "Attempted to set the state of an LED that the EventHub declared " "was not present. led=" << led; } } } virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const { outVirtualKeys.clear(); Device* device = getDevice(deviceId); if (device) { outVirtualKeys.appendVector(device->virtualKeys); } } virtual sp getKeyCharacterMap(int32_t) const { return NULL; } virtual bool setKeyboardLayoutOverlay(int32_t, const sp&) { return false; } virtual void vibrate(int32_t, nsecs_t) { } virtual void cancelVibrate(int32_t) { } virtual bool isExternal(int32_t) const { return false; } virtual void dump(String8&) { } virtual void monitor() { } virtual void requestReopenDevices() { } virtual void wake() { } }; // --- FakeInputReaderContext --- class FakeInputReaderContext : public InputReaderContext { sp mEventHub; sp mPolicy; sp mListener; int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; int32_t mGeneration; public: FakeInputReaderContext(const sp& eventHub, const sp& policy, const sp& listener) : mEventHub(eventHub), mPolicy(policy), mListener(listener), mGlobalMetaState(0) { } virtual ~FakeInputReaderContext() { } void assertUpdateGlobalMetaStateWasCalled() { ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled) << "Expected updateGlobalMetaState() to have been called."; mUpdateGlobalMetaStateWasCalled = false; } void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; } private: virtual void updateGlobalMetaState() { mUpdateGlobalMetaStateWasCalled = true; } virtual int32_t getGlobalMetaState() { return mGlobalMetaState; } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); } virtual InputListenerInterface* getListener() { return mListener.get(); } virtual void disableVirtualKeysUntil(nsecs_t) { } virtual bool shouldDropVirtualKey(nsecs_t, InputDevice*, int32_t, int32_t) { return false; } virtual void fadePointer() { } virtual void requestTimeoutAtTime(nsecs_t) { } virtual int32_t bumpGeneration() { return ++mGeneration; } virtual void getExternalStylusDevices(Vector& outDevices) { } virtual void dispatchExternalStylusState(const StylusState&) { } }; // --- FakeInputMapper --- class FakeInputMapper : public InputMapper { uint32_t mSources; int32_t mKeyboardType; int32_t mMetaState; KeyedVector mKeyCodeStates; KeyedVector mScanCodeStates; KeyedVector mSwitchStates; Vector mSupportedKeyCodes; RawEvent mLastEvent; bool mConfigureWasCalled; bool mResetWasCalled; bool mProcessWasCalled; public: FakeInputMapper(InputDevice* device, uint32_t sources) : InputMapper(device), mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), mMetaState(0), mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { } virtual ~FakeInputMapper() { } void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } void setMetaState(int32_t metaState) { mMetaState = metaState; } void assertConfigureWasCalled() { ASSERT_TRUE(mConfigureWasCalled) << "Expected configure() to have been called."; mConfigureWasCalled = false; } void assertResetWasCalled() { ASSERT_TRUE(mResetWasCalled) << "Expected reset() to have been called."; mResetWasCalled = false; } void assertProcessWasCalled(RawEvent* outLastEvent = NULL) { ASSERT_TRUE(mProcessWasCalled) << "Expected process() to have been called."; if (outLastEvent) { *outLastEvent = mLastEvent; } mProcessWasCalled = false; } void setKeyCodeState(int32_t keyCode, int32_t state) { mKeyCodeStates.replaceValueFor(keyCode, state); } void setScanCodeState(int32_t scanCode, int32_t state) { mScanCodeStates.replaceValueFor(scanCode, state); } void setSwitchState(int32_t switchCode, int32_t state) { mSwitchStates.replaceValueFor(switchCode, state); } void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.add(keyCode); } private: virtual uint32_t getSources() { return mSources; } virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) { InputMapper::populateDeviceInfo(deviceInfo); if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { deviceInfo->setKeyboardType(mKeyboardType); } } virtual void configure(nsecs_t, const InputReaderConfiguration*, uint32_t) { mConfigureWasCalled = true; } virtual void reset(nsecs_t) { mResetWasCalled = true; } virtual void process(const RawEvent* rawEvent) { mLastEvent = *rawEvent; mProcessWasCalled = true; } virtual int32_t getKeyCodeState(uint32_t, int32_t keyCode) { ssize_t index = mKeyCodeStates.indexOfKey(keyCode); return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } virtual int32_t getScanCodeState(uint32_t, int32_t scanCode) { ssize_t index = mScanCodeStates.indexOfKey(scanCode); return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } virtual int32_t getSwitchState(uint32_t, int32_t switchCode) { ssize_t index = mSwitchStates.indexOfKey(switchCode); return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; } virtual bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; for (size_t i = 0; i < numCodes; i++) { for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { if (keyCodes[i] == mSupportedKeyCodes[j]) { outFlags[i] = 1; result = true; } } } return result; } virtual int32_t getMetaState() { return mMetaState; } virtual void fadePointer() { } }; // --- InstrumentedInputReader --- class InstrumentedInputReader : public InputReader { InputDevice* mNextDevice; public: InstrumentedInputReader(const sp& eventHub, const sp& policy, const sp& listener) : InputReader(eventHub, policy, listener), mNextDevice(NULL) { } virtual ~InstrumentedInputReader() { if (mNextDevice) { delete mNextDevice; } } void setNextDevice(InputDevice* device) { mNextDevice = device; } InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name, uint32_t classes) { InputDeviceIdentifier identifier; identifier.name = name; int32_t generation = deviceId + 1; return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier, classes); } protected: virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { if (mNextDevice) { InputDevice* device = mNextDevice; mNextDevice = NULL; return device; } return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes); } friend class InputReaderTest; }; // --- InputReaderTest --- class InputReaderTest : public testing::Test { protected: sp mFakeListener; sp mFakePolicy; sp mFakeEventHub; sp mReader; virtual void SetUp() { mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeListener); } virtual void TearDown() { mReader.clear(); mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } void addDevice(int32_t deviceId, const String8& name, uint32_t classes, const PropertyMap* configuration) { mFakeEventHub->addDevice(deviceId, name, classes); if (configuration) { mFakeEventHub->addConfigurationMap(deviceId, configuration); } mFakeEventHub->finishDeviceScan(); mReader->loopOnce(); mReader->loopOnce(); mFakeEventHub->assertQueueIsEmpty(); } FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, const String8& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes); FakeInputMapper* mapper = new FakeInputMapper(device, sources); device->addMapper(mapper); mReader->setNextDevice(device); addDevice(deviceId, name, classes, configuration); return mapper; } }; TEST_F(InputReaderTest, GetInputDevices) { ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), INPUT_DEVICE_CLASS_KEYBOARD, NULL)); ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"), 0, NULL)); // no classes so device will be ignored Vector inputDevices; mReader->getInputDevices(inputDevices); ASSERT_EQ(1U, inputDevices.size()); ASSERT_EQ(1, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); // Should also have received a notification describing the new input devices. inputDevices = mFakePolicy->getInputDevices(); ASSERT_EQ(1U, inputDevices.size()); ASSERT_EQ(1, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); } TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, AINPUT_SOURCE_ANY, AKEYCODE_A)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, AINPUT_SOURCE_ANY, KEY_A)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, AINPUT_SOURCE_ANY, SW_LID)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->addSupportedKeyCode(AKEYCODE_A); mapper->addSupportedKeyCode(AKEYCODE_B); const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; uint8_t flags[4] = { 0, 0, 0, 1 }; ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) << "Should return false when device id is >= 0 but unknown."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return false when device id is valid but the sources are not supported by the device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return false when the device id is < 0 but the sources are not supported by any device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); } TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL); NotifyConfigurationChangedArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); } TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); RawEvent event; ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); ASSERT_EQ(0, event.when); ASSERT_EQ(1, event.deviceId); ASSERT_EQ(EV_KEY, event.type); ASSERT_EQ(KEY_A, event.code); ASSERT_EQ(1, event.value); } // --- InputDeviceTest --- class InputDeviceTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; sp mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; InputDevice* mDevice; virtual void SetUp() { mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); } virtual void TearDown() { delete mDevice; delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } }; const char* InputDeviceTest::DEVICE_NAME = "device"; const int32_t InputDeviceTest::DEVICE_ID = 1; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK; TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_ID, mDevice->getId()); ASSERT_STREQ(DEVICE_NAME, mDevice->getName()); ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); } TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { // Configuration. InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); // Reset. mDevice->reset(ARBITRARY_TIME); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Metadata. ASSERT_TRUE(mDevice->isIgnored()); ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources()); InputDeviceInfo info; mDevice->getDeviceInfo(&info); ASSERT_EQ(DEVICE_ID, info.getId()); ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources()); // State queries. ASSERT_EQ(0, mDevice->getMetaState()); ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown key code state."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown scan code state."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown switch state."; const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 1 }; ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) << "Ignored device should never mark any key codes."; ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; } TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); mapper1->setMetaState(AMETA_ALT_ON); mapper1->addSupportedKeyCode(AKEYCODE_A); mapper1->addSupportedKeyCode(AKEYCODE_B); mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); mapper1->setScanCodeState(2, AKEY_STATE_DOWN); mapper1->setScanCodeState(3, AKEY_STATE_UP); mapper1->setSwitchState(4, AKEY_STATE_DOWN); mDevice->addMapper(mapper1); FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); mapper2->setMetaState(AMETA_SHIFT_ON); mDevice->addMapper(mapper2); InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); String8 propertyValue; ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) << "Device should have read configuration during configuration phase."; ASSERT_STREQ("value", propertyValue.string()); ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); // Reset mDevice->reset(ARBITRARY_TIME); ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Metadata. ASSERT_FALSE(mDevice->isIgnored()); ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); InputDeviceInfo info; mDevice->getDeviceInfo(&info); ASSERT_EQ(DEVICE_ID, info.getId()); ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType()); ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources()); // State queries. ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState()) << "Should query mappers and combine meta states."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown key code state when source not supported."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown scan code state when source not supported."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown switch state when source not supported."; ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A)) << "Should query mapper when source is supported."; ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3)) << "Should query mapper when source is supported."; ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) << "Should query mapper when source is supported."; const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; uint8_t flags[4] = { 0, 0, 0, 1 }; ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should do nothing when source is unsupported."; ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) << "Should query mapper when source is supported."; ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged."; // Event handling. RawEvent event; mDevice->process(&event, 1); ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); } // --- InputMapperTest --- class InputMapperTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; sp mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; InputDevice* mDevice; virtual void SetUp() { mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); } virtual void TearDown() { delete mDevice; delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } void addConfigurationProperty(const char* key, const char* value) { mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value)); } void addMapperAndConfigure(InputMapper* mapper) { mDevice->addMapper(mapper); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); mDevice->reset(ARBITRARY_TIME); } void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { mFakePolicy->setDisplayInfo(displayId, width, height, orientation); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); } static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, int32_t code, int32_t value) { RawEvent event; event.when = when; event.deviceId = deviceId; event.type = type; event.code = code; event.value = value; mapper->process(&event); } static void assertMotionRange(const InputDeviceInfo& info, int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) { const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source); ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source; ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source; ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source; } static void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure, float size, float touchMajor, float touchMinor, float toolMajor, float toolMinor, float orientation, float distance) { ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), 1); ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON); ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON); ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 1); ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 1); ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 1); ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 1); ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON); ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON); } static void assertPosition(const sp& controller, float x, float y) { float actualX, actualY; controller->getPosition(&actualX, &actualY); ASSERT_NEAR(x, actualX, 1); ASSERT_NEAR(y, actualY, 1); } }; const char* InputMapperTest::DEVICE_NAME = "device"; const int32_t InputMapperTest::DEVICE_ID = 1; const int32_t InputMapperTest::DEVICE_GENERATION = 2; const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests // --- SwitchInputMapperTest --- class SwitchInputMapperTest : public InputMapperTest { protected: }; TEST_F(SwitchInputMapperTest, GetSources) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources()); } TEST_F(SwitchInputMapperTest, GetSwitchState) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); } TEST_F(SwitchInputMapperTest, Process) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_JACK_PHYSICAL_INSERT, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_HEADPHONE_INSERT, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); NotifySwitchArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySwitchWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT), args.switchValues); ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT), args.switchMask); ASSERT_EQ(uint32_t(0), args.policyFlags); } // --- KeyboardInputMapperTest --- class KeyboardInputMapperTest : public InputMapperTest { protected: void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode); }; void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, int32_t, int32_t rotatedKeyCode) { NotifyKeyArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); } TEST_F(KeyboardInputMapperTest, GetSources) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); } TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { const int32_t USAGE_A = 0x070004; const int32_t USAGE_UNKNOWN = 0x07ffff; mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Key down by scan code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_HOME, 1); NotifyKeyArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up by scan code. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_HOME, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key down by usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_A); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, 0, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEYCODE_A, args.keyCode); ASSERT_EQ(0, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up by usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_A); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, 0, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEYCODE_A, args.keyCode); ASSERT_EQ(0, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key down with unknown scan code or usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_UNKNOWN); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UNKNOWN, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(0, args.keyCode); ASSERT_EQ(KEY_UNKNOWN, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(0U, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up with unknown scan code or usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_UNKNOWN); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_UNKNOWN, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(0, args.keyCode); ASSERT_EQ(KEY_UNKNOWN, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(0U, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); } TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Initial metastate. ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); // Metakey down. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_LEFTSHIFT, 1); NotifyKeyArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); // Key down. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_A, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); // Key up. process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, EV_KEY, KEY_A, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); // Metakey up. process(mapper, ARBITRARY_TIME + 3, DEVICE_ID, EV_KEY, KEY_LEFTSHIFT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); } TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); } TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addConfigurationProperty("keyboard.orientationAware", "1"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP)); // Special case: if orientation changes while key is down, we still emit the same keycode // in the key up as we did in the key down. NotifyKeyArgs args; setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(KEY_UP, args.scanCode); ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(KEY_UP, args.scanCode); ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); } TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); } TEST_F(KeyboardInputMapperTest, GetScanCodeState) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); } TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) { mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/); mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Initialization should have turned all of the lights off. ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); // Toggle caps lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 0); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState()); // Toggle num lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 0); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState()); // Toggle caps lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState()); // Toggle scroll lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); // Toggle num lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); // Toggle scroll lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); } // --- CursorInputMapperTest --- class CursorInputMapperTest : public InputMapperTest { protected: static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; sp mFakePointerController; virtual void SetUp() { InputMapperTest::SetUp(); mFakePointerController = new FakePointerController(); mFakePolicy->setPointerController(DEVICE_ID, mFakePointerController); } void testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); }; const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { NotifyMotionArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, originalX); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, originalY); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); InputDeviceInfo info; mapper->populateDeviceInfo(&info); // Initially there may not be a valid motion range. ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE)); ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f)); // When the bounds are set, then there should be a valid motion range. mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1); InputDeviceInfo info2; mapper->populateDeviceInfo(&info2); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE, 1, 800 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE, 2, 480 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); InputDeviceInfo info; mapper->populateDeviceInfo(&info); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL, -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL, -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL, 0.0f, 1.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs args; // Button press. // Mostly testing non x/y behavior here so we don't need to check again elsewhere. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); ASSERT_EQ(uint32_t(0), args.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Button release. Should have same down time. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); ASSERT_EQ(uint32_t(0), args.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(0, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Motion in X but not Y. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Motion in Y but not X. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Button press. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Button release. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Combined X, Y and Button. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Move X, Y a bit while pressed. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Release Button. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); } TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addConfigurationProperty("cursor.orientationAware", "1"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); mFakePointerController->setButtonState(0); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; // press BTN_LEFT, release BTN_LEFT process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState()); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // press BTN_BACK, release BTN_BACK process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); } TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); mFakePointerController->setButtonState(0); NotifyMotionArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f)); } // --- TouchInputMapperTest --- class TouchInputMapperTest : public InputMapperTest { protected: static const int32_t RAW_X_MIN; static const int32_t RAW_X_MAX; static const int32_t RAW_Y_MIN; static const int32_t RAW_Y_MAX; static const int32_t RAW_TOUCH_MIN; static const int32_t RAW_TOUCH_MAX; static const int32_t RAW_TOOL_MIN; static const int32_t RAW_TOOL_MAX; static const int32_t RAW_PRESSURE_MIN; static const int32_t RAW_PRESSURE_MAX; static const int32_t RAW_ORIENTATION_MIN; static const int32_t RAW_ORIENTATION_MAX; static const int32_t RAW_DISTANCE_MIN; static const int32_t RAW_DISTANCE_MAX; static const int32_t RAW_TILT_MIN; static const int32_t RAW_TILT_MAX; static const int32_t RAW_ID_MIN; static const int32_t RAW_ID_MAX; static const int32_t RAW_SLOT_MIN; static const int32_t RAW_SLOT_MAX; static const float X_PRECISION; static const float Y_PRECISION; static const float GEOMETRIC_SCALE; static const TouchAffineTransformation AFFINE_TRANSFORM; static const VirtualKeyDefinition VIRTUAL_KEYS[2]; enum Axes { POSITION = 1 << 0, TOUCH = 1 << 1, TOOL = 1 << 2, PRESSURE = 1 << 3, ORIENTATION = 1 << 4, MINOR = 1 << 5, ID = 1 << 6, DISTANCE = 1 << 7, TILT = 1 << 8, SLOT = 1 << 9, TOOL_TYPE = 1 << 10, }; void prepareDisplay(int32_t orientation); void prepareVirtualKeys(); void prepareLocationCalibration(); int32_t toRawX(float displayX); int32_t toRawY(float displayY); float toCookedX(float rawX, float rawY); float toCookedY(float rawX, float rawY); float toDisplayX(int32_t rawX); float toDisplayY(int32_t rawY); }; const int32_t TouchInputMapperTest::RAW_X_MIN = 25; const int32_t TouchInputMapperTest::RAW_X_MAX = 1019; const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009; const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0; const int32_t TouchInputMapperTest::RAW_DISTANCE_MAX = 7; const int32_t TouchInputMapperTest::RAW_TILT_MIN = 0; const int32_t TouchInputMapperTest::RAW_TILT_MAX = 150; const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; const int32_t TouchInputMapperTest::RAW_SLOT_MIN = 0; const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9; const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH; const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT; const TouchAffineTransformation TouchInputMapperTest::AFFINE_TRANSFORM = TouchAffineTransformation(1, -2, 3, -4, 5, -6); const float TouchInputMapperTest::GEOMETRIC_SCALE = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1), float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1)); const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, }; void TouchInputMapperTest::prepareDisplay(int32_t orientation) { setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); } void TouchInputMapperTest::prepareVirtualKeys() { mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE); } void TouchInputMapperTest::prepareLocationCalibration() { mFakePolicy->setTouchAffineTransformation(AFFINE_TRANSFORM); } int32_t TouchInputMapperTest::toRawX(float displayX) { return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN); } int32_t TouchInputMapperTest::toRawY(float displayY) { return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN); } float TouchInputMapperTest::toCookedX(float rawX, float rawY) { AFFINE_TRANSFORM.applyTo(rawX, rawY); return rawX; } float TouchInputMapperTest::toCookedY(float rawX, float rawY) { AFFINE_TRANSFORM.applyTo(rawX, rawY); return rawY; } float TouchInputMapperTest::toDisplayX(int32_t rawX) { return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1); } float TouchInputMapperTest::toDisplayY(int32_t rawY) { return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1); } // --- SingleTouchInputMapperTest --- class SingleTouchInputMapperTest : public TouchInputMapperTest { protected: void prepareButtons(); void prepareAxes(int axes); void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); void processUp(SingleTouchInputMapper* mappery); void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); void processDistance(SingleTouchInputMapper* mapper, int32_t distance); void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY); void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value); void processSync(SingleTouchInputMapper* mapper); }; void SingleTouchInputMapperTest::prepareButtons() { mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); } void SingleTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & PRESSURE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); } if (axes & TOOL) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); } if (axes & DISTANCE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE, RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); } if (axes & TILT) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); } } void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); } void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); } void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0); } void SingleTouchInputMapperTest::processPressure( SingleTouchInputMapper* mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, pressure); } void SingleTouchInputMapperTest::processToolMajor( SingleTouchInputMapper* mapper, int32_t toolMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, toolMajor); } void SingleTouchInputMapperTest::processDistance( SingleTouchInputMapper* mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_DISTANCE, distance); } void SingleTouchInputMapperTest::processTilt( SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_X, tiltX); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_Y, tiltY); } void SingleTouchInputMapperTest::processKey( SingleTouchInputMapper* mapper, int32_t code, int32_t value) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); } void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchPad"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); } TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); } TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; uint8_t flags[2] = { 0, 0 }; ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyKeyArgs args; // Press virtual key. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Release virtual key. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Should not have sent any motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyKeyArgs keyArgs; // Press virtual key. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags); ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); ASSERT_EQ(KEY_HOME, keyArgs.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); // Move out of bounds. This should generate a cancel and a pointer down since we moved // into the display area. y -= 100; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags); ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); ASSERT_EQ(KEY_HOME, keyArgs.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); NotifyMotionArgs motionArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Keep moving out of bounds. Should generate a pointer move. y -= 50; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Release out of bounds. Should generate a pointer up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Initially go down out of bounds. int32_t x = -10; int32_t y = -10; processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // Move into the display area. Should generate a pointer down. x = 50; y = 75; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Release. Should generate a pointer up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Down. int32_t x = 100; int32_t y = 125; processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Move. x += 50; y += 75; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.orientationAware", "0"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Rotation 90. prepareDisplay(DISPLAY_ORIENTATION_90); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Rotation 0. prepareDisplay(DISPLAY_ORIENTATION_0); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 90. prepareDisplay(DISPLAY_ORIENTATION_90); processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 180. prepareDisplay(DISPLAY_ORIENTATION_180); processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 270. prepareDisplay(DISPLAY_ORIENTATION_270); processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawPressure = 10; int32_t rawToolMajor = 12; int32_t rawDistance = 2; int32_t rawTiltX = 30; int32_t rawTiltY = 110; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) / RAW_PRESSURE_MAX; float size = float(rawToolMajor) / RAW_TOOL_MAX; float tool = float(rawToolMajor) * GEOMETRIC_SCALE; float distance = float(rawDistance); float tiltCenter = (RAW_TILT_MAX + RAW_TILT_MIN) * 0.5f; float tiltScale = M_PI / 180; float tiltXAngle = (rawTiltX - tiltCenter) * tiltScale; float tiltYAngle = (rawTiltY - tiltCenter) * tiltScale; float orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); float tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); processDown(mapper, rawX, rawY); processPressure(mapper, rawPressure); processToolMajor(mapper, rawToolMajor); processDistance(mapper, rawDistance); processTilt(mapper, rawTiltX, rawTiltY); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, size, tool, tool, tool, tool, orientation, distance)); ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT)); } TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareLocationCalibration(); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); int32_t rawX = 100; int32_t rawY = 200; float x = toDisplayX(toCookedX(rawX, rawY)); float y = toDisplayY(toCookedY(rawX, rawY)); processDown(mapper, rawX, rawY); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); // press BTN_LEFT, release BTN_LEFT processKey(mapper, BTN_LEFT, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); processKey(mapper, BTN_LEFT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE processKey(mapper, BTN_RIGHT, 1); processKey(mapper, BTN_MIDDLE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_RIGHT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_MIDDLE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_BACK, release BTN_BACK processKey(mapper, BTN_BACK, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_BACK, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE processKey(mapper, BTN_SIDE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_SIDE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD processKey(mapper, BTN_FORWARD, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_FORWARD, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA processKey(mapper, BTN_EXTRA, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_EXTRA, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_STYLUS, release BTN_STYLUS processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_STYLUS2, release BTN_STYLUS2 processKey(mapper, BTN_STYLUS2, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS2, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // release touch processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // default tool type is finger processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_BRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); processKey(mapper, BTN_TOOL_PENCIL, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // airbrush processKey(mapper, BTN_TOOL_PENCIL, 0); processKey(mapper, BTN_TOOL_AIRBRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_LENS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_DOUBLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); processKey(mapper, BTN_TOOL_TRIPLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); processKey(mapper, BTN_TOOL_QUADTAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // back to default tool type processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 processKey(mapper, BTN_TOOL_FINGER, 1); processMove(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processMove(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when BTN_TOUCH is pressed, pressure defaults to 1 processKey(mapper, BTN_TOUCH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when BTN_TOUCH is released, hover restored processKey(mapper, BTN_TOUCH, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because pressure is 0 processDown(mapper, 100, 200); processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processMove(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when pressure is non-zero processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when pressure becomes 0, hover restored processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } // --- MultiTouchInputMapperTest --- class MultiTouchInputMapperTest : public TouchInputMapperTest { protected: void prepareAxes(int axes); void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); void processDistance(MultiTouchInputMapper* mapper, int32_t distance); void processId(MultiTouchInputMapper* mapper, int32_t id); void processSlot(MultiTouchInputMapper* mapper, int32_t slot); void processToolType(MultiTouchInputMapper* mapper, int32_t toolType); void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value); void processMTSync(MultiTouchInputMapper* mapper); void processSync(MultiTouchInputMapper* mapper); }; void MultiTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & TOUCH) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); if (axes & MINOR) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); } } if (axes & TOOL) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); if (axes & MINOR) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); } } if (axes & ORIENTATION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); } if (axes & PRESSURE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); } if (axes & DISTANCE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE, RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); } if (axes & ID) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, 0, 0); } if (axes & SLOT) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0); mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0); } if (axes & TOOL_TYPE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); } } void MultiTouchInputMapperTest::processPosition( MultiTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, y); } void MultiTouchInputMapperTest::processTouchMajor( MultiTouchInputMapper* mapper, int32_t touchMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor); } void MultiTouchInputMapperTest::processTouchMinor( MultiTouchInputMapper* mapper, int32_t touchMinor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor); } void MultiTouchInputMapperTest::processToolMajor( MultiTouchInputMapper* mapper, int32_t toolMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor); } void MultiTouchInputMapperTest::processToolMinor( MultiTouchInputMapper* mapper, int32_t toolMinor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor); } void MultiTouchInputMapperTest::processOrientation( MultiTouchInputMapper* mapper, int32_t orientation) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, orientation); } void MultiTouchInputMapperTest::processPressure( MultiTouchInputMapper* mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, pressure); } void MultiTouchInputMapperTest::processDistance( MultiTouchInputMapper* mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_DISTANCE, distance); } void MultiTouchInputMapperTest::processId( MultiTouchInputMapper* mapper, int32_t id) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, id); } void MultiTouchInputMapperTest::processSlot( MultiTouchInputMapper* mapper, int32_t slot) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_SLOT, slot); } void MultiTouchInputMapperTest::processToolType( MultiTouchInputMapper* mapper, int32_t toolType) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOOL_TYPE, toolType); } void MultiTouchInputMapperTest::processKey( MultiTouchInputMapper* mapper, int32_t code, int32_t value) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); } void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0); } void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processMTSync(mapper); processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processPosition(mapper, x1, y1); processMTSync(mapper); processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // First finger up. x2 += 15; y2 -= 20; processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processMTSync(mapper); processPosition(mapper, x3, y3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Second finger up. x3 += 30; y3 -= 20; processPosition(mapper, x3, y3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Last finger up. processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processId(mapper, 1); processMTSync(mapper); processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processPosition(mapper, x1, y1); processId(mapper, 1); processMTSync(mapper); processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // First finger up. x2 += 15; y2 -= 20; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processPosition(mapper, x3, y3); processId(mapper, 3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Second finger up. x3 += 30; y3 -= 20; processPosition(mapper, x3, y3); processId(mapper, 3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Last finger up. processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processId(mapper, 1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processId(mapper, 2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processSlot(mapper, 0); processPosition(mapper, x1, y1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // First finger up. x2 += 15; y2 -= 20; processSlot(mapper, 0); processId(mapper, -1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processSlot(mapper, 0); processId(mapper, 3); processPosition(mapper, x3, y3); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Second finger up. x3 += 30; y3 -= 20; processSlot(mapper, 1); processId(mapper, -1); processSlot(mapper, 0); processPosition(mapper, x3, y3); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Last finger up. processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 7; int32_t rawTouchMinor = 6; int32_t rawToolMajor = 9; int32_t rawToolMinor = 8; int32_t rawPressure = 11; int32_t rawDistance = 0; int32_t rawOrientation = 3; int32_t id = 5; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) / RAW_PRESSURE_MAX; float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2; float distance = float(rawDistance); processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processTouchMinor(mapper, rawTouchMinor); processToolMajor(mapper, rawToolMajor); processToolMinor(mapper, rawToolMinor); processPressure(mapper, rawPressure); processOrientation(mapper, rawOrientation); processDistance(mapper, rawDistance); processId(mapper, id); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, orientation, distance)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); addConfigurationProperty("touch.size.calibration", "geometric"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 140; int32_t rawTouchMinor = 120; int32_t rawToolMajor = 180; int32_t rawToolMinor = 160; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processTouchMinor(mapper, rawTouchMinor); processToolMajor(mapper, rawToolMajor); processToolMinor(mapper, rawToolMinor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touchMajor, touchMinor, toolMajor, toolMinor, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "diameter"); addConfigurationProperty("touch.size.scale", "10"); addConfigurationProperty("touch.size.bias", "160"); addConfigurationProperty("touch.size.isSummed", "1"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. // Note: We only provide a single common touch/tool value because the device is assumed // not to emit separate values for each pointer (isSummed = 1). int32_t rawX = 100; int32_t rawY = 200; int32_t rawX2 = 150; int32_t rawY2 = 250; int32_t rawTouchMajor = 5; int32_t rawToolMajor = 8; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float x2 = toDisplayX(rawX2); float y2 = toDisplayY(rawY2); float size = float(rawTouchMajor) / 2 / RAW_TOUCH_MAX; float touch = float(rawTouchMajor) / 2 * 10.0f + 160.0f; float tool = float(rawToolMajor) / 2 * 10.0f + 160.0f; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processPosition(mapper, rawX2, rawY2); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), args.action); ASSERT_EQ(size_t(2), args.pointerCount); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1], x2, y2, 1.0f, size, touch, touch, tool, tool, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "area"); addConfigurationProperty("touch.size.scale", "43"); addConfigurationProperty("touch.size.bias", "3"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 5; int32_t rawToolMajor = 8; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float size = float(rawTouchMajor) / RAW_TOUCH_MAX; float touch = sqrtf(rawTouchMajor) * 43.0f + 3.0f; float tool = sqrtf(rawToolMajor) * 43.0f + 3.0f; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | PRESSURE); addConfigurationProperty("touch.pressure.calibration", "amplitude"); addConfigurationProperty("touch.pressure.scale", "0.01"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawPressure = 60; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) * 0.01f; processPosition(mapper, rawX, rawY); processPressure(mapper, rawPressure); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); // press BTN_LEFT, release BTN_LEFT processKey(mapper, BTN_LEFT, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); processKey(mapper, BTN_LEFT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE processKey(mapper, BTN_RIGHT, 1); processKey(mapper, BTN_MIDDLE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_RIGHT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_MIDDLE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_BACK, release BTN_BACK processKey(mapper, BTN_BACK, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_BACK, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE processKey(mapper, BTN_SIDE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_SIDE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD processKey(mapper, BTN_FORWARD, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_FORWARD, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA processKey(mapper, BTN_EXTRA, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_EXTRA, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_STYLUS, release BTN_STYLUS processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_STYLUS2, release BTN_STYLUS2 processKey(mapper, BTN_STYLUS2, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS2, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // release touch processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // default tool type is finger processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_BRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); processKey(mapper, BTN_TOOL_PENCIL, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // airbrush processKey(mapper, BTN_TOOL_PENCIL, 0); processKey(mapper, BTN_TOOL_AIRBRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_LENS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_DOUBLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); processKey(mapper, BTN_TOOL_TRIPLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); processKey(mapper, BTN_TOOL_QUADTAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_FINGER processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_PEN processToolType(mapper, MT_TOOL_PEN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // back to default tool type processToolType(mapper, -1); // use a deliberately undefined tool type, for testing processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processPosition(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when BTN_TOUCH is pressed, pressure defaults to 1 processKey(mapper, BTN_TOUCH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when BTN_TOUCH is released, hover restored processKey(mapper, BTN_TOUCH, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because pressure is 0 processId(mapper, 1); processPosition(mapper, 100, 200); processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processPosition(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when pressure becomes non-zero processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when pressure becomes 0, hover restored processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } } // namespace android services/powermanager/0040755 0000000 0000000 00000000000 13077405420 014124 5ustar000000000 0000000 services/powermanager/Android.mk0100644 0000000 0000000 00000000556 13077405420 016040 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ IPowerManager.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder LOCAL_MODULE:= libpowermanager LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../../include include $(BUILD_SHARED_LIBRARY) services/powermanager/IPowerManager.cpp0100644 0000000 0000000 00000011571 13077405420 017332 0ustar000000000 0000000 /* * 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. */ #define LOG_TAG "IPowerManager" //#define LOG_NDEBUG 0 #include #include #include #include #include namespace android { class BpPowerManager : public BpInterface { public: BpPowerManager(const sp& impl) : BpInterface(impl) { } virtual status_t acquireWakeLock(int flags, const sp& lock, const String16& tag, const String16& packageName, bool isOneWay) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeStrongBinder(lock); data.writeInt32(flags); data.writeString16(tag); data.writeString16(packageName); data.writeInt32(0); // no WorkSource data.writeString16(NULL, 0); // no history tag return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply, isOneWay ? IBinder::FLAG_ONEWAY : 0); } virtual status_t acquireWakeLockWithUid(int flags, const sp& lock, const String16& tag, const String16& packageName, int uid, bool isOneWay) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeStrongBinder(lock); data.writeInt32(flags); data.writeString16(tag); data.writeString16(packageName); data.writeInt32(uid); // uid to blame for the work return remote()->transact(ACQUIRE_WAKE_LOCK_UID, data, &reply, isOneWay ? IBinder::FLAG_ONEWAY : 0); } virtual status_t releaseWakeLock(const sp& lock, int flags, bool isOneWay) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeStrongBinder(lock); data.writeInt32(flags); return remote()->transact(RELEASE_WAKE_LOCK, data, &reply, isOneWay ? IBinder::FLAG_ONEWAY : 0); } virtual status_t updateWakeLockUids(const sp& lock, int len, const int *uids, bool isOneWay) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeStrongBinder(lock); data.writeInt32Array(len, uids); return remote()->transact(UPDATE_WAKE_LOCK_UIDS, data, &reply, isOneWay ? IBinder::FLAG_ONEWAY : 0); } virtual status_t powerHint(int hintId, int param) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeInt32(hintId); data.writeInt32(param); // This FLAG_ONEWAY is in the .aidl, so there is no way to disable it return remote()->transact(POWER_HINT, data, &reply, IBinder::FLAG_ONEWAY); } virtual status_t goToSleep(int64_t event_time_ms, int reason, int flags) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeInt64(event_time_ms); data.writeInt32(reason); data.writeInt32(flags); return remote()->transact(GO_TO_SLEEP, data, &reply, 0); } virtual status_t reboot(bool confirm, const String16& reason, bool wait) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeInt32(confirm); data.writeString16(reason); data.writeInt32(wait); return remote()->transact(REBOOT, data, &reply, 0); } virtual status_t shutdown(bool confirm, const String16& reason, bool wait) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeInt32(confirm); data.writeString16(reason); data.writeInt32(wait); return remote()->transact(SHUTDOWN, data, &reply, 0); } virtual status_t crash(const String16& message) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); data.writeString16(message); return remote()->transact(CRASH, data, &reply, 0); } }; IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager"); // ---------------------------------------------------------------------------- }; // namespace android services/sensorservice/0040755 0000000 0000000 00000000000 13077405420 014327 5ustar000000000 0000000 services/sensorservice/Android.mk0100644 0000000 0000000 00000002302 13077405420 016232 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BatteryService.cpp \ CorrectedGyroSensor.cpp \ Fusion.cpp \ GravitySensor.cpp \ LinearAccelerationSensor.cpp \ OrientationSensor.cpp \ RecentEventLogger.cpp \ RotationVectorSensor.cpp \ SensorDevice.cpp \ SensorEventConnection.cpp \ SensorFusion.cpp \ SensorInterface.cpp \ SensorList.cpp \ SensorRecord.cpp \ SensorService.cpp \ SensorServiceUtils.cpp \ LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" LOCAL_CFLAGS += -Wall -Werror -Wextra LOCAL_CFLAGS += -fvisibility=hidden LOCAL_SHARED_LIBRARIES := \ libcutils \ libhardware \ libhardware_legacy \ libutils \ liblog \ libbinder \ libui \ libgui \ libcrypto LOCAL_MODULE:= libsensorservice include $(BUILD_SHARED_LIBRARY) ##################################################################### # build executable include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ main_sensorservice.cpp LOCAL_SHARED_LIBRARIES := \ libsensorservice \ libbinder \ libutils LOCAL_CFLAGS := -Wall -Werror -Wextra LOCAL_MODULE_TAGS := optional LOCAL_MODULE:= sensorservice include $(BUILD_EXECUTABLE) services/sensorservice/BatteryService.cpp0100644 0000000 0000000 00000006356 13077405420 017775 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include #include #include #include #include #include "BatteryService.h" namespace android { // --------------------------------------------------------------------------- BatteryService::BatteryService() { const sp sm(defaultServiceManager()); if (sm != NULL) { const String16 name("batterystats"); mBatteryStatService = interface_cast(sm->getService(name)); } } bool BatteryService::addSensor(uid_t uid, int handle) { Mutex::Autolock _l(mActivationsLock); Info key(uid, handle); ssize_t index = mActivations.indexOf(key); if (index < 0) { index = mActivations.add(key); } Info& info(mActivations.editItemAt(index)); info.count++; return info.count == 1; } bool BatteryService::removeSensor(uid_t uid, int handle) { Mutex::Autolock _l(mActivationsLock); ssize_t index = mActivations.indexOf(Info(uid, handle)); if (index < 0) return false; Info& info(mActivations.editItemAt(index)); info.count--; return info.count == 0; } void BatteryService::enableSensorImpl(uid_t uid, int handle) { if (mBatteryStatService != 0) { if (addSensor(uid, handle)) { int64_t identity = IPCThreadState::self()->clearCallingIdentity(); mBatteryStatService->noteStartSensor(uid, handle); IPCThreadState::self()->restoreCallingIdentity(identity); } } } void BatteryService::disableSensorImpl(uid_t uid, int handle) { if (mBatteryStatService != 0) { if (removeSensor(uid, handle)) { int64_t identity = IPCThreadState::self()->clearCallingIdentity(); mBatteryStatService->noteStopSensor(uid, handle); IPCThreadState::self()->restoreCallingIdentity(identity); } } } void BatteryService::cleanupImpl(uid_t uid) { if (mBatteryStatService != 0) { Mutex::Autolock _l(mActivationsLock); int64_t identity = IPCThreadState::self()->clearCallingIdentity(); for (size_t i=0 ; inoteStopSensor(info.uid, info.handle); mActivations.removeAt(i); i--; } } IPCThreadState::self()->restoreCallingIdentity(identity); } } ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService) // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/BatteryService.h0100644 0000000 0000000 00000004107 13077405420 017432 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include namespace android { // --------------------------------------------------------------------------- class BatteryService : public Singleton { friend class Singleton; sp mBatteryStatService; BatteryService(); void enableSensorImpl(uid_t uid, int handle); void disableSensorImpl(uid_t uid, int handle); void cleanupImpl(uid_t uid); struct Info { uid_t uid; int handle; int32_t count; Info() : uid(0), handle(0), count(0) { } Info(uid_t uid, int handle) : uid(uid), handle(handle), count(0) { } bool operator < (const Info& rhs) const { return (uid == rhs.uid) ? (handle < rhs.handle) : (uid < rhs.uid); } }; Mutex mActivationsLock; SortedVector mActivations; bool addSensor(uid_t uid, int handle); bool removeSensor(uid_t uid, int handle); public: static void enableSensor(uid_t uid, int handle) { BatteryService::getInstance().enableSensorImpl(uid, handle); } static void disableSensor(uid_t uid, int handle) { BatteryService::getInstance().disableSensorImpl(uid, handle); } static void cleanup(uid_t uid) { BatteryService::getInstance().cleanupImpl(uid); } }; // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/CorrectedGyroSensor.cpp0100644 0000000 0000000 00000005046 13077405420 021002 0ustar000000000 0000000 /* * 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 #include #include #include #include #include "CorrectedGyroSensor.h" #include "SensorDevice.h" #include "SensorFusion.h" namespace android { // --------------------------------------------------------------------------- CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count) : VirtualSensor() { for (size_t i=0 ; idata[0] -= bias.x; outEvent->data[1] -= bias.y; outEvent->data[2] -= bias.z; outEvent->sensor = '_cgy'; return true; } return false; } status_t CorrectedGyroSensor::activate(void* ident, bool enabled) { mSensorDevice.activate(ident, mGyro.getHandle(), enabled); return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t CorrectedGyroSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { mSensorDevice.setDelay(ident, mGyro.getHandle(), ns); return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/CorrectedGyroSensor.h0100644 0000000 0000000 00000003012 13077405420 020436 0ustar000000000 0000000 /* * 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_CORRECTED_GYRO_SENSOR_H #define ANDROID_CORRECTED_GYRO_SENSOR_H #include #include #include #include "SensorInterface.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion; class CorrectedGyroSensor : public VirtualSensor { Sensor mGyro; public: CorrectedGyroSensor(sensor_t const* list, size_t count); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override; virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_CORRECTED_GYRO_SENSOR_H services/sensorservice/Fusion.cpp0100644 0000000 0000000 00000037160 13077405420 016302 0ustar000000000 0000000 /* * 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 #include #include "Fusion.h" namespace android { // ----------------------------------------------------------------------- /*==================== BEGIN FUSION SENSOR PARAMETER =========================*/ /* Note: * If a platform uses software fusion, it is necessary to tune the following * parameters to fit the hardware sensors prior to release. * * The DEFAULT_ parameters will be used in FUSION_9AXIS and FUSION_NOMAG mode. * The GEOMAG_ parameters will be used in FUSION_NOGYRO mode. */ /* * GYRO_VAR gives the measured variance of the gyro's output per * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro, * which is independent of the sampling frequency. * * The variance of gyro's output at a given sampling period can be * calculated as: * variance(T) = GYRO_VAR / T * * The variance of the INTEGRATED OUTPUT at a given sampling period can be * calculated as: * variance_integrate_output(T) = GYRO_VAR * T */ static const float DEFAULT_GYRO_VAR = 1e-7; // (rad/s)^2 / Hz static const float DEFAULT_GYRO_BIAS_VAR = 1e-12; // (rad/s)^2 / s (guessed) static const float GEOMAG_GYRO_VAR = 1e-4; // (rad/s)^2 / Hz static const float GEOMAG_GYRO_BIAS_VAR = 1e-8; // (rad/s)^2 / s (guessed) /* * Standard deviations of accelerometer and magnetometer */ static const float DEFAULT_ACC_STDEV = 0.015f; // m/s^2 (measured 0.08 / CDD 0.05) static const float DEFAULT_MAG_STDEV = 0.1f; // uT (measured 0.7 / CDD 0.5) static const float GEOMAG_ACC_STDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) static const float GEOMAG_MAG_STDEV = 0.1f; // uT (measured 0.7 / CDD 0.5) /* ====================== END FUSION SENSOR PARAMETER ========================*/ static const float SYMMETRY_TOLERANCE = 1e-10f; /* * Accelerometer updates will not be performed near free fall to avoid * ill-conditioning and div by zeros. * Threshhold: 10% of g, in m/s^2 */ static const float NOMINAL_GRAVITY = 9.81f; static const float FREE_FALL_THRESHOLD = 0.1f * (NOMINAL_GRAVITY); /* * The geomagnetic-field should be between 30uT and 60uT. * Fields strengths greater than this likely indicate a local magnetic * disturbance which we do not want to update into the fused frame. */ static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT static const float MAX_VALID_MAGNETIC_FIELD_SQ = MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD; /* * Values of the field smaller than this should be ignored in fusion to avoid * ill-conditioning. This state can happen with anomalous local magnetic * disturbances canceling the Earth field. */ static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT static const float MIN_VALID_MAGNETIC_FIELD_SQ = MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD; /* * If the cross product of two vectors has magnitude squared less than this, * we reject it as invalid due to alignment of the vectors. * This threshold is used to check for the case where the magnetic field sample * is parallel to the gravity field, which can happen in certain places due * to magnetic field disturbances. */ static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3; static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ = MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG; static const float SQRT_3 = 1.732f; static const float WVEC_EPS = 1e-4f/SQRT_3; // ----------------------------------------------------------------------- template static mat scaleCovariance( const mat& A, const mat& P) { // A*P*transpose(A); mat APAt; for (size_t r=0 ; r static mat crossMatrix(const vec& p, OTHER_TYPE diag) { mat r; r[0][0] = diag; r[1][1] = diag; r[2][2] = diag; r[0][1] = p.z; r[1][0] =-p.z; r[0][2] =-p.y; r[2][0] = p.y; r[1][2] = p.x; r[2][1] =-p.x; return r; } template class Covariance { mat mSumXX; vec mSumX; size_t mN; public: Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { } void update(const vec& x) { mSumXX += x*transpose(x); mSumX += x; mN++; } mat operator()() const { const float N = 1.0f / mN; return mSumXX*N - (mSumX*transpose(mSumX))*(N*N); } void reset() { mN = 0; mSumXX = 0; mSumX = 0; } size_t getCount() const { return mN; } }; // ----------------------------------------------------------------------- Fusion::Fusion() { Phi[0][1] = 0; Phi[1][1] = 1; Ba.x = 0; Ba.y = 0; Ba.z = 1; Bm.x = 0; Bm.y = 1; Bm.z = 0; x0 = 0; x1 = 0; init(); } void Fusion::init(int mode) { mInitState = 0; mGyroRate = 0; mCount[0] = 0; mCount[1] = 0; mCount[2] = 0; mData = 0; mMode = mode; if (mMode != FUSION_NOGYRO) { //normal or game rotation mParam.gyroVar = DEFAULT_GYRO_VAR; mParam.gyroBiasVar = DEFAULT_GYRO_BIAS_VAR; mParam.accStdev = DEFAULT_ACC_STDEV; mParam.magStdev = DEFAULT_MAG_STDEV; } else { mParam.gyroVar = GEOMAG_GYRO_VAR; mParam.gyroBiasVar = GEOMAG_GYRO_BIAS_VAR; mParam.accStdev = GEOMAG_ACC_STDEV; mParam.magStdev = GEOMAG_MAG_STDEV; } } void Fusion::initFusion(const vec4_t& q, float dT) { // initial estimate: E{ x(t0) } x0 = q; x1 = 0; // process noise covariance matrix: G.Q.Gt, with // // G = | -1 0 | Q = | q00 q10 | // | 0 1 | | q01 q11 | // // q00 = sv^2.dt + 1/3.su^2.dt^3 // q10 = q01 = 1/2.su^2.dt^2 // q11 = su^2.dt // const float dT2 = dT*dT; const float dT3 = dT2*dT; // variance of integrated output at 1/dT Hz (random drift) const float q00 = mParam.gyroVar * dT + 0.33333f * mParam.gyroBiasVar * dT3; // variance of drift rate ramp const float q11 = mParam.gyroBiasVar * dT; const float q10 = 0.5f * mParam.gyroBiasVar * dT2; const float q01 = q10; GQGt[0][0] = q00; // rad^2 GQGt[1][0] = -q10; GQGt[0][1] = -q01; GQGt[1][1] = q11; // (rad/s)^2 // initial covariance: Var{ x(t0) } // TODO: initialize P correctly P = 0; } bool Fusion::hasEstimate() const { return ((mInitState & MAG) || (mMode == FUSION_NOMAG)) && ((mInitState & GYRO) || (mMode == FUSION_NOGYRO)) && (mInitState & ACC); } bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) { if (hasEstimate()) return true; if (what == ACC) { mData[0] += d * (1/length(d)); mCount[0]++; mInitState |= ACC; if (mMode == FUSION_NOGYRO ) { mGyroRate = dT; } } else if (what == MAG) { mData[1] += d * (1/length(d)); mCount[1]++; mInitState |= MAG; } else if (what == GYRO) { mGyroRate = dT; mData[2] += d*dT; mCount[2]++; mInitState |= GYRO; } if (hasEstimate()) { // Average all the values we collected so far mData[0] *= 1.0f/mCount[0]; if (mMode != FUSION_NOMAG) { mData[1] *= 1.0f/mCount[1]; } mData[2] *= 1.0f/mCount[2]; // calculate the MRPs from the data collection, this gives us // a rough estimate of our initial state mat33_t R; vec3_t up(mData[0]); vec3_t east; if (mMode != FUSION_NOMAG) { east = normalize(cross_product(mData[1], up)); } else { east = getOrthogonal(up); } vec3_t north(cross_product(up, east)); R << east << north << up; const vec4_t q = matrixToQuat(R); initFusion(q, mGyroRate); } return false; } void Fusion::handleGyro(const vec3_t& w, float dT) { if (!checkInitComplete(GYRO, w, dT)) return; predict(w, dT); } status_t Fusion::handleAcc(const vec3_t& a, float dT) { if (!checkInitComplete(ACC, a, dT)) return BAD_VALUE; // ignore acceleration data if we're close to free-fall const float l = length(a); if (l < FREE_FALL_THRESHOLD) { return BAD_VALUE; } const float l_inv = 1.0f/l; if ( mMode == FUSION_NOGYRO ) { //geo mag vec3_t w_dummy; w_dummy = x1; //bias predict(w_dummy, dT); } if ( mMode == FUSION_NOMAG) { vec3_t m; m = getRotationMatrix()*Bm; update(m, Bm, mParam.magStdev); } vec3_t unityA = a * l_inv; const float d = sqrtf(fabsf(l- NOMINAL_GRAVITY)); const float p = l_inv * mParam.accStdev*expf(d); update(unityA, Ba, p); return NO_ERROR; } status_t Fusion::handleMag(const vec3_t& m) { if (!checkInitComplete(MAG, m)) return BAD_VALUE; // the geomagnetic-field should be between 30uT and 60uT // reject if too large to avoid spurious magnetic sources const float magFieldSq = length_squared(m); if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) { return BAD_VALUE; } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) { // Also reject if too small since we will get ill-defined (zero mag) // cross-products below return BAD_VALUE; } // Orthogonalize the magnetic field to the gravity field, mapping it into // tangent to Earth. const vec3_t up( getRotationMatrix() * Ba ); const vec3_t east( cross_product(m, up) ); // If the m and up vectors align, the cross product magnitude will // approach 0. // Reject this case as well to avoid div by zero problems and // ill-conditioning below. if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) { return BAD_VALUE; } // If we have created an orthogonal magnetic field successfully, // then pass it in as the update. vec3_t north( cross_product(up, east) ); const float l_inv = 1 / length(north); north *= l_inv; update(north, Bm, mParam.magStdev*l_inv); return NO_ERROR; } void Fusion::checkState() { // P needs to stay positive semidefinite or the fusion diverges. When we // detect divergence, we reset the fusion. // TODO(braun): Instead, find the reason for the divergence and fix it. if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) || !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) { ALOGW("Sensor fusion diverged; resetting state."); P = 0; } } vec4_t Fusion::getAttitude() const { return x0; } vec3_t Fusion::getBias() const { return x1; } mat33_t Fusion::getRotationMatrix() const { return quatToMatrix(x0); } mat34_t Fusion::getF(const vec4_t& q) { mat34_t F; // This is used to compute the derivative of q // F = | [q.xyz]x | // | -q.xyz | F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y; F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x; F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w; F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z; return F; } void Fusion::predict(const vec3_t& w, float dT) { const vec4_t q = x0; const vec3_t b = x1; vec3_t we = w - b; if (length(we) < WVEC_EPS) { we = (we[0]>0.f)?WVEC_EPS:-WVEC_EPS; } // q(k+1) = O(we)*q(k) // -------------------- // // O(w) = | cos(0.5*||w||*dT)*I33 - [psi]x psi | // | -psi' cos(0.5*||w||*dT) | // // psi = sin(0.5*||w||*dT)*w / ||w|| // // // P(k+1) = Phi(k)*P(k)*Phi(k)' + G*Q(k)*G' // ---------------------------------------- // // G = | -I33 0 | // | 0 I33 | // // Phi = | Phi00 Phi10 | // | 0 1 | // // Phi00 = I33 // - [w]x * sin(||w||*dt)/||w|| // + [w]x^2 * (1-cos(||w||*dT))/||w||^2 // // Phi10 = [w]x * (1 - cos(||w||*dt))/||w||^2 // - [w]x^2 * (||w||*dT - sin(||w||*dt))/||w||^3 // - I33*dT const mat33_t I33(1); const mat33_t I33dT(dT); const mat33_t wx(crossMatrix(we, 0)); const mat33_t wx2(wx*wx); const float lwedT = length(we)*dT; const float hlwedT = 0.5f*lwedT; const float ilwe = 1.f/length(we); const float k0 = (1-cosf(lwedT))*(ilwe*ilwe); const float k1 = sinf(lwedT); const float k2 = cosf(hlwedT); const vec3_t psi(sinf(hlwedT)*ilwe*we); const mat33_t O33(crossMatrix(-psi, k2)); mat44_t O; O[0].xyz = O33[0]; O[0].w = -psi.x; O[1].xyz = O33[1]; O[1].w = -psi.y; O[2].xyz = O33[2]; O[2].w = -psi.z; O[3].xyz = psi; O[3].w = k2; Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0; Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1); x0 = O*q; if (x0.w < 0) x0 = -x0; P = Phi*P*transpose(Phi) + GQGt; checkState(); } void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) { vec4_t q(x0); // measured vector in body space: h(p) = A(p)*Bi const mat33_t A(quatToMatrix(q)); const vec3_t Bb(A*Bi); // Sensitivity matrix H = dh(p)/dp // H = [ L 0 ] const mat33_t L(crossMatrix(Bb, 0)); // gain... // K = P*Ht / [H*P*Ht + R] vec K; const mat33_t R(sigma*sigma); const mat33_t S(scaleCovariance(L, P[0][0]) + R); const mat33_t Si(invert(S)); const mat33_t LtSi(transpose(L)*Si); K[0] = P[0][0] * LtSi; K[1] = transpose(P[1][0])*LtSi; // update... // P = (I-K*H) * P // P -= K*H*P // | K0 | * | L 0 | * P = | K0*L 0 | * | P00 P10 | = | K0*L*P00 K0*L*P10 | // | K1 | | K1*L 0 | | P01 P11 | | K1*L*P00 K1*L*P10 | // Note: the Joseph form is numerically more stable and given by: // P = (I-KH) * P * (I-KH)' + K*R*R' const mat33_t K0L(K[0] * L); const mat33_t K1L(K[1] * L); P[0][0] -= K0L*P[0][0]; P[1][1] -= K1L*P[1][0]; P[1][0] -= K0L*P[1][0]; P[0][1] = transpose(P[1][0]); const vec3_t e(z - Bb); const vec3_t dq(K[0]*e); q += getF(q)*(0.5f*dq); x0 = normalize_quat(q); if (mMode != FUSION_NOMAG) { const vec3_t db(K[1]*e); x1 += db; } checkState(); } vec3_t Fusion::getOrthogonal(const vec3_t &v) { vec3_t w; if (fabsf(v[0])<= fabsf(v[1]) && fabsf(v[0]) <= fabsf(v[2])) { w[0]=0.f; w[1] = v[2]; w[2] = -v[1]; } else if (fabsf(v[1]) <= fabsf(v[2])) { w[0] = v[2]; w[1] = 0.f; w[2] = -v[0]; }else { w[0] = v[1]; w[1] = -v[0]; w[2] = 0.f; } return normalize(w); } // ----------------------------------------------------------------------- }; // namespace android services/sensorservice/Fusion.h0100644 0000000 0000000 00000005221 13077405420 015740 0ustar000000000 0000000 /* * 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_FUSION_H #define ANDROID_FUSION_H #include #include "quat.h" #include "mat.h" #include "vec.h" namespace android { typedef mat mat34_t; enum FUSION_MODE{ FUSION_9AXIS, // use accel gyro mag FUSION_NOMAG, // use accel gyro (game rotation, gravity) FUSION_NOGYRO, // use accel mag (geomag rotation) NUM_FUSION_MODE }; class Fusion { /* * the state vector is made of two sub-vector containing respectively: * - modified Rodrigues parameters * - the estimated gyro bias */ quat_t x0; vec3_t x1; /* * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is * semi-definite positive. * * P = | P00 P10 | = | P00 P10 | * | P01 P11 | | P10t P11 | * * Since P01 = transpose(P10), the code below never calculates or * stores P01. */ mat P; /* * the process noise covariance matrix */ mat GQGt; public: Fusion(); void init(int mode = FUSION_9AXIS); void handleGyro(const vec3_t& w, float dT); status_t handleAcc(const vec3_t& a, float dT); status_t handleMag(const vec3_t& m); vec4_t getAttitude() const; vec3_t getBias() const; mat33_t getRotationMatrix() const; bool hasEstimate() const; private: struct Parameter { float gyroVar; float gyroBiasVar; float accStdev; float magStdev; } mParam; mat Phi; vec3_t Ba, Bm; uint32_t mInitState; float mGyroRate; vec mData; size_t mCount[3]; int mMode; enum { ACC=0x1, MAG=0x2, GYRO=0x4 }; bool checkInitComplete(int, const vec3_t& w, float d = 0); void initFusion(const vec4_t& q0, float dT); void checkState(); void predict(const vec3_t& w, float dT); void update(const vec3_t& z, const vec3_t& Bi, float sigma); static mat34_t getF(const vec4_t& p); static vec3_t getOrthogonal(const vec3_t &v); }; }; // namespace android #endif // ANDROID_FUSION_H services/sensorservice/GravitySensor.cpp0100644 0000000 0000000 00000005344 13077405420 017655 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include "GravitySensor.h" #include "SensorDevice.h" #include "SensorFusion.h" namespace android { // --------------------------------------------------------------------------- GravitySensor::GravitySensor(sensor_t const* list, size_t count) { for (size_t i=0 ; idata[0] = g.x; outEvent->data[1] = g.y; outEvent->data[2] = g.z; outEvent->sensor = '_grv'; outEvent->type = SENSOR_TYPE_GRAVITY; return true; } return false; } status_t GravitySensor::activate(void* ident, bool enabled) { return mSensorFusion.activate(FUSION_NOMAG, ident, enabled); } status_t GravitySensor::setDelay(void* ident, int /*handle*/, int64_t ns) { return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/GravitySensor.h0100644 0000000 0000000 00000002762 13077405420 017323 0ustar000000000 0000000 /* * Copyright (C) 2010 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_GRAVITY_SENSOR_H #define ANDROID_GRAVITY_SENSOR_H #include #include #include #include "SensorInterface.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion; class GravitySensor : public VirtualSensor { Sensor mAccelerometer; public: GravitySensor(sensor_t const* list, size_t count); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override; virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_GRAVITY_SENSOR_H services/sensorservice/LinearAccelerationSensor.cpp0100644 0000000 0000000 00000004743 13077405420 021756 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include "LinearAccelerationSensor.h" #include "SensorDevice.h" #include "SensorFusion.h" namespace android { // --------------------------------------------------------------------------- LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count) : mGravitySensor(list, count) { const Sensor &gsensor = mGravitySensor.getSensor(); const sensor_t sensor = { .name = "Linear Acceleration Sensor", .vendor = "AOSP", .version = gsensor.getVersion(), .handle = '_lin', .type = SENSOR_TYPE_LINEAR_ACCELERATION, .maxRange = gsensor.getMaxValue(), .resolution = gsensor.getResolution(), .power = gsensor.getPowerUsage(), .minDelay = gsensor.getMinDelay(), }; mSensor = Sensor(&sensor); } bool LinearAccelerationSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { bool result = mGravitySensor.process(outEvent, event); if (result && event.type == SENSOR_TYPE_ACCELEROMETER) { outEvent->data[0] = event.acceleration.x - outEvent->data[0]; outEvent->data[1] = event.acceleration.y - outEvent->data[1]; outEvent->data[2] = event.acceleration.z - outEvent->data[2]; outEvent->sensor = '_lin'; outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION; return true; } return false; } status_t LinearAccelerationSensor::activate(void* ident, bool enabled) { return mGravitySensor.activate(ident, enabled); } status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) { return mGravitySensor.setDelay(ident, handle, ns); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/LinearAccelerationSensor.h0100644 0000000 0000000 00000003121 13077405420 021410 0ustar000000000 0000000 /* * Copyright (C) 2010 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_LINEAR_ACCELERATION_SENSOR_H #define ANDROID_LINEAR_ACCELERATION_SENSOR_H #include #include #include #include "SensorInterface.h" #include "GravitySensor.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion; class LinearAccelerationSensor : public VirtualSensor { GravitySensor mGravitySensor; virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event); public: LinearAccelerationSensor(sensor_t const* list, size_t count); virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H services/sensorservice/OrientationSensor.cpp0100644 0000000 0000000 00000005301 13077405420 020514 0ustar000000000 0000000 /* * 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 #include #include #include #include #include "OrientationSensor.h" #include "SensorDevice.h" #include "SensorFusion.h" namespace android { // --------------------------------------------------------------------------- OrientationSensor::OrientationSensor() { const sensor_t sensor = { .name = "Orientation Sensor", .vendor = "AOSP", .version = 1, .handle = '_ypr', .type = SENSOR_TYPE_ORIENTATION, .maxRange = 360.0f, .resolution = 1.0f/256.0f, // FIXME: real value here .power = mSensorFusion.getPowerUsage(), .minDelay = mSensorFusion.getMinDelay(), }; mSensor = Sensor(&sensor); } bool OrientationSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { if (event.type == SENSOR_TYPE_ACCELEROMETER) { if (mSensorFusion.hasEstimate()) { vec3_t g; const float rad2deg = 180 / M_PI; const mat33_t R(mSensorFusion.getRotationMatrix()); g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg; g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg; g[2] = asinf ( R[2][0]) * rad2deg; if (g[0] < 0) g[0] += 360; *outEvent = event; outEvent->orientation.azimuth = g.x; outEvent->orientation.pitch = g.y; outEvent->orientation.roll = g.z; outEvent->orientation.status = SENSOR_STATUS_ACCURACY_HIGH; outEvent->sensor = '_ypr'; outEvent->type = SENSOR_TYPE_ORIENTATION; return true; } } return false; } status_t OrientationSensor::activate(void* ident, bool enabled) { return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t OrientationSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/OrientationSensor.h0100644 0000000 0000000 00000002710 13077405420 020162 0ustar000000000 0000000 /* * 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_ORIENTATION_SENSOR_H #define ANDROID_ORIENTATION_SENSOR_H #include #include #include #include "SensorInterface.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion; class OrientationSensor : public VirtualSensor { public: OrientationSensor(); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override; virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_ORIENTATION_SENSOR_H services/sensorservice/RecentEventLogger.cpp0100644 0000000 0000000 00000006173 13077405420 020421 0ustar000000000 0000000 /* * Copyright (C) 2016 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 "RecentEventLogger.h" #include "SensorServiceUtils.h" #include #include namespace android { namespace SensorServiceUtil { namespace { constexpr size_t LOG_SIZE = 10; constexpr size_t LOG_SIZE_LARGE = 50; // larger samples for debugging }// unnamed namespace RecentEventLogger::RecentEventLogger(int sensorType) : mSensorType(sensorType), mEventSize(eventSizeBySensorType(mSensorType)), mRecentEvents(logSizeBySensorType(sensorType)) { // blank } void RecentEventLogger::addEvent(const sensors_event_t& event) { std::lock_guard lk(mLock); mRecentEvents.emplace(event); } bool RecentEventLogger::isEmpty() const { return mRecentEvents.size() == 0; } std::string RecentEventLogger::dump() const { std::lock_guard lk(mLock); //TODO: replace String8 with std::string completely in this function String8 buffer; buffer.appendFormat("last %zu events\n", mRecentEvents.size()); int j = 0; for (int i = mRecentEvents.size() - 1; i >= 0; --i) { const auto& ev = mRecentEvents[i]; struct tm * timeinfo = localtime(&(ev.mWallTime.tv_sec)); buffer.appendFormat("\t%2d (ts=%.9f, wall=%02d:%02d:%02d.%03d) ", ++j, ev.mEvent.timestamp/1e9, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, (int) ns2ms(ev.mWallTime.tv_nsec)); // data if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { buffer.appendFormat("%" PRIu64 ", ", ev.mEvent.u64.step_counter); } else { for (size_t k = 0; k < mEventSize; ++k) { buffer.appendFormat("%.2f, ", ev.mEvent.data[k]); } } buffer.append("\n"); } return std::string(buffer.string()); } bool RecentEventLogger::populateLastEvent(sensors_event_t *event) const { std::lock_guard lk(mLock); if (mRecentEvents.size()) { // Index 0 contains the latest event emplace()'ed *event = mRecentEvents[0].mEvent; return true; } else { return false; } } size_t RecentEventLogger::logSizeBySensorType(int sensorType) { return (sensorType == SENSOR_TYPE_STEP_COUNTER || sensorType == SENSOR_TYPE_SIGNIFICANT_MOTION || sensorType == SENSOR_TYPE_ACCELEROMETER) ? LOG_SIZE_LARGE : LOG_SIZE; } RecentEventLogger::SensorEventLog::SensorEventLog(const sensors_event_t& e) : mEvent(e) { clock_gettime(CLOCK_REALTIME, &mWallTime); } } // namespace SensorServiceUtil } // namespace android services/sensorservice/RecentEventLogger.h0100644 0000000 0000000 00000004137 13077405420 020064 0ustar000000000 0000000 /* * Copyright (C) 2016 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_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H #define ANDROID_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H #include "RingBuffer.h" #include "SensorServiceUtils.h" #include #include #include namespace android { namespace SensorServiceUtil { // A circular buffer that record the last N events of a sensor type for debugging. The size of this // buffer depends on sensor type and is controlled by logSizeBySensorType(). The last N events // generated from the sensor are stored in this buffer. The buffer is NOT cleared when the sensor // unregisters and as a result very old data in the dumpsys output can be seen, which is an intended // behavior. class RecentEventLogger : public Dumpable { public: RecentEventLogger(int sensorType); void addEvent(const sensors_event_t& event); bool populateLastEvent(sensors_event_t *event) const; bool isEmpty() const; virtual ~RecentEventLogger() {} // Dumpable interface virtual std::string dump() const override; protected: struct SensorEventLog { SensorEventLog(const sensors_event_t& e); timespec mWallTime; sensors_event_t mEvent; }; const int mSensorType; const size_t mEventSize; mutable std::mutex mLock; RingBuffer mRecentEvents; private: static size_t logSizeBySensorType(int sensorType); }; } // namespace SensorServiceUtil } // namespace android; #endif // ANDROID_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H services/sensorservice/RingBuffer.h0100644 0000000 0000000 00000023413 13077405420 016531 0ustar000000000 0000000 /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H #define ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H #include #include #include #include #include namespace android { namespace SensorServiceUtil { /** * A RingBuffer class that maintains an array of objects that can grow up to a certain size. * Elements added to the RingBuffer are inserted in the logical front of the buffer, and * invalidate all current iterators for that RingBuffer object. */ template class RingBuffer final { public: /** * Construct a RingBuffer that can grow up to the given length. */ RingBuffer(size_t length); /** * Forward iterator to this class. Implements an std:forward_iterator. */ class iterator : public std::iterator { public: iterator(T* ptr, size_t size, size_t pos, size_t ctr); iterator& operator++(); iterator operator++(int); bool operator==(const iterator& rhs); bool operator!=(const iterator& rhs); T& operator*(); T* operator->(); private: T* mPtr; size_t mSize; size_t mPos; size_t mCtr; }; /** * Constant forward iterator to this class. Implements an std:forward_iterator. */ class const_iterator : public std::iterator { public: const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr); const_iterator& operator++(); const_iterator operator++(int); bool operator==(const const_iterator& rhs); bool operator!=(const const_iterator& rhs); const T& operator*(); const T* operator->(); private: const T* mPtr; size_t mSize; size_t mPos; size_t mCtr; }; /** * Adds item to the front of this RingBuffer. If the RingBuffer is at its maximum length, * this will result in the last element being replaced (this is done using the element's * assignment operator). * * All current iterators are invalidated. */ void add(const T& item); /** * Moves item to the front of this RingBuffer. Following a call to this, item should no * longer be used. If the RingBuffer is at its maximum length, this will result in the * last element being replaced (this is done using the element's assignment operator). * * All current iterators are invalidated. */ void add(T&& item); /** * Construct item in-place in the front of this RingBuffer using the given arguments. If * the RingBuffer is at its maximum length, this will result in the last element being * replaced (this is done using the element's assignment operator). * * All current iterators are invalidated. */ template void emplace(Args&&... args); /** * Get an iterator to the front of this RingBuffer. */ iterator begin(); /** * Get an iterator to the end of this RingBuffer. */ iterator end(); /** * Get a const_iterator to the front of this RingBuffer. */ const_iterator begin() const; /** * Get a const_iterator to the end of this RingBuffer. */ const_iterator end() const; /** * Return a reference to the element at a given index. If the index is out of range for * this ringbuffer, [0, size), the behavior for this is undefined. */ T& operator[](size_t index); /** * Return a const reference to the element at a given index. If the index is out of range * for this ringbuffer, [0, size), the behavior for this is undefined. */ const T& operator[](size_t index) const; /** * Return the current size of this RingBuffer. */ size_t size() const; /** * Remove all elements from this RingBuffer and set the size to 0. */ void clear(); private: size_t mFrontIdx; size_t mMaxBufferSize; std::vector mBuffer; }; // class RingBuffer template RingBuffer::RingBuffer(size_t length) : mFrontIdx{0}, mMaxBufferSize{length} {} template RingBuffer::iterator::iterator(T* ptr, size_t size, size_t pos, size_t ctr) : mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {} template typename RingBuffer::iterator& RingBuffer::iterator::operator++() { ++mCtr; if (CC_UNLIKELY(mCtr == mSize)) { mPos = mSize; return *this; } mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1); return *this; } template typename RingBuffer::iterator RingBuffer::iterator::operator++(int) { iterator tmp{mPtr, mSize, mPos, mCtr}; ++(*this); return tmp; } template bool RingBuffer::iterator::operator==(const iterator& rhs) { return (mPtr + mPos) == (rhs.mPtr + rhs.mPos); } template bool RingBuffer::iterator::operator!=(const iterator& rhs) { return (mPtr + mPos) != (rhs.mPtr + rhs.mPos); } template T& RingBuffer::iterator::operator*() { return *(mPtr + mPos); } template T* RingBuffer::iterator::operator->() { return mPtr + mPos; } template RingBuffer::const_iterator::const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr) : mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {} template typename RingBuffer::const_iterator& RingBuffer::const_iterator::operator++() { ++mCtr; if (CC_UNLIKELY(mCtr == mSize)) { mPos = mSize; return *this; } mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1); return *this; } template typename RingBuffer::const_iterator RingBuffer::const_iterator::operator++(int) { const_iterator tmp{mPtr, mSize, mPos, mCtr}; ++(*this); return tmp; } template bool RingBuffer::const_iterator::operator==(const const_iterator& rhs) { return (mPtr + mPos) == (rhs.mPtr + rhs.mPos); } template bool RingBuffer::const_iterator::operator!=(const const_iterator& rhs) { return (mPtr + mPos) != (rhs.mPtr + rhs.mPos); } template const T& RingBuffer::const_iterator::operator*() { return *(mPtr + mPos); } template const T* RingBuffer::const_iterator::operator->() { return mPtr + mPos; } template void RingBuffer::add(const T& item) { if (mBuffer.size() < mMaxBufferSize) { mBuffer.push_back(item); mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); return; } mBuffer[mFrontIdx] = item; mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); } template void RingBuffer::add(T&& item) { if (mBuffer.size() != mMaxBufferSize) { mBuffer.push_back(std::forward(item)); mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); return; } // Only works for types with move assignment operator mBuffer[mFrontIdx] = std::forward(item); mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); } template template void RingBuffer::emplace(Args&&... args) { if (mBuffer.size() != mMaxBufferSize) { mBuffer.emplace_back(std::forward(args)...); mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); return; } // Only works for types with move assignment operator mBuffer[mFrontIdx] = T(std::forward(args)...); mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize); } template typename RingBuffer::iterator RingBuffer::begin() { size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1; return iterator(mBuffer.data(), mBuffer.size(), (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0); } template typename RingBuffer::iterator RingBuffer::end() { size_t s = mBuffer.size(); return iterator(mBuffer.data(), s, s, s); } template typename RingBuffer::const_iterator RingBuffer::begin() const { size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1; return const_iterator(mBuffer.data(), mBuffer.size(), (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0); } template typename RingBuffer::const_iterator RingBuffer::end() const { size_t s = mBuffer.size(); return const_iterator(mBuffer.data(), s, s, s); } template T& RingBuffer::operator[](size_t index) { LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.", index, mBuffer.size()); size_t pos = (index >= mFrontIdx) ? mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index; return mBuffer[pos]; } template const T& RingBuffer::operator[](size_t index) const { LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.", index, mBuffer.size()); size_t pos = (index >= mFrontIdx) ? mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index; return mBuffer[pos]; } template size_t RingBuffer::size() const { return mBuffer.size(); } template void RingBuffer::clear() { mBuffer.clear(); mFrontIdx = 0; } } // namespace SensorServiceUtil }; // namespace android #endif // ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H services/sensorservice/RotationVectorSensor.cpp0100644 0000000 0000000 00000011231 13077405420 021202 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include "RotationVectorSensor.h" namespace android { // --------------------------------------------------------------------------- RotationVectorSensor::RotationVectorSensor(int mode) : mMode(mode) { const sensor_t sensor = { .name = getSensorName(), .vendor = "AOSP", .version = 3, .handle = getSensorToken(), .type = getSensorType(), .maxRange = 1, .resolution = 1.0f / (1<<24), .power = mSensorFusion.getPowerUsage(), .minDelay = mSensorFusion.getMinDelay(), }; mSensor = Sensor(&sensor); } bool RotationVectorSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { if (event.type == SENSOR_TYPE_ACCELEROMETER) { if (mSensorFusion.hasEstimate(mMode)) { const vec4_t q(mSensorFusion.getAttitude(mMode)); *outEvent = event; outEvent->data[0] = q.x; outEvent->data[1] = q.y; outEvent->data[2] = q.z; outEvent->data[3] = q.w; outEvent->sensor = getSensorToken(); outEvent->type = getSensorType(); return true; } } return false; } status_t RotationVectorSensor::activate(void* ident, bool enabled) { return mSensorFusion.activate(mMode, ident, enabled); } status_t RotationVectorSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { return mSensorFusion.setDelay(mMode, ident, ns); } int RotationVectorSensor::getSensorType() const { switch(mMode) { case FUSION_9AXIS: return SENSOR_TYPE_ROTATION_VECTOR; case FUSION_NOMAG: return SENSOR_TYPE_GAME_ROTATION_VECTOR; case FUSION_NOGYRO: return SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR; default: assert(0); return 0; } } const char* RotationVectorSensor::getSensorName() const { switch(mMode) { case FUSION_9AXIS: return "Rotation Vector Sensor"; case FUSION_NOMAG: return "Game Rotation Vector Sensor"; case FUSION_NOGYRO: return "GeoMag Rotation Vector Sensor"; default: assert(0); return NULL; } } int RotationVectorSensor::getSensorToken() const { switch(mMode) { case FUSION_9AXIS: return '_rov'; case FUSION_NOMAG: return '_gar'; case FUSION_NOGYRO: return '_geo'; default: assert(0); return 0; } } // --------------------------------------------------------------------------- GyroDriftSensor::GyroDriftSensor() { const sensor_t sensor = { .name = "Gyroscope Bias (debug)", .vendor = "AOSP", .version = 1, .handle = '_gbs', .type = SENSOR_TYPE_ACCELEROMETER, .maxRange = 1, .resolution = 1.0f / (1<<24), .power = mSensorFusion.getPowerUsage(), .minDelay = mSensorFusion.getMinDelay(), }; mSensor = Sensor(&sensor); } bool GyroDriftSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { if (event.type == SENSOR_TYPE_ACCELEROMETER) { if (mSensorFusion.hasEstimate()) { const vec3_t b(mSensorFusion.getGyroBias()); *outEvent = event; outEvent->data[0] = b.x; outEvent->data[1] = b.y; outEvent->data[2] = b.z; outEvent->sensor = '_gbs'; outEvent->type = SENSOR_TYPE_ACCELEROMETER; return true; } } return false; } status_t GyroDriftSensor::activate(void* ident, bool enabled) { return mSensorFusion.activate(FUSION_9AXIS, ident, enabled); } status_t GyroDriftSensor::setDelay(void* ident, int /*handle*/, int64_t ns) { return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/RotationVectorSensor.h0100644 0000000 0000000 00000004401 13077405420 020650 0ustar000000000 0000000 /* * Copyright (C) 2010 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_ROTATION_VECTOR_SENSOR_H #define ANDROID_ROTATION_VECTOR_SENSOR_H #include #include #include #include "SensorDevice.h" #include "SensorInterface.h" #include "Fusion.h" #include "SensorFusion.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class RotationVectorSensor : public VirtualSensor { public: RotationVectorSensor(int mode = FUSION_9AXIS); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override; virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; protected: const int mMode; int getSensorType() const; const char* getSensorName() const ; int getSensorToken() const ; }; class GameRotationVectorSensor : public RotationVectorSensor { public: GameRotationVectorSensor() : RotationVectorSensor(FUSION_NOMAG) {} }; class GeoMagRotationVectorSensor : public RotationVectorSensor { public: GeoMagRotationVectorSensor() : RotationVectorSensor(FUSION_NOGYRO) {} }; class GyroDriftSensor : public VirtualSensor { public: GyroDriftSensor(); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override; virtual status_t activate(void* ident, bool enabled) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_ROTATION_VECTOR_SENSOR_H services/sensorservice/SensorDevice.cpp0100644 0000000 0000000 00000046147 13077405420 017435 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include #include "SensorDevice.h" #include "SensorService.h" namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice) SensorDevice::SensorDevice() : mSensorDevice(0), mSensorModule(0) { status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&mSensorModule); ALOGE_IF(err, "couldn't load %s module (%s)", SENSORS_HARDWARE_MODULE_ID, strerror(-err)); if (mSensorModule) { err = sensors_open_1(&mSensorModule->common, &mSensorDevice); ALOGE_IF(err, "couldn't open device for module %s (%s)", SENSORS_HARDWARE_MODULE_ID, strerror(-err)); if (mSensorDevice) { if (mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_1 || mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_2) { ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3"); } sensor_t const* list; ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); mActivationCount.setCapacity(count); Info model; for (size_t i=0 ; iactivate( reinterpret_cast(mSensorDevice), list[i].handle, 0); } } } } void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) { if (connected) { Info model; mActivationCount.add(handle, model); mSensorDevice->activate( reinterpret_cast(mSensorDevice), handle, 0); } else { mActivationCount.removeItem(handle); } } std::string SensorDevice::dump() const { if (!mSensorModule) return "HAL not initialized\n"; String8 result; sensor_t const* list; int count = mSensorModule->get_sensors_list(mSensorModule, &list); result.appendFormat("HAL: %s (%s), version %#010x\n", mSensorModule->common.name, mSensorModule->common.author, getHalDeviceVersion()); result.appendFormat("Total %d h/w sensors, %zu running:\n", count, mActivationCount.size()); Mutex::Autolock _l(mLock); for (int i = 0 ; i < count ; i++) { const Info& info = mActivationCount.valueFor(list[i].handle); if (info.batchParams.isEmpty()) continue; result.appendFormat("0x%08x) active-count = %zu; ", list[i].handle, info.batchParams.size()); result.append("sampling_period(ms) = {"); for (size_t j = 0; j < info.batchParams.size(); j++) { const BatchParams& params = info.batchParams.valueAt(j); result.appendFormat("%.1f%s", params.batchDelay / 1e6f, j < info.batchParams.size() - 1 ? ", " : ""); } result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f); result.append("batching_period(ms) = {"); for (size_t j = 0; j < info.batchParams.size(); j++) { BatchParams params = info.batchParams.valueAt(j); result.appendFormat("%.1f%s", params.batchTimeout / 1e6f, j < info.batchParams.size() - 1 ? ", " : ""); } result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f); } return result.string(); } ssize_t SensorDevice::getSensorList(sensor_t const** list) { if (!mSensorModule) return NO_INIT; ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list); return count; } status_t SensorDevice::initCheck() const { return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT; } ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { if (!mSensorDevice) return NO_INIT; ssize_t c; do { c = mSensorDevice->poll(reinterpret_cast (mSensorDevice), buffer, count); } while (c == -EINTR); return c; } void SensorDevice::autoDisable(void *ident, int handle) { Info& info( mActivationCount.editValueFor(handle) ); Mutex::Autolock _l(mLock); info.removeBatchParamsForIdent(ident); } status_t SensorDevice::activate(void* ident, int handle, int enabled) { if (!mSensorDevice) return NO_INIT; status_t err(NO_ERROR); bool actuateHardware = false; Mutex::Autolock _l(mLock); Info& info( mActivationCount.editValueFor(handle) ); ALOGD_IF(DEBUG_CONNECTIONS, "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", ident, handle, enabled, info.batchParams.size()); if (enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident)); if (isClientDisabledLocked(ident)) { return INVALID_OPERATION; } if (info.batchParams.indexOfKey(ident) >= 0) { if (info.numActiveClients() == 1) { // This is the first connection, we need to activate the underlying h/w sensor. actuateHardware = true; } } else { // Log error. Every activate call should be preceded by a batch() call. ALOGE("\t >>>ERROR: activate called without batch"); } } else { ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident)); if (info.removeBatchParamsForIdent(ident) >= 0) { if (info.numActiveClients() == 0) { // This is the last connection, we need to de-activate the underlying h/w sensor. actuateHardware = true; } else { const int halVersion = getHalDeviceVersion(); if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { // Call batch for this sensor with the previously calculated best effort // batch_rate and timeout. One of the apps has unregistered for sensor // events, and the best effort batch parameters might have changed. ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle, info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout); mSensorDevice->batch(mSensorDevice, handle,info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout); } } } else { // sensor wasn't enabled for this ident } if (isClientDisabledLocked(ident)) { return NO_ERROR; } } if (actuateHardware) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled); err = mSensorDevice->activate( reinterpret_cast (mSensorDevice), handle, enabled); ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle, strerror(-err)); if (err != NO_ERROR && enabled) { // Failure when enabling the sensor. Clean up on failure. info.removeBatchParamsForIdent(ident); } } // On older devices which do not support batch, call setDelay(). if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle, info.bestBatchParams.batchDelay); mSensorDevice->setDelay( reinterpret_cast(mSensorDevice), handle, info.bestBatchParams.batchDelay); } return err; } status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { if (!mSensorDevice) return NO_INIT; if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) { samplingPeriodNs = MINIMUM_EVENTS_PERIOD; } const int halVersion = getHalDeviceVersion(); if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 && maxBatchReportLatencyNs != 0) { // Batch is not supported on older devices return invalid operation. return INVALID_OPERATION; } ALOGD_IF(DEBUG_CONNECTIONS, "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64, ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs); Mutex::Autolock _l(mLock); Info& info(mActivationCount.editValueFor(handle)); if (info.batchParams.indexOfKey(ident) < 0) { BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs); info.batchParams.add(ident, params); } else { // A batch has already been called with this ident. Update the batch parameters. info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs); } BatchParams prevBestBatchParams = info.bestBatchParams; // Find the minimum of all timeouts and batch_rates for this sensor. info.selectBatchParams(); ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> curr_period=%" PRId64 " min_period=%" PRId64 " curr_timeout=%" PRId64 " min_timeout=%" PRId64, prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay, prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout); status_t err(NO_ERROR); // If the min period or min timeout has changed since the last batch call, call batch. if (prevBestBatchParams != info.bestBatchParams) { if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle, info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout); err = mSensorDevice->batch(mSensorDevice, handle, info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout); } else { // For older devices which do not support batch, call setDelay() after activate() is // called. Some older devices may not support calling setDelay before activate(), so // call setDelay in SensorDevice::activate() method. } if (err != NO_ERROR) { ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s", mSensorDevice, handle, info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout, strerror(-err)); info.removeBatchParamsForIdent(ident); } } return err; } status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) { if (!mSensorDevice) return NO_INIT; if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) { samplingPeriodNs = MINIMUM_EVENTS_PERIOD; } Mutex::Autolock _l(mLock); if (isClientDisabledLocked(ident)) return INVALID_OPERATION; Info& info( mActivationCount.editValueFor(handle) ); // If the underlying sensor is NOT in continuous mode, setDelay() should return an error. // Calling setDelay() in batch mode is an invalid operation. if (info.bestBatchParams.batchTimeout != 0) { return INVALID_OPERATION; } ssize_t index = info.batchParams.indexOfKey(ident); if (index < 0) { return BAD_INDEX; } BatchParams& params = info.batchParams.editValueAt(index); params.batchDelay = samplingPeriodNs; info.selectBatchParams(); return mSensorDevice->setDelay(reinterpret_cast(mSensorDevice), handle, info.bestBatchParams.batchDelay); } int SensorDevice::getHalDeviceVersion() const { if (!mSensorDevice) return -1; return mSensorDevice->common.version; } status_t SensorDevice::flush(void* ident, int handle) { if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) { return INVALID_OPERATION; } if (isClientDisabled(ident)) return INVALID_OPERATION; ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle); return mSensorDevice->flush(mSensorDevice, handle); } bool SensorDevice::isClientDisabled(void* ident) { Mutex::Autolock _l(mLock); return isClientDisabledLocked(ident); } bool SensorDevice::isClientDisabledLocked(void* ident) { return mDisabledClients.indexOf(ident) >= 0; } void SensorDevice::enableAllSensors() { Mutex::Autolock _l(mLock); mDisabledClients.clear(); const int halVersion = getHalDeviceVersion(); for (size_t i = 0; i< mActivationCount.size(); ++i) { Info& info = mActivationCount.editValueAt(i); if (info.batchParams.isEmpty()) continue; info.selectBatchParams(); const int sensor_handle = mActivationCount.keyAt(i); ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ", sensor_handle); status_t err(NO_ERROR); if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) { err = mSensorDevice->batch(mSensorDevice, sensor_handle, info.bestBatchParams.flags, info.bestBatchParams.batchDelay, info.bestBatchParams.batchTimeout); ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err)); } if (err == NO_ERROR) { err = mSensorDevice->activate( reinterpret_cast(mSensorDevice), sensor_handle, 1); ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err)); } if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) { err = mSensorDevice->setDelay( reinterpret_cast(mSensorDevice), sensor_handle, info.bestBatchParams.batchDelay); ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err)); } } } void SensorDevice::disableAllSensors() { Mutex::Autolock _l(mLock); for (size_t i = 0; i< mActivationCount.size(); ++i) { const Info& info = mActivationCount.valueAt(i); // Check if this sensor has been activated previously and disable it. if (info.batchParams.size() > 0) { const int sensor_handle = mActivationCount.keyAt(i); ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", sensor_handle); mSensorDevice->activate( reinterpret_cast (mSensorDevice), sensor_handle, 0); // Add all the connections that were registered for this sensor to the disabled // clients list. for (size_t j = 0; j < info.batchParams.size(); ++j) { mDisabledClients.add(info.batchParams.keyAt(j)); } } } } status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) { ALOGD_IF(DEBUG_CONNECTIONS, "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f", injected_sensor_event->sensor, injected_sensor_event->timestamp, injected_sensor_event->data[0], injected_sensor_event->data[1], injected_sensor_event->data[2], injected_sensor_event->data[3], injected_sensor_event->data[4], injected_sensor_event->data[5]); if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { return INVALID_OPERATION; } return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event); } status_t SensorDevice::setMode(uint32_t mode) { if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { return INVALID_OPERATION; } return mSensorModule->set_operation_mode(mode); } // --------------------------------------------------------------------------- int SensorDevice::Info::numActiveClients() { SensorDevice& device(SensorDevice::getInstance()); int num = 0; for (size_t i = 0; i < batchParams.size(); ++i) { if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { ++num; } } return num; } status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { ssize_t index = batchParams.indexOfKey(ident); if (index < 0) { ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)", ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index)); return BAD_INDEX; } BatchParams& params = batchParams.editValueAt(index); params.flags = flags; params.batchDelay = samplingPeriodNs; params.batchTimeout = maxBatchReportLatencyNs; return NO_ERROR; } void SensorDevice::Info::selectBatchParams() { BatchParams bestParams(0, -1, -1); SensorDevice& device(SensorDevice::getInstance()); for (size_t i = 0; i < batchParams.size(); ++i) { if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; BatchParams params = batchParams.valueAt(i); if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { bestParams.batchDelay = params.batchDelay; } if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { bestParams.batchTimeout = params.batchTimeout; } } bestBatchParams = bestParams; } ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) { ssize_t idx = batchParams.removeItem(ident); if (idx >= 0) { selectBatchParams(); } return idx; } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/SensorDevice.h0100644 0000000 0000000 00000011617 13077405420 017074 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_DEVICE_H #define ANDROID_SENSOR_DEVICE_H #include "SensorServiceUtils.h" #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- using SensorServiceUtil::Dumpable; class SensorDevice : public Singleton, public Dumpable { public: ssize_t getSensorList(sensor_t const** list); void handleDynamicSensorConnection(int handle, bool connected); status_t initCheck() const; int getHalDeviceVersion() const; ssize_t poll(sensors_event_t* buffer, size_t count); status_t activate(void* ident, int handle, int enabled); status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs); // Call batch with timeout zero instead of calling setDelay() for newer devices. status_t setDelay(void* ident, int handle, int64_t ns); status_t flush(void* ident, int handle); status_t setMode(uint32_t mode); void disableAllSensors(); void enableAllSensors(); void autoDisable(void *ident, int handle); status_t injectSensorData(const sensors_event_t *event); // Dumpable virtual std::string dump() const; private: friend class Singleton; sensors_poll_device_1_t* mSensorDevice; struct sensors_module_t* mSensorModule; static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz mutable Mutex mLock; // protect mActivationCount[].batchParams // fixed-size array after construction // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from // batch call. For continous mode clients, maxBatchReportLatency is set to zero. struct BatchParams { // TODO: Get rid of flags parameter everywhere. int flags; nsecs_t batchDelay, batchTimeout; BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {} BatchParams(int flag, nsecs_t delay, nsecs_t timeout): flags(flag), batchDelay(delay), batchTimeout(timeout) { } bool operator != (const BatchParams& other) { return other.batchDelay != batchDelay || other.batchTimeout != batchTimeout || other.flags != flags; } }; // Store batch parameters in the KeyedVector and the optimal batch_rate and timeout in // bestBatchParams. For every batch() call corresponding params are stored in batchParams // vector. A continuous mode request is batch(... timeout=0 ..) followed by activate(). A batch // mode request is batch(... timeout > 0 ...) followed by activate(). // Info is a per-sensor data structure which contains the batch parameters for each client that // has registered for this sensor. struct Info { BatchParams bestBatchParams; // Key is the unique identifier(ident) for each client, value is the batch parameters // requested by the client. KeyedVector batchParams; Info() : bestBatchParams(0, -1, -1) {} // Sets batch parameters for this ident. Returns error if this ident is not already present // in the KeyedVector above. status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs); // Finds the optimal parameters for batching and stores them in bestBatchParams variable. void selectBatchParams(); // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of // the removed ident. If index >=0, ident is present and successfully removed. ssize_t removeBatchParamsForIdent(void* ident); int numActiveClients(); }; DefaultKeyedVector mActivationCount; // Use this vector to determine which client is activated or deactivated. SortedVector mDisabledClients; SensorDevice(); bool isClientDisabled(void* ident); bool isClientDisabledLocked(void* ident); }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SENSOR_DEVICE_H services/sensorservice/SensorEventAckReceiver.h0100644 0000000 0000000 00000002062 13077405420 021054 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_EVENT_ACK_RECEIVER_H #define ANDROID_SENSOR_EVENT_ACK_RECEIVER_H #include "SensorService.h" namespace android { class SensorService; class SensorService::SensorEventAckReceiver : public Thread { sp const mService; public: virtual bool threadLoop(); SensorEventAckReceiver(const sp& service) : mService(service) { } }; } #endif // ANDROID_SENSOR_EVNET_ACK_RECEIVER_H services/sensorservice/SensorEventConnection.cpp0100644 0000000 0000000 00000064247 13077405420 021340 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include "vec.h" #include "SensorEventConnection.h" #include "SensorDevice.h" namespace android { SensorService::SensorEventConnection::SensorEventConnection( const sp& service, uid_t uid, String8 packageName, bool isDataInjectionMode, const String16& opPackageName) : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false), mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) { mChannel = new BitTube(mService->mSocketBufferSize); #if DEBUG_CONNECTIONS mEventsReceived = mEventsSentFromCache = mEventsSent = 0; mTotalAcksNeeded = mTotalAcksReceived = 0; #endif } SensorService::SensorEventConnection::~SensorEventConnection() { ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this); mService->cleanupConnection(this); if (mEventCache != NULL) { delete mEventCache; } } void SensorService::SensorEventConnection::onFirstRef() { LooperCallback::onFirstRef(); } bool SensorService::SensorEventConnection::needsWakeLock() { Mutex::Autolock _l(mConnectionLock); return !mDead && mWakeLockRefCount > 0; } void SensorService::SensorEventConnection::resetWakeLockRefCount() { Mutex::Autolock _l(mConnectionLock); mWakeLockRefCount = 0; } void SensorService::SensorEventConnection::dump(String8& result) { Mutex::Autolock _l(mConnectionLock); result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL"); result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | " "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); for (size_t i = 0; i < mSensorInfo.size(); ++i) { const FlushInfo& flushInfo = mSensorInfo.valueAt(i); result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n", mService->getSensorName(mSensorInfo.keyAt(i)).string(), mSensorInfo.keyAt(i), flushInfo.mFirstFlushPending ? "First flush pending" : "active", flushInfo.mPendingFlushEventsToSend); } #if DEBUG_CONNECTIONS result.appendFormat("\t events recvd: %d | sent %d | cache %d | dropped %d |" " total_acks_needed %d | total_acks_recvd %d\n", mEventsReceived, mEventsSent, mEventsSentFromCache, mEventsReceived - (mEventsSentFromCache + mEventsSent + mCacheSize), mTotalAcksNeeded, mTotalAcksReceived); #endif } bool SensorService::SensorEventConnection::addSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); sp si = mService->getSensorInterfaceFromHandle(handle); if (si == nullptr || !canAccessSensor(si->getSensor(), "Tried adding", mOpPackageName) || mSensorInfo.indexOfKey(handle) >= 0) { return false; } mSensorInfo.add(handle, FlushInfo()); return true; } bool SensorService::SensorEventConnection::removeSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); if (mSensorInfo.removeItem(handle) >= 0) { return true; } return false; } bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const { Mutex::Autolock _l(mConnectionLock); return mSensorInfo.indexOfKey(handle) >= 0; } bool SensorService::SensorEventConnection::hasAnySensor() const { Mutex::Autolock _l(mConnectionLock); return mSensorInfo.size() ? true : false; } bool SensorService::SensorEventConnection::hasOneShotSensors() const { Mutex::Autolock _l(mConnectionLock); for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); sp si = mService->getSensorInterfaceFromHandle(handle); if (si != nullptr && si->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) { return true; } } return false; } String8 SensorService::SensorEventConnection::getPackageName() const { return mPackageName; } void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle, bool value) { Mutex::Autolock _l(mConnectionLock); ssize_t index = mSensorInfo.indexOfKey(handle); if (index >= 0) { FlushInfo& flushInfo = mSensorInfo.editValueAt(index); flushInfo.mFirstFlushPending = value; } } void SensorService::SensorEventConnection::updateLooperRegistration(const sp& looper) { Mutex::Autolock _l(mConnectionLock); updateLooperRegistrationLocked(looper); } void SensorService::SensorEventConnection::updateLooperRegistrationLocked( const sp& looper) { bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) || mDataInjectionMode; // If all sensors are unregistered OR Looper has encountered an error, we can remove the Fd from // the Looper if it has been previously added. if (!isConnectionActive || mDead) { if (mHasLooperCallbacks) { ALOGD_IF(DEBUG_CONNECTIONS, "%p removeFd fd=%d", this, mChannel->getSendFd()); looper->removeFd(mChannel->getSendFd()); mHasLooperCallbacks = false; } return; } int looper_flags = 0; if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT; if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); sp si = mService->getSensorInterfaceFromHandle(handle); if (si != nullptr && si->getSensor().isWakeUpSensor()) { looper_flags |= ALOOPER_EVENT_INPUT; } } // If flags is still set to zero, we don't need to add this fd to the Looper, if the fd has // already been added, remove it. This is likely to happen when ALL the events stored in the // cache have been sent to the corresponding app. if (looper_flags == 0) { if (mHasLooperCallbacks) { ALOGD_IF(DEBUG_CONNECTIONS, "removeFd fd=%d", mChannel->getSendFd()); looper->removeFd(mChannel->getSendFd()); mHasLooperCallbacks = false; } return; } // Add the file descriptor to the Looper for receiving acknowledegments if the app has // registered for wake-up sensors OR for sending events in the cache. int ret = looper->addFd(mChannel->getSendFd(), 0, looper_flags, this, NULL); if (ret == 1) { ALOGD_IF(DEBUG_CONNECTIONS, "%p addFd fd=%d", this, mChannel->getSendFd()); mHasLooperCallbacks = true; } else { ALOGE("Looper::addFd failed ret=%d fd=%d", ret, mChannel->getSendFd()); } } void SensorService::SensorEventConnection::incrementPendingFlushCount(int32_t handle) { Mutex::Autolock _l(mConnectionLock); ssize_t index = mSensorInfo.indexOfKey(handle); if (index >= 0) { FlushInfo& flushInfo = mSensorInfo.editValueAt(index); flushInfo.mPendingFlushEventsToSend++; } } status_t SensorService::SensorEventConnection::sendEvents( sensors_event_t const* buffer, size_t numEvents, sensors_event_t* scratch, SensorEventConnection const * const * mapFlushEventsToConnections) { // filter out events not for this connection int count = 0; Mutex::Autolock _l(mConnectionLock); if (scratch) { size_t i=0; while (i(buffer); count = numEvents; } sendPendingFlushEventsLocked(); // Early return if there are no events for this connection. if (count == 0) { return status_t(NO_ERROR); } #if DEBUG_CONNECTIONS mEventsReceived += count; #endif if (mCacheSize != 0) { // There are some events in the cache which need to be sent first. Copy this buffer to // the end of cache. if (mCacheSize + count <= mMaxCacheSize) { memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t)); mCacheSize += count; } else { // Check if any new sensors have registered on this connection which may have increased // the max cache size that is desired. if (mCacheSize + count < computeMaxCacheSizeLocked()) { reAllocateCacheLocked(scratch, count); return status_t(NO_ERROR); } // Some events need to be dropped. int remaningCacheSize = mMaxCacheSize - mCacheSize; if (remaningCacheSize != 0) { memcpy(&mEventCache[mCacheSize], scratch, remaningCacheSize * sizeof(sensors_event_t)); } int numEventsDropped = count - remaningCacheSize; countFlushCompleteEventsLocked(mEventCache, numEventsDropped); // Drop the first "numEventsDropped" in the cache. memmove(mEventCache, &mEventCache[numEventsDropped], (mCacheSize - numEventsDropped) * sizeof(sensors_event_t)); // Copy the remainingEvents in scratch buffer to the end of cache. memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize, numEventsDropped * sizeof(sensors_event_t)); } return status_t(NO_ERROR); } int index_wake_up_event = findWakeUpSensorEventLocked(scratch, count); if (index_wake_up_event >= 0) { scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK; ++mWakeLockRefCount; #if DEBUG_CONNECTIONS ++mTotalAcksNeeded; #endif } // NOTE: ASensorEvent and sensors_event_t are the same type. ssize_t size = SensorEventQueue::write(mChannel, reinterpret_cast(scratch), count); if (size < 0) { // Write error, copy events to local cache. if (index_wake_up_event >= 0) { // If there was a wake_up sensor_event, reset the flag. scratch[index_wake_up_event].flags &= ~WAKE_UP_SENSOR_EVENT_NEEDS_ACK; if (mWakeLockRefCount > 0) { --mWakeLockRefCount; } #if DEBUG_CONNECTIONS --mTotalAcksNeeded; #endif } if (mEventCache == NULL) { mMaxCacheSize = computeMaxCacheSizeLocked(); mEventCache = new sensors_event_t[mMaxCacheSize]; mCacheSize = 0; } memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t)); mCacheSize += count; // Add this file descriptor to the looper to get a callback when this fd is available for // writing. updateLooperRegistrationLocked(mService->getLooper()); return size; } #if DEBUG_CONNECTIONS if (size > 0) { mEventsSent += count; } #endif return size < 0 ? status_t(size) : status_t(NO_ERROR); } void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch, int count) { sensors_event_t *eventCache_new; const int new_cache_size = computeMaxCacheSizeLocked(); // Allocate new cache, copy over events from the old cache & scratch, free up memory. eventCache_new = new sensors_event_t[new_cache_size]; memcpy(eventCache_new, mEventCache, mCacheSize * sizeof(sensors_event_t)); memcpy(&eventCache_new[mCacheSize], scratch, count * sizeof(sensors_event_t)); ALOGD_IF(DEBUG_CONNECTIONS, "reAllocateCacheLocked maxCacheSize=%d %d", mMaxCacheSize, new_cache_size); delete mEventCache; mEventCache = eventCache_new; mCacheSize += count; mMaxCacheSize = new_cache_size; } void SensorService::SensorEventConnection::sendPendingFlushEventsLocked() { ASensorEvent flushCompleteEvent; memset(&flushCompleteEvent, 0, sizeof(flushCompleteEvent)); flushCompleteEvent.type = SENSOR_TYPE_META_DATA; // Loop through all the sensors for this connection and check if there are any pending // flush complete events to be sent. for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); sp si = mService->getSensorInterfaceFromHandle(handle); if (si == nullptr) { continue; } FlushInfo& flushInfo = mSensorInfo.editValueAt(i); while (flushInfo.mPendingFlushEventsToSend > 0) { flushCompleteEvent.meta_data.sensor = handle; bool wakeUpSensor = si->getSensor().isWakeUpSensor(); if (wakeUpSensor) { ++mWakeLockRefCount; flushCompleteEvent.flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK; } ssize_t size = SensorEventQueue::write(mChannel, &flushCompleteEvent, 1); if (size < 0) { if (wakeUpSensor) --mWakeLockRefCount; return; } ALOGD_IF(DEBUG_CONNECTIONS, "sent dropped flush complete event==%d ", flushCompleteEvent.meta_data.sensor); flushInfo.mPendingFlushEventsToSend--; } } } void SensorService::SensorEventConnection::writeToSocketFromCache() { // At a time write at most half the size of the receiver buffer in SensorEventQueue OR // half the size of the socket buffer allocated in BitTube whichever is smaller. const int maxWriteSize = helpers::min(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2, int(mService->mSocketBufferSize/(sizeof(sensors_event_t)*2))); Mutex::Autolock _l(mConnectionLock); // Send pending flush complete events (if any) sendPendingFlushEventsLocked(); for (int numEventsSent = 0; numEventsSent < mCacheSize;) { const int numEventsToWrite = helpers::min(mCacheSize - numEventsSent, maxWriteSize); int index_wake_up_event = findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite); if (index_wake_up_event >= 0) { mEventCache[index_wake_up_event + numEventsSent].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK; ++mWakeLockRefCount; #if DEBUG_CONNECTIONS ++mTotalAcksNeeded; #endif } ssize_t size = SensorEventQueue::write(mChannel, reinterpret_cast(mEventCache + numEventsSent), numEventsToWrite); if (size < 0) { if (index_wake_up_event >= 0) { // If there was a wake_up sensor_event, reset the flag. mEventCache[index_wake_up_event + numEventsSent].flags &= ~WAKE_UP_SENSOR_EVENT_NEEDS_ACK; if (mWakeLockRefCount > 0) { --mWakeLockRefCount; } #if DEBUG_CONNECTIONS --mTotalAcksNeeded; #endif } memmove(mEventCache, &mEventCache[numEventsSent], (mCacheSize - numEventsSent) * sizeof(sensors_event_t)); ALOGD_IF(DEBUG_CONNECTIONS, "wrote %d events from cache size==%d ", numEventsSent, mCacheSize); mCacheSize -= numEventsSent; return; } numEventsSent += numEventsToWrite; #if DEBUG_CONNECTIONS mEventsSentFromCache += numEventsToWrite; #endif } ALOGD_IF(DEBUG_CONNECTIONS, "wrote all events from cache size=%d ", mCacheSize); // All events from the cache have been sent. Reset cache size to zero. mCacheSize = 0; // There are no more events in the cache. We don't need to poll for write on the fd. // Update Looper registration. updateLooperRegistrationLocked(mService->getLooper()); } void SensorService::SensorEventConnection::countFlushCompleteEventsLocked( sensors_event_t const* scratch, const int numEventsDropped) { ALOGD_IF(DEBUG_CONNECTIONS, "dropping %d events ", numEventsDropped); // Count flushComplete events in the events that are about to the dropped. These will be sent // separately before the next batch of events. for (int j = 0; j < numEventsDropped; ++j) { if (scratch[j].type == SENSOR_TYPE_META_DATA) { FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor); flushInfo.mPendingFlushEventsToSend++; ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d", flushInfo.mPendingFlushEventsToSend); } } return; } int SensorService::SensorEventConnection::findWakeUpSensorEventLocked( sensors_event_t const* scratch, const int count) { for (int i = 0; i < count; ++i) { if (mService->isWakeUpSensorEvent(scratch[i])) { return i; } } return -1; } sp SensorService::SensorEventConnection::getSensorChannel() const { return mChannel; } status_t SensorService::SensorEventConnection::enableDisable( int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) { status_t err; if (enabled) { err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs, reservedFlags, mOpPackageName); } else { err = mService->disable(this, handle); } return err; } status_t SensorService::SensorEventConnection::setEventRate( int handle, nsecs_t samplingPeriodNs) { return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName); } status_t SensorService::SensorEventConnection::flush() { return mService->flushSensor(this, mOpPackageName); } int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) { if (events & ALOOPER_EVENT_HANGUP || events & ALOOPER_EVENT_ERROR) { { // If the Looper encounters some error, set the flag mDead, reset mWakeLockRefCount, // and remove the fd from Looper. Call checkWakeLockState to know if SensorService // can release the wake-lock. ALOGD_IF(DEBUG_CONNECTIONS, "%p Looper error %d", this, fd); Mutex::Autolock _l(mConnectionLock); mDead = true; mWakeLockRefCount = 0; updateLooperRegistrationLocked(mService->getLooper()); } mService->checkWakeLockState(); if (mDataInjectionMode) { // If the Looper has encountered some error in data injection mode, reset SensorService // back to normal mode. mService->resetToNormalMode(); mDataInjectionMode = false; } return 1; } if (events & ALOOPER_EVENT_INPUT) { unsigned char buf[sizeof(sensors_event_t)]; ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT); { Mutex::Autolock _l(mConnectionLock); if (numBytesRead == sizeof(sensors_event_t)) { if (!mDataInjectionMode) { ALOGE("Data injected in normal mode, dropping event" "package=%s uid=%d", mPackageName.string(), mUid); // Unregister call backs. return 0; } sensors_event_t sensor_event; memcpy(&sensor_event, buf, sizeof(sensors_event_t)); sp si = mService->getSensorInterfaceFromHandle(sensor_event.sensor); if (si == nullptr) { return 1; } SensorDevice& dev(SensorDevice::getInstance()); sensor_event.type = si->getSensor().getType(); dev.injectSensorData(&sensor_event); #if DEBUG_CONNECTIONS ++mEventsReceived; #endif } else if (numBytesRead == sizeof(uint32_t)) { uint32_t numAcks = 0; memcpy(&numAcks, buf, numBytesRead); // Sanity check to ensure there are no read errors in recv, numAcks is always // within the range and not zero. If any of the above don't hold reset // mWakeLockRefCount to zero. if (numAcks > 0 && numAcks < mWakeLockRefCount) { mWakeLockRefCount -= numAcks; } else { mWakeLockRefCount = 0; } #if DEBUG_CONNECTIONS mTotalAcksReceived += numAcks; #endif } else { // Read error, reset wakelock refcount. mWakeLockRefCount = 0; } } // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released // here as checkWakeLockState() will need it. if (mWakeLockRefCount == 0) { mService->checkWakeLockState(); } // continue getting callbacks. return 1; } if (events & ALOOPER_EVENT_OUTPUT) { // send sensor data that is stored in mEventCache for this connection. mService->sendEventsFromCache(this); } return 1; } int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const { size_t fifoWakeUpSensors = 0; size_t fifoNonWakeUpSensors = 0; for (size_t i = 0; i < mSensorInfo.size(); ++i) { sp si = mService->getSensorInterfaceFromHandle(mSensorInfo.keyAt(i)); if (si == nullptr) { continue; } const Sensor& sensor = si->getSensor(); if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) { // Each sensor has a reserved fifo. Sum up the fifo sizes for all wake up sensors and // non wake_up sensors. if (sensor.isWakeUpSensor()) { fifoWakeUpSensors += sensor.getFifoReservedEventCount(); } else { fifoNonWakeUpSensors += sensor.getFifoReservedEventCount(); } } else { // Shared fifo. Compute the max of the fifo sizes for wake_up and non_wake up sensors. if (sensor.isWakeUpSensor()) { fifoWakeUpSensors = fifoWakeUpSensors > sensor.getFifoMaxEventCount() ? fifoWakeUpSensors : sensor.getFifoMaxEventCount(); } else { fifoNonWakeUpSensors = fifoNonWakeUpSensors > sensor.getFifoMaxEventCount() ? fifoNonWakeUpSensors : sensor.getFifoMaxEventCount(); } } } if (fifoWakeUpSensors + fifoNonWakeUpSensors == 0) { // It is extremely unlikely that there is a write failure in non batch mode. Return a cache // size that is equal to that of the batch mode. // ALOGW("Write failure in non-batch mode"); return MAX_SOCKET_BUFFER_SIZE_BATCHED/sizeof(sensors_event_t); } return fifoWakeUpSensors + fifoNonWakeUpSensors; } } // namespace android services/sensorservice/SensorEventConnection.h0100644 0000000 0000000 00000016426 13077405420 021001 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_EVENT_CONNECTION_H #define ANDROID_SENSOR_EVENT_CONNECTION_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SensorService.h" namespace android { class SensorService; class SensorService::SensorEventConnection: public BnSensorEventConnection, public LooperCallback { friend class SensorService; public: SensorEventConnection(const sp& service, uid_t uid, String8 packageName, bool isDataInjectionMode, const String16& opPackageName); status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch, SensorEventConnection const * const * mapFlushEventsToConnections = NULL); bool hasSensor(int32_t handle) const; bool hasAnySensor() const; bool hasOneShotSensors() const; bool addSensor(int32_t handle); bool removeSensor(int32_t handle); void setFirstFlushPending(int32_t handle, bool value); void dump(String8& result); bool needsWakeLock(); void resetWakeLockRefCount(); String8 getPackageName() const; uid_t getUid() const { return mUid; } private: virtual ~SensorEventConnection(); virtual void onFirstRef(); virtual sp getSensorChannel() const; virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags); virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs); virtual status_t flush(); // Count the number of flush complete events which are about to be dropped in the buffer. // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent // separately before the next batch of events. void countFlushCompleteEventsLocked(sensors_event_t const* scratch, int numEventsDropped); // Check if there are any wake up events in the buffer. If yes, return the index of the first // wake_up sensor event in the buffer else return -1. This wake_up sensor event will have the // flag WAKE_UP_SENSOR_EVENT_NEEDS_ACK set. Exactly one event per packet will have the wake_up // flag set. SOCK_SEQPACKET ensures that either the entire packet is read or dropped. int findWakeUpSensorEventLocked(sensors_event_t const* scratch, int count); // Send pending flush_complete events. There may have been flush_complete_events that are // dropped which need to be sent separately before other events. On older HALs (1_0) this method // emulates the behavior of flush(). void sendPendingFlushEventsLocked(); // Writes events from mEventCache to the socket. void writeToSocketFromCache(); // Compute the approximate cache size from the FIFO sizes of various sensors registered for this // connection. Wake up and non-wake up sensors have separate FIFOs but FIFO may be shared // amongst wake-up sensors and non-wake up sensors. int computeMaxCacheSizeLocked() const; // When more sensors register, the maximum cache size desired may change. Compute max cache // size, reallocate memory and copy over events from the older cache. void reAllocateCacheLocked(sensors_event_t const* scratch, int count); // LooperCallback method. If there is data to read on this fd, it is an ack from the app that it // has read events from a wake up sensor, decrement mWakeLockRefCount. If this fd is available // for writing send the data from the cache. virtual int handleEvent(int fd, int events, void* data); // Increment mPendingFlushEventsToSend for the given sensor handle. void incrementPendingFlushCount(int32_t handle); // Add or remove the file descriptor associated with the BitTube to the looper. If mDead is set // to true or there are no more sensors for this connection, the file descriptor is removed if // it has been previously added to the Looper. Depending on the state of the connection FD may // be added to the Looper. The flags to set are determined by the internal state of the // connection. FDs are added to the looper when wake-up sensors are registered (to poll for // acknowledgements) and when write fails on the socket when there are too many error and the // other end hangs up or when this client unregisters for this connection. void updateLooperRegistration(const sp& looper); void updateLooperRegistrationLocked(const sp& looper); sp const mService; sp mChannel; uid_t mUid; mutable Mutex mConnectionLock; // Number of events from wake up sensors which are still pending and haven't been delivered to // the corresponding application. It is incremented by one unit for each write to the socket. uint32_t mWakeLockRefCount; // If this flag is set to true, it means that the file descriptor associated with the BitTube // has been added to the Looper in SensorService. This flag is typically set when this // connection has wake-up sensors associated with it or when write has failed on this connection // and we're storing some events in the cache. bool mHasLooperCallbacks; // If there are any errors associated with the Looper this flag is set to true and // mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if this // flag is set. bool mDead; bool mDataInjectionMode; struct FlushInfo { // The number of flush complete events dropped for this sensor is stored here. They are // sent separately before the next batch of events. int mPendingFlushEventsToSend; // Every activate is preceded by a flush. Only after the first flush complete is received, // the events for the sensor are sent on that *connection*. bool mFirstFlushPending; FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false) {} }; // protected by SensorService::mLock. Key for this vector is the sensor handle. KeyedVector mSensorInfo; sensors_event_t *mEventCache; int mCacheSize, mMaxCacheSize; String8 mPackageName; const String16 mOpPackageName; #if DEBUG_CONNECTIONS int mEventsReceived, mEventsSent, mEventsSentFromCache; int mTotalAcksNeeded, mTotalAcksReceived; #endif }; } // namepsace android #endif // ANDROID_SENSOR_EVENT_CONNECTION_H services/sensorservice/SensorFusion.cpp0100644 0000000 0000000 00000020206 13077405420 017465 0ustar000000000 0000000 /* * 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 "SensorDevice.h" #include "SensorFusion.h" #include "SensorService.h" namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion) SensorFusion::SensorFusion() : mSensorDevice(SensorDevice::getInstance()), mAttitude(mAttitudes[FUSION_9AXIS]), mGyroTime(0), mAccTime(0) { sensor_t const* list; Sensor uncalibratedGyro; ssize_t count = mSensorDevice.getSensorList(&list); mEnabled[FUSION_9AXIS] = false; mEnabled[FUSION_NOMAG] = false; mEnabled[FUSION_NOGYRO] = false; if (count > 0) { for (size_t i=0 ; i 0 && event.timestamp - mGyroTime< (int64_t)(5e7) ) { //0.05sec dT = (event.timestamp - mGyroTime) / 1000000000.0f; // here we estimate the gyro rate (useful for debugging) const float freq = 1 / dT; if (freq >= 100 && freq<1000) { // filter values obviously wrong const float alpha = 1 / (1 + dT); // 1s time-constant mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha; } const vec3_t gyro(event.data); for (int i = 0; i 0 && event.timestamp - mAccTime< (int64_t)(1e8) ) { //0.1sec dT = (event.timestamp - mAccTime) / 1000000000.0f; const vec3_t acc(event.data); for (int i = 0; i inline T min(T a, T b) { return a inline T max(T a, T b) { return a>b ? a : b; } status_t SensorFusion::activate(int mode, void* ident, bool enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "SensorFusion::activate(mode=%d, ident=%p, enabled=%d)", mode, ident, enabled); const ssize_t idx = mClients[mode].indexOf(ident); if (enabled) { if (idx < 0) { mClients[mode].add(ident); } } else { if (idx >= 0) { mClients[mode].removeItemsAt(idx); } } const bool newState = mClients[mode].size() != 0; if (newState != mEnabled[mode]) { mEnabled[mode] = newState; if (newState) { mFusions[mode].init(mode); } } mSensorDevice.activate(ident, mAcc.getHandle(), enabled); if (mode != FUSION_NOMAG) { mSensorDevice.activate(ident, mMag.getHandle(), enabled); } if (mode != FUSION_NOGYRO) { mSensorDevice.activate(ident, mGyro.getHandle(), enabled); } return NO_ERROR; } status_t SensorFusion::setDelay(int mode, void* ident, int64_t ns) { // Call batch with timeout zero instead of setDelay(). if (ns > (int64_t)5e7) { ns = (int64_t)(5e7); } mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0); if (mode != FUSION_NOMAG) { mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0); } if (mode != FUSION_NOGYRO) { mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0); } return NO_ERROR; } float SensorFusion::getPowerUsage(int mode) const { float power = mAcc.getPowerUsage() + ((mode != FUSION_NOMAG) ? mMag.getPowerUsage() : 0) + ((mode != FUSION_NOGYRO) ? mGyro.getPowerUsage() : 0); return power; } int32_t SensorFusion::getMinDelay() const { return mAcc.getMinDelay(); } void SensorFusion::dump(String8& result) { const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]); result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, " "q=< %g, %g, %g, %g > (%g), " "b=< %g, %g, %g >\n", mEnabled[FUSION_9AXIS] ? "enabled" : "disabled", mClients[FUSION_9AXIS].size(), mEstimatedGyroRate, fusion_9axis.getAttitude().x, fusion_9axis.getAttitude().y, fusion_9axis.getAttitude().z, fusion_9axis.getAttitude().w, length(fusion_9axis.getAttitude()), fusion_9axis.getBias().x, fusion_9axis.getBias().y, fusion_9axis.getBias().z); const Fusion& fusion_nomag(mFusions[FUSION_NOMAG]); result.appendFormat("game fusion(no mag) %s (%zd clients), " "gyro-rate=%7.2fHz, " "q=< %g, %g, %g, %g > (%g), " "b=< %g, %g, %g >\n", mEnabled[FUSION_NOMAG] ? "enabled" : "disabled", mClients[FUSION_NOMAG].size(), mEstimatedGyroRate, fusion_nomag.getAttitude().x, fusion_nomag.getAttitude().y, fusion_nomag.getAttitude().z, fusion_nomag.getAttitude().w, length(fusion_nomag.getAttitude()), fusion_nomag.getBias().x, fusion_nomag.getBias().y, fusion_nomag.getBias().z); const Fusion& fusion_nogyro(mFusions[FUSION_NOGYRO]); result.appendFormat("geomag fusion (no gyro) %s (%zd clients), " "gyro-rate=%7.2fHz, " "q=< %g, %g, %g, %g > (%g), " "b=< %g, %g, %g >\n", mEnabled[FUSION_NOGYRO] ? "enabled" : "disabled", mClients[FUSION_NOGYRO].size(), mEstimatedGyroRate, fusion_nogyro.getAttitude().x, fusion_nogyro.getAttitude().y, fusion_nogyro.getAttitude().z, fusion_nogyro.getAttitude().w, length(fusion_nogyro.getAttitude()), fusion_nogyro.getBias().x, fusion_nogyro.getBias().y, fusion_nogyro.getBias().z); } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/SensorFusion.h0100644 0000000 0000000 00000005125 13077405420 017135 0ustar000000000 0000000 /* * 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_SENSOR_FUSION_H #define ANDROID_SENSOR_FUSION_H #include #include #include #include #include #include #include "Fusion.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion : public Singleton { friend class Singleton; SensorDevice& mSensorDevice; Sensor mAcc; Sensor mMag; Sensor mGyro; Fusion mFusions[NUM_FUSION_MODE]; // normal, no_mag, no_gyro bool mEnabled[NUM_FUSION_MODE]; vec4_t &mAttitude; vec4_t mAttitudes[NUM_FUSION_MODE]; SortedVector mClients[3]; float mEstimatedGyroRate; nsecs_t mTargetDelayNs; nsecs_t mGyroTime; nsecs_t mAccTime; SensorFusion(); public: void process(const sensors_event_t& event); bool isEnabled() const { return mEnabled[FUSION_9AXIS] || mEnabled[FUSION_NOMAG] || mEnabled[FUSION_NOGYRO]; } bool hasEstimate(int mode = FUSION_9AXIS) const { return mFusions[mode].hasEstimate(); } mat33_t getRotationMatrix(int mode = FUSION_9AXIS) const { return mFusions[mode].getRotationMatrix(); } vec4_t getAttitude(int mode = FUSION_9AXIS) const { return mAttitudes[mode]; } vec3_t getGyroBias() const { return mFusions[FUSION_9AXIS].getBias(); } float getEstimatedRate() const { return mEstimatedGyroRate; } status_t activate(int mode, void* ident, bool enabled); status_t setDelay(int mode, void* ident, int64_t ns); float getPowerUsage(int mode=FUSION_9AXIS) const; int32_t getMinDelay() const; void dump(String8& result); }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SENSOR_FUSION_H services/sensorservice/SensorInterface.cpp0100644 0000000 0000000 00000005446 13077405420 020133 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "SensorInterface.h" #include "SensorDevice.h" #include "SensorFusion.h" #include #include namespace android { // --------------------------------------------------------------------------- namespace { const sensor_t DUMMY_SENSOR = { .name = "", .vendor = "", .stringType = "", .requiredPermission = ""}; } //unnamed namespace BaseSensor::BaseSensor(const sensor_t& sensor) : mSensorDevice(SensorDevice::getInstance()), mSensor(&sensor, mSensorDevice.getHalDeviceVersion()) { } BaseSensor::BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]) : mSensorDevice(SensorDevice::getInstance()), mSensor(sensor, Sensor::uuid_t(uuid), mSensorDevice.getHalDeviceVersion()) { } // --------------------------------------------------------------------------- HardwareSensor::HardwareSensor(const sensor_t& sensor): BaseSensor(sensor) { } HardwareSensor::HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]): BaseSensor(sensor, uuid) { } HardwareSensor::~HardwareSensor() { } bool HardwareSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) { *outEvent = event; return true; } status_t HardwareSensor::activate(void* ident, bool enabled) { return mSensorDevice.activate(ident, mSensor.getHandle(), enabled); } status_t HardwareSensor::batch(void* ident, int /*handle*/, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { return mSensorDevice.batch(ident, mSensor.getHandle(), flags, samplingPeriodNs, maxBatchReportLatencyNs); } status_t HardwareSensor::flush(void* ident, int handle) { return mSensorDevice.flush(ident, handle); } status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) { return mSensorDevice.setDelay(ident, handle, ns); } void HardwareSensor::autoDisable(void *ident, int handle) { mSensorDevice.autoDisable(ident, handle); } VirtualSensor::VirtualSensor() : BaseSensor(DUMMY_SENSOR), mSensorFusion(SensorFusion::getInstance()) { } // --------------------------------------------------------------------------- }; // namespace android services/sensorservice/SensorInterface.h0100644 0000000 0000000 00000007147 13077405420 017600 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_INTERFACE_H #define ANDROID_SENSOR_INTERFACE_H #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SensorDevice; class SensorFusion; class SensorInterface : public VirtualLightRefBase { public: virtual ~SensorInterface() {} virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) = 0; virtual status_t activate(void* ident, bool enabled) = 0; virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0; virtual status_t batch(void* ident, int handle, int /*flags*/, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) = 0; virtual status_t flush(void* /*ident*/, int /*handle*/) = 0; virtual const Sensor& getSensor() const = 0; virtual bool isVirtual() const = 0; virtual void autoDisable(void* /*ident*/, int /*handle*/) = 0; }; class BaseSensor : public SensorInterface { public: BaseSensor(const sensor_t& sensor); BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]); // Not all sensors need to support batching. virtual status_t batch(void* ident, int handle, int, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) override { if (maxBatchReportLatencyNs == 0) { return setDelay(ident, handle, samplingPeriodNs); } return -EINVAL; } virtual status_t flush(void* /*ident*/, int /*handle*/) override { return -EINVAL; } virtual const Sensor& getSensor() const override { return mSensor; } virtual void autoDisable(void* /*ident*/, int /*handle*/) override { } protected: SensorDevice& mSensorDevice; Sensor mSensor; }; // --------------------------------------------------------------------------- class HardwareSensor : public BaseSensor { public: HardwareSensor(const sensor_t& sensor); HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]); virtual ~HardwareSensor(); virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event); virtual status_t activate(void* ident, bool enabled) override; virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) override; virtual status_t setDelay(void* ident, int handle, int64_t ns) override; virtual status_t flush(void* ident, int handle) override; virtual bool isVirtual() const override { return false; } virtual void autoDisable(void *ident, int handle) override; }; class VirtualSensor : public BaseSensor { public: VirtualSensor(); virtual bool isVirtual() const override { return true; } protected: SensorFusion& mSensorFusion; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SENSOR_INTERFACE_H services/sensorservice/SensorList.cpp0100644 0000000 0000000 00000014226 13077405420 017142 0ustar000000000 0000000 /* * Copyright (C) 2016 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 "SensorList.h" #include #include #include namespace android { namespace SensorServiceUtil { const Sensor SensorList::mNonSensor = Sensor("unknown"); bool SensorList::add( int handle, SensorInterface* si, bool isForDebug, bool isVirtual) { std::lock_guard lk(mLock); if (handle == si->getSensor().getHandle() && mUsedHandle.insert(handle).second) { // will succeed as the mUsedHandle does not have this handle mHandleMap.emplace(handle, Entry(si, isForDebug, isVirtual)); return true; } // handle exist already or handle mismatch return false; } bool SensorList::remove(int handle) { std::lock_guard lk(mLock); auto entry = mHandleMap.find(handle); if (entry != mHandleMap.end()) { mHandleMap.erase(entry); return true; } return false; } String8 SensorList::getName(int handle) const { return getOne( handle, [] (const Entry& e) -> String8 {return e.si->getSensor().getName();}, mNonSensor.getName()); } sp SensorList::getInterface(int handle) const { return getOne>( handle, [] (const Entry& e) -> sp {return e.si;}, nullptr); } bool SensorList::isNewHandle(int handle) const { std::lock_guard lk(mLock); return mUsedHandle.find(handle) == mUsedHandle.end(); } const Vector SensorList::getUserSensors() const { // lock in forEachEntry Vector sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { if (!e.isForDebug && !e.si->getSensor().isDynamicSensor()) { sensors.add(e.si->getSensor()); } return true; }); return sensors; } const Vector SensorList::getUserDebugSensors() const { // lock in forEachEntry Vector sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { if (!e.si->getSensor().isDynamicSensor()) { sensors.add(e.si->getSensor()); } return true; }); return sensors; } const Vector SensorList::getDynamicSensors() const { // lock in forEachEntry Vector sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { if (!e.isForDebug && e.si->getSensor().isDynamicSensor()) { sensors.add(e.si->getSensor()); } return true; }); return sensors; } const Vector SensorList::getVirtualSensors() const { // lock in forEachEntry Vector sensors; forEachEntry( [&sensors] (const Entry& e) -> bool { if (e.isVirtual) { sensors.add(e.si->getSensor()); } return true; }); return sensors; } std::string SensorList::dump() const { String8 result; forEachSensor([&result] (const Sensor& s) -> bool { result.appendFormat( "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32 ") | perm: %s\n\t", s.getHandle(), s.getName().string(), s.getVendor().string(), s.getVersion(), s.getStringType().string(), s.getType(), s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a"); const int reportingMode = s.getReportingMode(); if (reportingMode == AREPORTING_MODE_CONTINUOUS) { result.append(" continuous | "); } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) { result.append(" on-change | "); } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) { result.append(" one-shot | "); } else if (reportingMode == AREPORTING_MODE_SPECIAL_TRIGGER) { result.append(" special-trigger | "); } else { result.append(" unknown-mode | "); } if (s.getMaxDelay() > 0) { result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay()); } else { result.appendFormat("maxDelay=%" PRId32 "us | ", s.getMaxDelay()); } if (s.getMinDelay() > 0) { result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay()); } else { result.appendFormat("minDelay=%" PRId32 "us | ", s.getMinDelay()); } if (s.getFifoMaxEventCount() > 0) { result.appendFormat("FIFO (max,reserved) = (%" PRIu32 ", %" PRIu32 ") events | ", s.getFifoMaxEventCount(), s.getFifoReservedEventCount()); } else { result.append("no batching | "); } if (s.isWakeUpSensor()) { result.appendFormat("wakeUp | "); } else { result.appendFormat("non-wakeUp | "); } if (s.isDynamicSensor()) { result.appendFormat("dynamic, "); } if (s.hasAdditionalInfo()) { result.appendFormat("has-additional-info, "); } result.append("\n"); return true; }); return std::string(result.string()); } SensorList::~SensorList() { } } // namespace SensorServiceUtil } // namespace android services/sensorservice/SensorList.h0100644 0000000 0000000 00000010522 13077405420 016602 0ustar000000000 0000000 /* * Copyright (C) 2016 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_SENSOR_SERVICE_UTIL_SENSOR_LIST_H #define ANDROID_SENSOR_SERVICE_UTIL_SENSOR_LIST_H #include "SensorInterface.h" #include "SensorServiceUtils.h" #include #include #include #include #include #include #include namespace android { class SensorInterface; namespace SensorServiceUtil { class SensorList : public Dumpable { public: // After SensorInterface * is added into SensorList, it can be assumed that SensorList own the // object it pointed to and the object should not be released elsewhere. bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false); // After a handle is removed, the object that SensorInterface * pointing to may get deleted if // no more sp<> of the same object exist. bool remove(int handle); inline bool hasAnySensor() const { return mHandleMap.size() > 0;} //helper functions const Vector getUserSensors() const; const Vector getUserDebugSensors() const; const Vector getDynamicSensors() const; const Vector getVirtualSensors() const; String8 getName(int handle) const; sp getInterface(int handle) const; bool isNewHandle(int handle) const; // Iterate through Sensor in sensor list and perform operation f on each Sensor object. // // TF is a function with the signature: // bool f(const Sensor &); // A return value of 'false' stops the iteration immediately. // // Note: in the function f, it is illegal to make calls to member functions of the same // SensorList object on which forEachSensor is invoked. template void forEachSensor(const TF& f) const; const Sensor& getNonSensor() const { return mNonSensor;} // Dumpable interface virtual std::string dump() const override; virtual ~SensorList(); private: struct Entry { sp si; const bool isForDebug; const bool isVirtual; Entry(SensorInterface* si_, bool debug_, bool virtual_) : si(si_), isForDebug(debug_), isVirtual(virtual_) { } }; const static Sensor mNonSensor; //.getName() == "unknown", // Iterate through Entry in sensor list and perform operation f on each Entry. // // TF is a function with the signature: // bool f(const Entry &); // A return value of 'false' stops the iteration over entries immediately. // // Note: in the function being passed in, it is illegal to make calls to member functions of the // same SensorList object on which forEachSensor is invoked. template void forEachEntry(const TF& f) const; template T getOne(int handle, const TF& accessor, T def = T()) const; mutable std::mutex mLock; std::map mHandleMap; std::unordered_set mUsedHandle; }; template void SensorList::forEachSensor(const TF& f) const { // lock happens in forEachEntry forEachEntry([&f] (const Entry& e) -> bool { return f(e.si->getSensor());}); } template void SensorList::forEachEntry(const TF& f) const { std::lock_guard lk(mLock); for (auto&& i : mHandleMap) { if (!f(i.second)){ break; } } } template T SensorList::getOne(int handle, const TF& accessor, T def) const { std::lock_guard lk(mLock); auto i = mHandleMap.find(handle); if (i != mHandleMap.end()) { return accessor(i->second); } else { return def; } } } // namespace SensorServiceUtil } // namespace android #endif // ANDROID_SENSOR_SERVICE_UTIL_SENSOR_LIST_H services/sensorservice/SensorRecord.cpp0100644 0000000 0000000 00000004650 13077405420 017445 0ustar000000000 0000000 /* * Copyright (C) 2010 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 "SensorRecord.h" #include "SensorEventConnection.h" namespace android { SensorService::SensorRecord::SensorRecord( const sp& connection) { mConnections.add(connection); } bool SensorService::SensorRecord::addConnection( const sp& connection) { if (mConnections.indexOf(connection) < 0) { mConnections.add(connection); return true; } return false; } bool SensorService::SensorRecord::removeConnection( const wp& connection) { ssize_t index = mConnections.indexOf(connection); if (index >= 0) { mConnections.removeItemsAt(index, 1); } // Remove this connections from the queue of flush() calls made on this sensor. for (Vector< wp >::iterator it = mPendingFlushConnections.begin(); it != mPendingFlushConnections.end(); ) { if (it->unsafe_get() == connection.unsafe_get()) { it = mPendingFlushConnections.erase(it); } else { ++it; } } return mConnections.size() ? false : true; } void SensorService::SensorRecord::addPendingFlushConnection( const sp& connection) { mPendingFlushConnections.add(connection); } void SensorService::SensorRecord::removeFirstPendingFlushConnection() { if (mPendingFlushConnections.size() > 0) { mPendingFlushConnections.removeAt(0); } } SensorService::SensorEventConnection * SensorService::SensorRecord::getFirstPendingFlushConnection() { if (mPendingFlushConnections.size() > 0) { return mPendingFlushConnections[0].unsafe_get(); } return NULL; } void SensorService::SensorRecord::clearAllPendingFlushConnections() { mPendingFlushConnections.clear(); } } // namespace android services/sensorservice/SensorRecord.h0100644 0000000 0000000 00000003076 13077405420 017113 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_RECORD_H #define ANDROID_SENSOR_RECORD_H #include "SensorService.h" namespace android { class SensorService; class SensorService::SensorRecord { public: SensorRecord(const sp& connection); bool addConnection(const sp& connection); bool removeConnection(const wp& connection); size_t getNumConnections() const { return mConnections.size(); } void addPendingFlushConnection(const sp& connection); void removeFirstPendingFlushConnection(); SensorEventConnection * getFirstPendingFlushConnection(); void clearAllPendingFlushConnections(); private: SortedVector< wp > mConnections; // A queue of all flush() calls made on this sensor. Flush complete events // will be sent in this order. Vector< wp > mPendingFlushConnections; }; } #endif // ANDROID_SENSOR_RECORD_H services/sensorservice/SensorRegistrationInfo.h0100644 0000000 0000000 00000002633 13077405420 021161 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_REGISTRATION_INFO_H #define ANDROID_SENSOR_REGISTRATION_INFO_H namespace android { class SensorService; struct SensorService::SensorRegistrationInfo { int32_t mSensorHandle; String8 mPackageName; bool mActivated; int32_t mSamplingRateUs; int32_t mMaxReportLatencyUs; int32_t mHour, mMin, mSec; SensorRegistrationInfo() : mPackageName() { mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN; mHour = mMin = mSec = INT32_MIN; mActivated = false; } static bool isSentinel(const SensorRegistrationInfo& info) { return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN); } }; } // namespace android; #endif // ANDROID_SENSOR_REGISTRATION_INFO_H services/sensorservice/SensorService.cpp0100644 0000000 0000000 00000150175 13077405420 017633 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include #include #include #include #include #include "BatteryService.h" #include "CorrectedGyroSensor.h" #include "GravitySensor.h" #include "LinearAccelerationSensor.h" #include "OrientationSensor.h" #include "RotationVectorSensor.h" #include "SensorFusion.h" #include "SensorInterface.h" #include "SensorService.h" #include "SensorEventAckReceiver.h" #include "SensorEventConnection.h" #include "SensorRecord.h" #include "SensorRegistrationInfo.h" #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- /* * Notes: * * - what about a gyro-corrected magnetic-field sensor? * - run mag sensor from time to time to force calibration * - gravity sensor length is wrong (=> drift in linear-acc sensor) * */ const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock"; uint8_t SensorService::sHmacGlobalKey[128] = {}; bool SensorService::sHmacGlobalKeyIsValid = false; #define SENSOR_SERVICE_DIR "/data/system/sensor_service" #define SENSOR_SERVICE_HMAC_KEY_FILE SENSOR_SERVICE_DIR "/hmac_key" // Permissions. static const String16 sDump("android.permission.DUMP"); SensorService::SensorService() : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED), mWakeLockAcquired(false) { } bool SensorService::initializeHmacKey() { int fd = open(SENSOR_SERVICE_HMAC_KEY_FILE, O_RDONLY|O_CLOEXEC); if (fd != -1) { int result = read(fd, sHmacGlobalKey, sizeof(sHmacGlobalKey)); close(fd); if (result == sizeof(sHmacGlobalKey)) { return true; } ALOGW("Unable to read HMAC key; generating new one."); } if (RAND_bytes(sHmacGlobalKey, sizeof(sHmacGlobalKey)) == -1) { ALOGW("Can't generate HMAC key; dynamic sensor getId() will be wrong."); return false; } // We need to make sure this is only readable to us. bool wroteKey = false; mkdir(SENSOR_SERVICE_DIR, S_IRWXU); fd = open(SENSOR_SERVICE_HMAC_KEY_FILE, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR|S_IWUSR); if (fd != -1) { int result = write(fd, sHmacGlobalKey, sizeof(sHmacGlobalKey)); close(fd); wroteKey = (result == sizeof(sHmacGlobalKey)); } if (wroteKey) { ALOGI("Generated new HMAC key."); } else { ALOGW("Unable to write HMAC key; dynamic sensor getId() will change " "after reboot."); } // Even if we failed to write the key we return true, because we did // initialize the HMAC key. return true; } void SensorService::onFirstRef() { ALOGD("nuSensorService starting..."); SensorDevice& dev(SensorDevice::getInstance()); sHmacGlobalKeyIsValid = initializeHmacKey(); if (dev.initCheck() == NO_ERROR) { sensor_t const* list; ssize_t count = dev.getSensorList(&list); if (count > 0) { ssize_t orientationIndex = -1; bool hasGyro = false, hasAccel = false, hasMag = false; uint32_t virtualSensorsNeeds = (1< bool { if (s.getFifoMaxEventCount() > 0) { batchingSupported = true; } return !batchingSupported; }); if (batchingSupported) { // Increase socket buffer size to a max of 100 KB for batching capabilities. mSocketBufferSize = MAX_SOCKET_BUFFER_SIZE_BATCHED; } else { mSocketBufferSize = SOCKET_BUFFER_SIZE_NON_BATCHED; } // Compare the socketBufferSize value against the system limits and limit // it to maxSystemSocketBufferSize if necessary. FILE *fp = fopen("/proc/sys/net/core/wmem_max", "r"); char line[128]; if (fp != NULL && fgets(line, sizeof(line), fp) != NULL) { line[sizeof(line) - 1] = '\0'; size_t maxSystemSocketBufferSize; sscanf(line, "%zu", &maxSystemSocketBufferSize); if (mSocketBufferSize > maxSystemSocketBufferSize) { mSocketBufferSize = maxSystemSocketBufferSize; } } if (fp) { fclose(fp); } mWakeLockAcquired = false; mLooper = new Looper(false); const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT; mSensorEventBuffer = new sensors_event_t[minBufferSize]; mSensorEventScratch = new sensors_event_t[minBufferSize]; mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize]; mCurrentOperatingMode = NORMAL; mNextSensorRegIndex = 0; for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) { mLastNSensorRegistrations.push(); } mInitCheck = NO_ERROR; mAckReceiver = new SensorEventAckReceiver(this); mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); run("SensorService", PRIORITY_URGENT_DISPLAY); } } } const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) { int handle = s->getSensor().getHandle(); int type = s->getSensor().getType(); if (mSensors.add(handle, s, isDebug, isVirtual)){ mRecentEvent.emplace(handle, new RecentEventLogger(type)); return s->getSensor(); } else { return mSensors.getNonSensor(); } } const Sensor& SensorService::registerDynamicSensorLocked(SensorInterface* s, bool isDebug) { return registerSensor(s, isDebug); } bool SensorService::unregisterDynamicSensorLocked(int handle) { bool ret = mSensors.remove(handle); const auto i = mRecentEvent.find(handle); if (i != mRecentEvent.end()) { delete i->second; mRecentEvent.erase(i); } return ret; } const Sensor& SensorService::registerVirtualSensor(SensorInterface* s, bool isDebug) { return registerSensor(s, isDebug, true); } SensorService::~SensorService() { for (auto && entry : mRecentEvent) { delete entry.second; } } status_t SensorService::dump(int fd, const Vector& args) { String8 result; if (!PermissionCache::checkCallingPermission(sDump)) { result.appendFormat("Permission Denial: can't dump SensorService from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { if (args.size() > 2) { return INVALID_OPERATION; } Mutex::Autolock _l(mLock); SensorDevice& dev(SensorDevice::getInstance()); if (args.size() == 2 && args[0] == String16("restrict")) { // If already in restricted mode. Ignore. if (mCurrentOperatingMode == RESTRICTED) { return status_t(NO_ERROR); } // If in any mode other than normal, ignore. if (mCurrentOperatingMode != NORMAL) { return INVALID_OPERATION; } mCurrentOperatingMode = RESTRICTED; dev.disableAllSensors(); // Clear all pending flush connections for all active sensors. If one of the active // connections has called flush() and the underlying sensor has been disabled before a // flush complete event is returned, we need to remove the connection from this queue. for (size_t i=0 ; i< mActiveSensors.size(); ++i) { mActiveSensors.valueAt(i)->clearAllPendingFlushConnections(); } mWhiteListedPackage.setTo(String8(args[1])); return status_t(NO_ERROR); } else if (args.size() == 1 && args[0] == String16("enable")) { // If currently in restricted mode, reset back to NORMAL mode else ignore. if (mCurrentOperatingMode == RESTRICTED) { mCurrentOperatingMode = NORMAL; dev.enableAllSensors(); } if (mCurrentOperatingMode == DATA_INJECTION) { resetToNormalModeLocked(); } mWhiteListedPackage.clear(); return status_t(NO_ERROR); } else if (args.size() == 2 && args[0] == String16("data_injection")) { if (mCurrentOperatingMode == NORMAL) { dev.disableAllSensors(); status_t err = dev.setMode(DATA_INJECTION); if (err == NO_ERROR) { mCurrentOperatingMode = DATA_INJECTION; } else { // Re-enable sensors. dev.enableAllSensors(); } mWhiteListedPackage.setTo(String8(args[1])); return NO_ERROR; } else if (mCurrentOperatingMode == DATA_INJECTION) { // Already in DATA_INJECTION mode. Treat this as a no_op. return NO_ERROR; } else { // Transition to data injection mode supported only from NORMAL mode. return INVALID_OPERATION; } } else if (!mSensors.hasAnySensor()) { result.append("No Sensors on the device\n"); } else { // Default dump the sensor list and debugging information. // result.append("Sensor Device:\n"); result.append(SensorDevice::getInstance().dump().c_str()); result.append("Sensor List:\n"); result.append(mSensors.dump().c_str()); result.append("Fusion States:\n"); SensorFusion::getInstance().dump(result); result.append("Recent Sensor events:\n"); for (auto&& i : mRecentEvent) { sp s = mSensors.getInterface(i.first); if (!i.second->isEmpty() && s->getSensor().getRequiredPermission().isEmpty()) { // if there is events and sensor does not need special permission. result.appendFormat("%s: ", s->getSensor().getName().string()); result.append(i.second->dump().c_str()); } } result.append("Active sensors:\n"); for (size_t i=0 ; igetNumConnections()); } result.appendFormat("Socket Buffer size = %zd events\n", mSocketBufferSize/sizeof(sensors_event_t)); result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held"); result.appendFormat("Mode :"); switch(mCurrentOperatingMode) { case NORMAL: result.appendFormat(" NORMAL\n"); break; case RESTRICTED: result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string()); break; case DATA_INJECTION: result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string()); } result.appendFormat("%zd active connections\n", mActiveConnections.size()); for (size_t i=0 ; i < mActiveConnections.size() ; i++) { sp connection(mActiveConnections[i].promote()); if (connection != 0) { result.appendFormat("Connection Number: %zu \n", i); connection->dump(result); } } result.appendFormat("Previous Registrations:\n"); // Log in the reverse chronological order. int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE; const int startIndex = currentIndex; do { const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex]; if (SensorRegistrationInfo::isSentinel(reg_info)) { // Ignore sentinel, proceed to next item. currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE; continue; } if (reg_info.mActivated) { result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x " "samplingRate=%dus maxReportLatency=%dus\n", reg_info.mHour, reg_info.mMin, reg_info.mSec, reg_info.mPackageName.string(), reg_info.mSensorHandle, reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs); } else { result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n", reg_info.mHour, reg_info.mMin, reg_info.mSec, reg_info.mPackageName.string(), reg_info.mSensorHandle); } currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE; } while(startIndex != currentIndex); } } write(fd, result.string(), result.size()); return NO_ERROR; } //TODO: move to SensorEventConnection later void SensorService::cleanupAutoDisabledSensorLocked(const sp& connection, sensors_event_t const* buffer, const int count) { for (int i=0 ; ihasSensor(handle)) { sp si = getSensorInterfaceFromHandle(handle); // If this buffer has an event from a one_shot sensor and this connection is registered // for this particular one_shot sensor, try cleaning up the connection. if (si != nullptr && si->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) { si->autoDisable(connection.get(), handle); cleanupWithoutDisableLocked(connection, handle); } } } } bool SensorService::threadLoop() { ALOGD("nuSensorService thread starting..."); // each virtual sensor could generate an event per "real" event, that's why we need to size // numEventMax much smaller than MAX_RECEIVE_BUFFER_EVENT_COUNT. in practice, this is too // aggressive, but guaranteed to be enough. const size_t vcount = mSensors.getVirtualSensors().size(); const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT; const size_t numEventMax = minBufferSize / (1 + vcount); SensorDevice& device(SensorDevice::getInstance()); const int halVersion = device.getHalDeviceVersion(); do { ssize_t count = device.poll(mSensorEventBuffer, numEventMax); if (count < 0) { ALOGE("sensor poll failed (%s)", strerror(-count)); break; } // Reset sensors_event_t.flags to zero for all events in the buffer. for (int i = 0; i < count; i++) { mSensorEventBuffer[i].flags = 0; } // Make a copy of the connection vector as some connections may be removed during the course // of this loop (especially when one-shot sensor events are present in the sensor_event // buffer). Promote all connections to StrongPointers before the lock is acquired. If the // destructor of the sp gets called when the lock is acquired, it may result in a deadlock // as ~SensorEventConnection() needs to acquire mLock again for cleanup. So copy all the // strongPointers to a vector before the lock is acquired. SortedVector< sp > activeConnections; populateActiveConnections(&activeConnections); Mutex::Autolock _l(mLock); // Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The // rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock, // sending events to clients (incrementing SensorEventConnection::mWakeLockRefCount) should // not be interleaved with decrementing SensorEventConnection::mWakeLockRefCount and // releasing the wakelock. bool bufferHasWakeUpEvent = false; for (int i = 0; i < count; i++) { if (isWakeUpSensorEvent(mSensorEventBuffer[i])) { bufferHasWakeUpEvent = true; break; } } if (bufferHasWakeUpEvent && !mWakeLockAcquired) { setWakeLockAcquiredLocked(true); } recordLastValueLocked(mSensorEventBuffer, count); // handle virtual sensors if (count && vcount) { sensors_event_t const * const event = mSensorEventBuffer; if (!mActiveVirtualSensors.empty()) { size_t k = 0; SensorFusion& fusion(SensorFusion::getInstance()); if (fusion.isEnabled()) { for (size_t i=0 ; i= minBufferSize) { ALOGE("buffer too small to hold all events: " "count=%zd, k=%zu, size=%zu", count, k, minBufferSize); break; } sensors_event_t out; sp si = mSensors.getInterface(handle); if (si == nullptr) { ALOGE("handle %d is not an valid virtual sensor", handle); continue; } if (si->process(&out, event[i])) { mSensorEventBuffer[count + k] = out; k++; } } } if (k) { // record the last synthesized values recordLastValueLocked(&mSensorEventBuffer[count], k); count += k; // sort the buffer by time-stamps sortEventBuffer(mSensorEventBuffer, count); } } } // handle backward compatibility for RotationVector sensor if (halVersion < SENSORS_DEVICE_API_VERSION_1_0) { for (int i = 0; i < count; i++) { if (mSensorEventBuffer[i].type == SENSOR_TYPE_ROTATION_VECTOR) { // All the 4 components of the quaternion should be available // No heading accuracy. Set it to -1 mSensorEventBuffer[i].data[4] = -1; } } } for (int i = 0; i < count; ++i) { // Map flush_complete_events in the buffer to SensorEventConnections which called flush // on the hardware sensor. mapFlushEventsToConnections[i] will be the // SensorEventConnection mapped to the corresponding flush_complete_event in // mSensorEventBuffer[i] if such a mapping exists (NULL otherwise). mMapFlushEventsToConnections[i] = NULL; if (mSensorEventBuffer[i].type == SENSOR_TYPE_META_DATA) { const int sensor_handle = mSensorEventBuffer[i].meta_data.sensor; SensorRecord* rec = mActiveSensors.valueFor(sensor_handle); if (rec != NULL) { mMapFlushEventsToConnections[i] = rec->getFirstPendingFlushConnection(); rec->removeFirstPendingFlushConnection(); } } // handle dynamic sensor meta events, process registration and unregistration of dynamic // sensor based on content of event. if (mSensorEventBuffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) { if (mSensorEventBuffer[i].dynamic_sensor_meta.connected) { int handle = mSensorEventBuffer[i].dynamic_sensor_meta.handle; const sensor_t& dynamicSensor = *(mSensorEventBuffer[i].dynamic_sensor_meta.sensor); ALOGI("Dynamic sensor handle 0x%x connected, type %d, name %s", handle, dynamicSensor.type, dynamicSensor.name); if (mSensors.isNewHandle(handle)) { const auto& uuid = mSensorEventBuffer[i].dynamic_sensor_meta.uuid; sensor_t s = dynamicSensor; // make sure the dynamic sensor flag is set s.flags |= DYNAMIC_SENSOR_MASK; // force the handle to be consistent s.handle = handle; SensorInterface *si = new HardwareSensor(s, uuid); // This will release hold on dynamic sensor meta, so it should be called // after Sensor object is created. device.handleDynamicSensorConnection(handle, true /*connected*/); registerDynamicSensorLocked(si); } else { ALOGE("Handle %d has been used, cannot use again before reboot.", handle); } } else { int handle = mSensorEventBuffer[i].dynamic_sensor_meta.handle; ALOGI("Dynamic sensor handle 0x%x disconnected", handle); device.handleDynamicSensorConnection(handle, false /*connected*/); if (!unregisterDynamicSensorLocked(handle)) { ALOGE("Dynamic sensor release error."); } size_t numConnections = activeConnections.size(); for (size_t i=0 ; i < numConnections; ++i) { if (activeConnections[i] != NULL) { activeConnections[i]->removeSensor(handle); } } } } } // Send our events to clients. Check the state of wake lock for each client and release the // lock if none of the clients need it. bool needsWakeLock = false; size_t numConnections = activeConnections.size(); for (size_t i=0 ; i < numConnections; ++i) { if (activeConnections[i] != 0) { activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch, mMapFlushEventsToConnections); needsWakeLock |= activeConnections[i]->needsWakeLock(); // If the connection has one-shot sensors, it may be cleaned up after first trigger. // Early check for one-shot sensors. if (activeConnections[i]->hasOneShotSensors()) { cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer, count); } } } if (mWakeLockAcquired && !needsWakeLock) { setWakeLockAcquiredLocked(false); } } while (!Thread::exitPending()); ALOGW("Exiting SensorService::threadLoop => aborting..."); abort(); return false; } sp SensorService::getLooper() const { return mLooper; } void SensorService::resetAllWakeLockRefCounts() { SortedVector< sp > activeConnections; populateActiveConnections(&activeConnections); { Mutex::Autolock _l(mLock); for (size_t i=0 ; i < activeConnections.size(); ++i) { if (activeConnections[i] != 0) { activeConnections[i]->resetWakeLockRefCount(); } } setWakeLockAcquiredLocked(false); } } void SensorService::setWakeLockAcquiredLocked(bool acquire) { if (acquire) { if (!mWakeLockAcquired) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); mWakeLockAcquired = true; } mLooper->wake(); } else { if (mWakeLockAcquired) { release_wake_lock(WAKE_LOCK_NAME); mWakeLockAcquired = false; } } } bool SensorService::isWakeLockAcquired() { Mutex::Autolock _l(mLock); return mWakeLockAcquired; } bool SensorService::SensorEventAckReceiver::threadLoop() { ALOGD("new thread SensorEventAckReceiver"); sp looper = mService->getLooper(); do { bool wakeLockAcquired = mService->isWakeLockAcquired(); int timeout = -1; if (wakeLockAcquired) timeout = 5000; int ret = looper->pollOnce(timeout); if (ret == ALOOPER_POLL_TIMEOUT) { mService->resetAllWakeLockRefCounts(); } } while(!Thread::exitPending()); return false; } void SensorService::recordLastValueLocked( const sensors_event_t* buffer, size_t count) { for (size_t i = 0; i < count; i++) { if (buffer[i].type == SENSOR_TYPE_META_DATA || buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META || buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) { continue; } auto logger = mRecentEvent.find(buffer[i].sensor); if (logger != mRecentEvent.end()) { logger->second->addEvent(buffer[i]); } } } void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) { struct compar { static int cmp(void const* lhs, void const* rhs) { sensors_event_t const* l = static_cast(lhs); sensors_event_t const* r = static_cast(rhs); return l->timestamp - r->timestamp; } }; qsort(buffer, count, sizeof(sensors_event_t), compar::cmp); } String8 SensorService::getSensorName(int handle) const { return mSensors.getName(handle); } bool SensorService::isVirtualSensor(int handle) const { sp sensor = getSensorInterfaceFromHandle(handle); return sensor != nullptr && sensor->isVirtual(); } bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const { int handle = event.sensor; if (event.type == SENSOR_TYPE_META_DATA) { handle = event.meta_data.sensor; } sp sensor = getSensorInterfaceFromHandle(handle); return sensor != nullptr && sensor->getSensor().isWakeUpSensor(); } int32_t SensorService::getIdFromUuid(const Sensor::uuid_t &uuid) const { if ((uuid.i64[0] == 0) && (uuid.i64[1] == 0)) { // UUID is not supported for this device. return 0; } if ((uuid.i64[0] == INT64_C(~0)) && (uuid.i64[1] == INT64_C(~0))) { // This sensor can be uniquely identified in the system by // the combination of its type and name. return -1; } // We have a dynamic sensor. if (!sHmacGlobalKeyIsValid) { // Rather than risk exposing UUIDs, we cripple dynamic sensors. ALOGW("HMAC key failure; dynamic sensor getId() will be wrong."); return 0; } // We want each app author/publisher to get a different ID, so that the // same dynamic sensor cannot be tracked across apps by multiple // authors/publishers. So we use both our UUID and our User ID. // Note potential confusion: // UUID => Universally Unique Identifier. // UID => User Identifier. // We refrain from using "uid" except as needed by API to try to // keep this distinction clear. auto appUserId = IPCThreadState::self()->getCallingUid(); uint8_t uuidAndApp[sizeof(uuid) + sizeof(appUserId)]; memcpy(uuidAndApp, &uuid, sizeof(uuid)); memcpy(uuidAndApp + sizeof(uuid), &appUserId, sizeof(appUserId)); // Now we use our key on our UUID/app combo to get the hash. uint8_t hash[EVP_MAX_MD_SIZE]; unsigned int hashLen; if (HMAC(EVP_sha256(), sHmacGlobalKey, sizeof(sHmacGlobalKey), uuidAndApp, sizeof(uuidAndApp), hash, &hashLen) == nullptr) { // Rather than risk exposing UUIDs, we cripple dynamic sensors. ALOGW("HMAC failure; dynamic sensor getId() will be wrong."); return 0; } int32_t id = 0; if (hashLen < sizeof(id)) { // We never expect this case, but out of paranoia, we handle it. // Our 'id' length is already quite small, we don't want the // effective length of it to be even smaller. // Rather than risk exposing UUIDs, we cripple dynamic sensors. ALOGW("HMAC insufficient; dynamic sensor getId() will be wrong."); return 0; } // This is almost certainly less than all of 'hash', but it's as secure // as we can be with our current 'id' length. memcpy(&id, hash, sizeof(id)); // Note at the beginning of the function that we return the values of // 0 and -1 to represent special cases. As a result, we can't return // those as dynamic sensor IDs. If we happened to hash to one of those // values, we change 'id' so we report as a dynamic sensor, and not as // one of those special cases. if (id == -1) { id = -2; } else if (id == 0) { id = 1; } return id; } void SensorService::makeUuidsIntoIdsForSensorList(Vector &sensorList) const { for (auto &sensor : sensorList) { int32_t id = getIdFromUuid(sensor.getUuid()); sensor.setId(id); } } Vector SensorService::getSensorList(const String16& opPackageName) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sensors", value, "0"); const Vector& initialSensorList = (atoi(value)) ? mSensors.getUserDebugSensors() : mSensors.getUserSensors(); Vector accessibleSensorList; for (size_t i = 0; i < initialSensorList.size(); i++) { Sensor sensor = initialSensorList[i]; if (canAccessSensor(sensor, "getSensorList", opPackageName)) { accessibleSensorList.add(sensor); } else { ALOGI("Skipped sensor %s because it requires permission %s and app op %d", sensor.getName().string(), sensor.getRequiredPermission().string(), sensor.getRequiredAppOp()); } } makeUuidsIntoIdsForSensorList(accessibleSensorList); return accessibleSensorList; } Vector SensorService::getDynamicSensorList(const String16& opPackageName) { Vector accessibleSensorList; mSensors.forEachSensor( [&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool { if (sensor.isDynamicSensor()) { if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) { accessibleSensorList.add(sensor); } else { ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32, sensor.getName().string(), sensor.getRequiredPermission().string(), sensor.getRequiredAppOp()); } } return true; }); makeUuidsIntoIdsForSensorList(accessibleSensorList); return accessibleSensorList; } sp SensorService::createSensorEventConnection(const String8& packageName, int requestedMode, const String16& opPackageName) { // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION. if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) { return NULL; } Mutex::Autolock _l(mLock); // To create a client in DATA_INJECTION mode to inject data, SensorService should already be // operating in DI mode. if (requestedMode == DATA_INJECTION) { if (mCurrentOperatingMode != DATA_INJECTION) return NULL; if (!isWhiteListedPackage(packageName)) return NULL; } uid_t uid = IPCThreadState::self()->getCallingUid(); sp result(new SensorEventConnection(this, uid, packageName, requestedMode == DATA_INJECTION, opPackageName)); if (requestedMode == DATA_INJECTION) { if (mActiveConnections.indexOf(result) < 0) { mActiveConnections.add(result); } // Add the associated file descriptor to the Looper for polling whenever there is data to // be injected. result->updateLooperRegistration(mLooper); } return result; } int SensorService::isDataInjectionEnabled() { Mutex::Autolock _l(mLock); return (mCurrentOperatingMode == DATA_INJECTION); } status_t SensorService::resetToNormalMode() { Mutex::Autolock _l(mLock); return resetToNormalModeLocked(); } status_t SensorService::resetToNormalModeLocked() { SensorDevice& dev(SensorDevice::getInstance()); dev.enableAllSensors(); status_t err = dev.setMode(NORMAL); mCurrentOperatingMode = NORMAL; return err; } void SensorService::cleanupConnection(SensorEventConnection* c) { Mutex::Autolock _l(mLock); const wp connection(c); size_t size = mActiveSensors.size(); ALOGD_IF(DEBUG_CONNECTIONS, "%zu active sensors", size); for (size_t i=0 ; ihasSensor(handle)) { ALOGD_IF(DEBUG_CONNECTIONS, "%zu: disabling handle=0x%08x", i, handle); sp sensor = getSensorInterfaceFromHandle(handle); if (sensor != nullptr) { sensor->activate(c, false); } else { ALOGE("sensor interface of handle=0x%08x is null!", handle); } c->removeSensor(handle); } SensorRecord* rec = mActiveSensors.valueAt(i); ALOGE_IF(!rec, "mActiveSensors[%zu] is null (handle=0x%08x)!", i, handle); ALOGD_IF(DEBUG_CONNECTIONS, "removing connection %p for sensor[%zu].handle=0x%08x", c, i, handle); if (rec && rec->removeConnection(connection)) { ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection"); mActiveSensors.removeItemsAt(i, 1); mActiveVirtualSensors.erase(handle); delete rec; size--; } else { i++; } } c->updateLooperRegistration(mLooper); mActiveConnections.remove(connection); BatteryService::cleanup(c->getUid()); if (c->needsWakeLock()) { checkWakeLockStateLocked(); } } sp SensorService::getSensorInterfaceFromHandle(int handle) const { return mSensors.getInterface(handle); } status_t SensorService::enable(const sp& connection, int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; sp sensor = getSensorInterfaceFromHandle(handle); if (sensor == nullptr || !canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) { return BAD_VALUE; } Mutex::Autolock _l(mLock); if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION) && !isWhiteListedPackage(connection->getPackageName())) { return INVALID_OPERATION; } SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec == 0) { rec = new SensorRecord(connection); mActiveSensors.add(handle, rec); if (sensor->isVirtual()) { mActiveVirtualSensors.emplace(handle); } } else { if (rec->addConnection(connection)) { // this sensor is already activated, but we are adding a connection that uses it. // Immediately send down the last known value of the requested sensor if it's not a // "continuous" sensor. if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) { // NOTE: The wake_up flag of this event may get set to // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event. auto logger = mRecentEvent.find(handle); if (logger != mRecentEvent.end()) { sensors_event_t event; // It is unlikely that this buffer is empty as the sensor is already active. // One possible corner case may be two applications activating an on-change // sensor at the same time. if(logger->second->populateLastEvent(&event)) { event.sensor = handle; if (event.version == sizeof(sensors_event_t)) { if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { setWakeLockAcquiredLocked(true); } connection->sendEvents(&event, 1, NULL); if (!connection->needsWakeLock() && mWakeLockAcquired) { checkWakeLockStateLocked(); } } } } } } } if (connection->addSensor(handle)) { BatteryService::enableSensor(connection->getUid(), handle); // the sensor was added (which means it wasn't already there) // so, see if this connection becomes active if (mActiveConnections.indexOf(connection) < 0) { mActiveConnections.add(connection); } } else { ALOGW("sensor %08x already enabled in connection %p (ignoring)", handle, connection.get()); } nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs(); if (samplingPeriodNs < minDelayNs) { samplingPeriodNs = minDelayNs; } ALOGD_IF(DEBUG_CONNECTIONS, "Calling batch handle==%d flags=%d" "rate=%" PRId64 " timeout== %" PRId64"", handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs); status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs, maxBatchReportLatencyNs); // Call flush() before calling activate() on the sensor. Wait for a first // flush complete event before sending events on this connection. Ignore // one-shot sensors which don't support flush(). Ignore on-change sensors // to maintain the on-change logic (any on-change events except the initial // one should be trigger by a change in value). Also if this sensor isn't // already active, don't call flush(). if (err == NO_ERROR && sensor->getSensor().getReportingMode() == AREPORTING_MODE_CONTINUOUS && rec->getNumConnections() > 1) { connection->setFirstFlushPending(handle, true); status_t err_flush = sensor->flush(connection.get(), handle); // Flush may return error if the underlying h/w sensor uses an older HAL. if (err_flush == NO_ERROR) { rec->addPendingFlushConnection(connection.get()); } else { connection->setFirstFlushPending(handle, false); } } if (err == NO_ERROR) { ALOGD_IF(DEBUG_CONNECTIONS, "Calling activate on %d", handle); err = sensor->activate(connection.get(), true); } if (err == NO_ERROR) { connection->updateLooperRegistration(mLooper); SensorRegistrationInfo ®_info = mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); reg_info.mSensorHandle = handle; reg_info.mSamplingRateUs = samplingPeriodNs/1000; reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000; reg_info.mActivated = true; reg_info.mPackageName = connection->getPackageName(); time_t rawtime = time(NULL); struct tm * timeinfo = localtime(&rawtime); reg_info.mHour = timeinfo->tm_hour; reg_info.mMin = timeinfo->tm_min; reg_info.mSec = timeinfo->tm_sec; mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } if (err != NO_ERROR) { // batch/activate has failed, reset our state. cleanupWithoutDisableLocked(connection, handle); } return err; } status_t SensorService::disable(const sp& connection, int handle) { if (mInitCheck != NO_ERROR) return mInitCheck; Mutex::Autolock _l(mLock); status_t err = cleanupWithoutDisableLocked(connection, handle); if (err == NO_ERROR) { sp sensor = getSensorInterfaceFromHandle(handle); err = sensor != nullptr ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); } if (err == NO_ERROR) { SensorRegistrationInfo ®_info = mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); reg_info.mActivated = false; reg_info.mPackageName= connection->getPackageName(); reg_info.mSensorHandle = handle; time_t rawtime = time(NULL); struct tm * timeinfo = localtime(&rawtime); reg_info.mHour = timeinfo->tm_hour; reg_info.mMin = timeinfo->tm_min; reg_info.mSec = timeinfo->tm_sec; mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } return err; } status_t SensorService::cleanupWithoutDisable( const sp& connection, int handle) { Mutex::Autolock _l(mLock); return cleanupWithoutDisableLocked(connection, handle); } status_t SensorService::cleanupWithoutDisableLocked( const sp& connection, int handle) { SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec) { // see if this connection becomes inactive if (connection->removeSensor(handle)) { BatteryService::disableSensor(connection->getUid(), handle); } if (connection->hasAnySensor() == false) { connection->updateLooperRegistration(mLooper); mActiveConnections.remove(connection); } // see if this sensor becomes inactive if (rec->removeConnection(connection)) { mActiveSensors.removeItem(handle); mActiveVirtualSensors.erase(handle); delete rec; } return NO_ERROR; } return BAD_VALUE; } status_t SensorService::setEventRate(const sp& connection, int handle, nsecs_t ns, const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; sp sensor = getSensorInterfaceFromHandle(handle); if (sensor == nullptr || !canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) { return BAD_VALUE; } if (ns < 0) return BAD_VALUE; nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs(); if (ns < minDelayNs) { ns = minDelayNs; } return sensor->setDelay(connection.get(), handle, ns); } status_t SensorService::flushSensor(const sp& connection, const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; SensorDevice& dev(SensorDevice::getInstance()); const int halVersion = dev.getHalDeviceVersion(); status_t err(NO_ERROR); Mutex::Autolock _l(mLock); // Loop through all sensors for this connection and call flush on each of them. for (size_t i = 0; i < connection->mSensorInfo.size(); ++i) { const int handle = connection->mSensorInfo.keyAt(i); sp sensor = getSensorInterfaceFromHandle(handle); if (sensor == nullptr) { continue; } if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) { ALOGE("flush called on a one-shot sensor"); err = INVALID_OPERATION; continue; } if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0 || isVirtualSensor(handle)) { // For older devices just increment pending flush count which will send a trivial // flush complete event. connection->incrementPendingFlushCount(handle); } else { if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) { err = INVALID_OPERATION; continue; } status_t err_flush = sensor->flush(connection.get(), handle); if (err_flush == NO_ERROR) { SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec != NULL) rec->addPendingFlushConnection(connection); } err = (err_flush != NO_ERROR) ? err_flush : err; } } return err; } bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, const String16& opPackageName) { const String8& requiredPermission = sensor.getRequiredPermission(); if (requiredPermission.length() <= 0) { return true; } bool hasPermission = false; // Runtime permissions can't use the cache as they may change. if (sensor.isRequiredPermissionRuntime()) { hasPermission = checkPermission(String16(requiredPermission), IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission)); } if (!hasPermission) { ALOGE("%s a sensor (%s) without holding its required permission: %s", operation, sensor.getName().string(), sensor.getRequiredPermission().string()); return false; } const int32_t opCode = sensor.getRequiredAppOp(); if (opCode >= 0) { AppOpsManager appOps; if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName) != AppOpsManager::MODE_ALLOWED) { ALOGE("%s a sensor (%s) without enabled required app op: %d", operation, sensor.getName().string(), opCode); return false; } } return true; } void SensorService::checkWakeLockState() { Mutex::Autolock _l(mLock); checkWakeLockStateLocked(); } void SensorService::checkWakeLockStateLocked() { if (!mWakeLockAcquired) { return; } bool releaseLock = true; for (size_t i=0 ; i connection(mActiveConnections[i].promote()); if (connection != 0) { if (connection->needsWakeLock()) { releaseLock = false; break; } } } if (releaseLock) { setWakeLockAcquiredLocked(false); } } void SensorService::sendEventsFromCache(const sp& connection) { Mutex::Autolock _l(mLock); connection->writeToSocketFromCache(); if (connection->needsWakeLock()) { setWakeLockAcquiredLocked(true); } } void SensorService::populateActiveConnections( SortedVector< sp >* activeConnections) { Mutex::Autolock _l(mLock); for (size_t i=0 ; i < mActiveConnections.size(); ++i) { sp connection(mActiveConnections[i].promote()); if (connection != 0) { activeConnections->add(connection); } } } bool SensorService::isWhiteListedPackage(const String8& packageName) { return (packageName.contains(mWhiteListedPackage.string())); } }; // namespace android services/sensorservice/SensorService.h0100644 0000000 0000000 00000026053 13077405420 017275 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SENSOR_SERVICE_H #define ANDROID_SENSOR_SERVICE_H #include "SensorList.h" #include "RecentEventLogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __clang__ // Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable // without changing the API, so let's tell clang this is indeed intentional. #pragma clang diagnostic ignored "-Woverloaded-virtual" #endif // --------------------------------------------------------------------------- #define IGNORE_HARDWARE_FUSION false #define DEBUG_CONNECTIONS false // Max size is 100 KB which is enough to accept a batch of about 1000 events. #define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024 // For older HALs which don't support batching, use a smaller socket buffer size. #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024 #define SENSOR_REGISTRATIONS_BUF_SIZE 20 namespace android { // --------------------------------------------------------------------------- class SensorInterface; using namespace SensorServiceUtil; class SensorService : public BinderService, public BnSensorServer, protected Thread { // nested class/struct for internal use class SensorEventConnection; public: void cleanupConnection(SensorEventConnection* connection); status_t enable(const sp& connection, int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, const String16& opPackageName); status_t disable(const sp& connection, int handle); status_t setEventRate(const sp& connection, int handle, nsecs_t ns, const String16& opPackageName); status_t flushSensor(const sp& connection, const String16& opPackageName); private: friend class BinderService; // nested class/struct for internal use class SensorRecord; class SensorEventAckReceiver; struct SensorRegistrationInfo; enum Mode { // The regular operating mode where any application can register/unregister/call flush on // sensors. NORMAL = 0, // This mode is only used for testing purposes. Not all HALs support this mode. In this mode, // the HAL ignores the sensor data provided by physical sensors and accepts the data that is // injected from the SensorService as if it were the real sensor data. This mode is primarily // used for testing various algorithms like vendor provided SensorFusion, Step Counter and // Step Detector etc. Typically in this mode, there will be a client (a // SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps can // unregister and register for any sensor that supports injection. Registering to sensors // that do not support injection will give an error. TODO(aakella) : Allow exactly one // client to inject sensor data at a time. DATA_INJECTION = 1, // This mode is used only for testing sensors. Each sensor can be tested in isolation with // the required sampling_rate and maxReportLatency parameters without having to think about // the data rates requested by other applications. End user devices are always expected to be // in NORMAL mode. When this mode is first activated, all active sensors from all connections // are disabled. Calling flush() will return an error. In this mode, only the requests from // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only // these apps can register/unregister/call flush() on sensors. If SensorService switches to // NORMAL mode again, all sensors that were previously registered to are activated with the // corresponding paramaters if the application hasn't unregistered for sensors in the mean // time. NOTE: Non whitelisted app whose sensors were previously deactivated may still // receive events if a whitelisted app requests data from the same sensor. RESTRICTED = 2 // State Transitions supported. // RESTRICTED <--- NORMAL ---> DATA_INJECTION // ---> <--- // Shell commands to switch modes in SensorService. // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in // restricted mode it is treated as a NO_OP (and packageName is NOT changed). // // $ adb shell dumpsys sensorservice restrict .cts. // // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in // data_injection mode it is treated as a NO_OP (and packageName is NOT changed). // // $ adb shell dumpsys sensorservice data_injection .xts. // // 3) Reset sensorservice back to NORMAL mode. // $ adb shell dumpsys sensorservice enable }; static const char* WAKE_LOCK_NAME; static char const* getServiceName() ANDROID_API { return "sensorservice"; } SensorService() ANDROID_API; virtual ~SensorService(); virtual void onFirstRef(); // Thread interface virtual bool threadLoop(); // ISensorServer interface virtual Vector getSensorList(const String16& opPackageName); virtual Vector getDynamicSensorList(const String16& opPackageName); virtual sp createSensorEventConnection( const String8& packageName, int requestedMode, const String16& opPackageName); virtual int isDataInjectionEnabled(); virtual status_t dump(int fd, const Vector& args); String8 getSensorName(int handle) const; bool isVirtualSensor(int handle) const; sp getSensorInterfaceFromHandle(int handle) const; bool isWakeUpSensor(int type) const; void recordLastValueLocked(sensors_event_t const* buffer, size_t count); static void sortEventBuffer(sensors_event_t* buffer, size_t count); const Sensor& registerSensor(SensorInterface* sensor, bool isDebug = false, bool isVirtual = false); const Sensor& registerVirtualSensor(SensorInterface* sensor, bool isDebug = false); const Sensor& registerDynamicSensorLocked(SensorInterface* sensor, bool isDebug = false); bool unregisterDynamicSensorLocked(int handle); status_t cleanupWithoutDisable(const sp& connection, int handle); status_t cleanupWithoutDisableLocked(const sp& connection, int handle); void cleanupAutoDisabledSensorLocked(const sp& connection, sensors_event_t const* buffer, const int count); static bool canAccessSensor(const Sensor& sensor, const char* operation, const String16& opPackageName); // SensorService acquires a partial wakelock for delivering events from wake up sensors. This // method checks whether all the events from these wake up sensors have been delivered to the // corresponding applications, if yes the wakelock is released. void checkWakeLockState(); void checkWakeLockStateLocked(); bool isWakeLockAcquired(); bool isWakeUpSensorEvent(const sensors_event_t& event) const; sp getLooper() const; // Reset mWakeLockRefCounts for all SensorEventConnections to zero. This may happen if // SensorService did not receive any acknowledgements from apps which have registered for // wake_up sensors. void resetAllWakeLockRefCounts(); // Acquire or release wake_lock. If wake_lock is acquired, set the timeout in the looper to 5 // seconds and wake the looper. void setWakeLockAcquiredLocked(bool acquire); // Send events from the event cache for this particular connection. void sendEventsFromCache(const sp& connection); // Promote all weak referecences in mActiveConnections vector to strong references and add them // to the output vector. void populateActiveConnections( SortedVector< sp >* activeConnections); // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are // allowed to register for or call flush on sensors. Typically only cts test packages are // allowed. bool isWhiteListedPackage(const String8& packageName); // Reset the state of SensorService to NORMAL mode. status_t resetToNormalMode(); status_t resetToNormalModeLocked(); // Transforms the UUIDs for all the sensors into proper IDs. void makeUuidsIntoIdsForSensorList(Vector &sensorList) const; // Gets the appropriate ID from the given UUID. int32_t getIdFromUuid(const Sensor::uuid_t &uuid) const; // Either read from storage or create a new one. static bool initializeHmacKey(); static uint8_t sHmacGlobalKey[128]; static bool sHmacGlobalKeyIsValid; SensorList mSensors; status_t mInitCheck; // Socket buffersize used to initialize BitTube. This size depends on whether batching is // supported or not. uint32_t mSocketBufferSize; sp mLooper; sp mAckReceiver; // protected by mLock mutable Mutex mLock; DefaultKeyedVector mActiveSensors; std::unordered_set mActiveVirtualSensors; SortedVector< wp > mActiveConnections; bool mWakeLockAcquired; sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; SensorEventConnection const **mMapFlushEventsToConnections; std::unordered_map mRecentEvent; Mode mCurrentOperatingMode; // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only // applications with this packageName are allowed to activate/deactivate or call flush on // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to // sensors. String8 mWhiteListedPackage; int mNextSensorRegIndex; Vector mLastNSensorRegistrations; }; } // namespace android #endif // ANDROID_SENSOR_SERVICE_H services/sensorservice/SensorServiceUtils.cpp0100644 0000000 0000000 00000003657 13077405420 020656 0ustar000000000 0000000 /* * Copyright (C) 2016 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 "SensorServiceUtils.h" #include namespace android { namespace SensorServiceUtil { // Keep in sync with sSensorReportingMode in Sensor.java size_t eventSizeBySensorType(int type) { if (type >= SENSOR_TYPE_DEVICE_PRIVATE_BASE) { return 16; } switch (type) { case SENSOR_TYPE_POSE_6DOF: return 16; case SENSOR_TYPE_ROTATION_VECTOR: case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: return 5; case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: return 6; case SENSOR_TYPE_GAME_ROTATION_VECTOR: return 4; case SENSOR_TYPE_SIGNIFICANT_MOTION: case SENSOR_TYPE_STEP_DETECTOR: case SENSOR_TYPE_STEP_COUNTER: case SENSOR_TYPE_HEART_RATE: case SENSOR_TYPE_TILT_DETECTOR: case SENSOR_TYPE_WAKE_GESTURE: case SENSOR_TYPE_GLANCE_GESTURE: case SENSOR_TYPE_PICK_UP_GESTURE: case SENSOR_TYPE_WRIST_TILT_GESTURE: case SENSOR_TYPE_DEVICE_ORIENTATION: case SENSOR_TYPE_STATIONARY_DETECT: case SENSOR_TYPE_MOTION_DETECT: case SENSOR_TYPE_HEART_BEAT: return 1; default: return 3; } } } // namespace SensorServiceUtil } // namespace android; services/sensorservice/SensorServiceUtils.h0100644 0000000 0000000 00000002046 13077405420 020312 0ustar000000000 0000000 /* * Copyright (C) 2016 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_SENSOR_SERVICE_UTIL #define ANDROID_SENSOR_SERVICE_UTIL #include #include namespace android { namespace SensorServiceUtil { class Dumpable { public: virtual std::string dump() const = 0; virtual void setFormat(std::string ) {} virtual ~Dumpable() {} }; size_t eventSizeBySensorType(int type); } // namespace SensorServiceUtil } // namespace android; #endif // ANDROID_SENSOR_SERVICE_UTIL services/sensorservice/main_sensorservice.cpp0100644 0000000 0000000 00000001514 13077405420 020727 0ustar000000000 0000000 /* * 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 #include "SensorService.h" using namespace android; int main(int /*argc*/, char** /*argv*/) { signal(SIGPIPE, SIG_IGN); SensorService::publishAndJoinThreadPool(); return 0; } services/sensorservice/mat.h0100644 0000000 0000000 00000026014 13077405420 015261 0ustar000000000 0000000 /* * 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_MAT_H #define ANDROID_MAT_H #include "vec.h" #include "traits.h" // ----------------------------------------------------------------------- namespace android { template class mat; namespace helpers { template mat& doAssign( mat& lhs, typename TypeTraits::ParameterType rhs) { for (size_t i=0 ; i mat PURE doMul( const mat& lhs, const mat& rhs) { mat res; for (size_t c=0 ; c vec PURE doMul( const mat& lhs, const vec& rhs) { vec res; for (size_t r=0 ; r mat PURE doMul( const vec& lhs, const mat& rhs) { mat res; for (size_t c=0 ; c mat PURE doMul( const mat& rhs, typename TypeTraits::ParameterType v) { mat res; for (size_t c=0 ; c mat PURE doMul( typename TypeTraits::ParameterType v, const mat& rhs) { mat res; for (size_t c=0 ; c class mat : public vec< vec, C > { typedef typename TypeTraits::ParameterType pTYPE; typedef vec< vec, C > base; public: // STL-like interface. typedef TYPE value_type; typedef TYPE& reference; typedef TYPE const& const_reference; typedef size_t size_type; size_type size() const { return R*C; } enum { ROWS = R, COLS = C }; // ----------------------------------------------------------------------- // default constructors mat() { } mat(const mat& rhs) : base(rhs) { } mat(const base& rhs) : base(rhs) { } // ----------------------------------------------------------------------- // conversion constructors // sets the diagonal to the value, off-diagonal to zero mat(pTYPE rhs) { helpers::doAssign(*this, rhs); } // ----------------------------------------------------------------------- // Assignment mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; } mat& operator=(const base& rhs) { base::operator=(rhs); return *this; } mat& operator=(pTYPE rhs) { return helpers::doAssign(*this, rhs); } // ----------------------------------------------------------------------- // non-member function declaration and definition friend inline mat PURE operator + (const mat& lhs, const mat& rhs) { return helpers::doAdd( static_cast(lhs), static_cast(rhs)); } friend inline mat PURE operator - (const mat& lhs, const mat& rhs) { return helpers::doSub( static_cast(lhs), static_cast(rhs)); } // matrix*matrix template friend mat PURE operator * ( const mat& lhs, const mat& rhs) { return helpers::doMul(lhs, rhs); } // matrix*vector friend vec PURE operator * ( const mat& lhs, const vec& rhs) { return helpers::doMul(lhs, rhs); } // vector*matrix friend mat PURE operator * ( const vec& lhs, const mat& rhs) { return helpers::doMul(lhs, rhs); } // matrix*scalar friend inline mat PURE operator * (const mat& lhs, pTYPE v) { return helpers::doMul(lhs, v); } // scalar*matrix friend inline mat PURE operator * (pTYPE v, const mat& rhs) { return helpers::doMul(v, rhs); } // ----------------------------------------------------------------------- // streaming operator to set the columns of the matrix: // example: // mat33_t m; // m << v0 << v1 << v2; // column_builder<> stores the matrix and knows which column to set template struct column_builder { mat& matrix; column_builder(mat& matrix) : matrix(matrix) { } }; // operator << is not a method of column_builder<> so we can // overload it for unauthorized values (partial specialization // not allowed in class-scope). // we just set the column and return the next column_builder<> template friend column_builder operator << ( const column_builder& lhs, const vec& rhs) { lhs.matrix[PREV_COLUMN+1] = rhs; return column_builder(lhs.matrix); } // we return void here so we get a compile-time error if the // user tries to set too many columns friend void operator << ( const column_builder& lhs, const vec& rhs) { lhs.matrix[C-1] = rhs; } // this is where the process starts. we set the first columns and // return the next column_builder<> column_builder<0> operator << (const vec& rhs) { (*this)[0] = rhs; return column_builder<0>(*this); } }; // Specialize column matrix so they're exactly equivalent to a vector template class mat : public vec { typedef vec base; public: // STL-like interface. typedef TYPE value_type; typedef TYPE& reference; typedef TYPE const& const_reference; typedef size_t size_type; size_type size() const { return R; } enum { ROWS = R, COLS = 1 }; mat() { } mat(const base& rhs) : base(rhs) { } mat(const mat& rhs) : base(rhs) { } mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); } mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; } mat& operator=(const base& rhs) { base::operator=(rhs); return *this; } mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); } // we only have one column, so ignore the index const base& operator[](size_t) const { return *this; } base& operator[](size_t) { return *this; } void operator << (const vec& rhs) { base::operator[](0) = rhs; } }; // ----------------------------------------------------------------------- // matrix functions // transpose. this handles matrices of matrices inline int PURE transpose(int v) { return v; } inline float PURE transpose(float v) { return v; } inline double PURE transpose(double v) { return v; } // Transpose a matrix template mat PURE transpose(const mat& m) { mat r; for (size_t i=0 ; i static TYPE trace(const mat& m) { TYPE t; for (size_t i=0 ; i static bool isPositiveSemidefinite(const mat& m, TYPE tolerance) { for (size_t i=0 ; i tolerance) return false; return true; } // Transpose a vector template < template class VEC, typename TYPE, size_t SIZE > mat PURE transpose(const VEC& v) { mat r; for (size_t i=0 ; i mat PURE invert(const mat& src) { T t; size_t swap; mat tmp(src); mat inverse(1); for (size_t i=0 ; i fabs(tmp[i][i])) { swap = j; } } if (swap != i) { /* swap rows. */ for (size_t k=0 ; k mat22_t; typedef mat mat33_t; typedef mat mat44_t; // ----------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_MAT_H */ services/sensorservice/quat.h0100644 0000000 0000000 00000005276 13077405420 015461 0ustar000000000 0000000 /* * 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_QUAT_H #define ANDROID_QUAT_H #include #include "vec.h" #include "mat.h" // ----------------------------------------------------------------------- namespace android { // ----------------------------------------------------------------------- template mat quatToMatrix(const vec& q) { mat R; TYPE q0(q.w); TYPE q1(q.x); TYPE q2(q.y); TYPE q3(q.z); TYPE sq_q1 = 2 * q1 * q1; TYPE sq_q2 = 2 * q2 * q2; TYPE sq_q3 = 2 * q3 * q3; TYPE q1_q2 = 2 * q1 * q2; TYPE q3_q0 = 2 * q3 * q0; TYPE q1_q3 = 2 * q1 * q3; TYPE q2_q0 = 2 * q2 * q0; TYPE q2_q3 = 2 * q2 * q3; TYPE q1_q0 = 2 * q1 * q0; R[0][0] = 1 - sq_q2 - sq_q3; R[0][1] = q1_q2 - q3_q0; R[0][2] = q1_q3 + q2_q0; R[1][0] = q1_q2 + q3_q0; R[1][1] = 1 - sq_q1 - sq_q3; R[1][2] = q2_q3 - q1_q0; R[2][0] = q1_q3 - q2_q0; R[2][1] = q2_q3 + q1_q0; R[2][2] = 1 - sq_q1 - sq_q2; return R; } template vec matrixToQuat(const mat& R) { // matrix to quaternion struct { inline TYPE operator()(TYPE v) { return v < 0 ? 0 : v; } } clamp; vec q; const float Hx = R[0].x; const float My = R[1].y; const float Az = R[2].z; q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ); q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ); q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ); q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f ); q.x = copysignf(q.x, R[2].y - R[1].z); q.y = copysignf(q.y, R[0].z - R[2].x); q.z = copysignf(q.z, R[1].x - R[0].y); // guaranteed to be unit-quaternion return q; } template vec normalize_quat(const vec& q) { vec r(q); if (r.w < 0) { r = -r; } return normalize(r); } // ----------------------------------------------------------------------- typedef vec4_t quat_t; // ----------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_QUAT_H */ services/sensorservice/tests/0040755 0000000 0000000 00000000000 13077405420 015471 5ustar000000000 0000000 services/sensorservice/tests/Android.mk0100644 0000000 0000000 00000000373 13077405420 017402 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ sensorservicetest.cpp LOCAL_SHARED_LIBRARIES := \ libcutils libutils libui libgui LOCAL_MODULE:= test-sensorservice LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) services/sensorservice/tests/sensorservicetest.cpp0100644 0000000 0000000 00000006300 13077405420 021763 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include using namespace android; static nsecs_t sStartTime = 0; int receiver(__unused int fd, __unused int events, void* data) { sp q((SensorEventQueue*)data); ssize_t n; ASensorEvent buffer[8]; static nsecs_t oldTimeStamp = 0; while ((n = q->read(buffer, 8)) > 0) { for (int i=0 ; i q = mgr.createEventQueue(); printf("queue=%p\n", q.get()); Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); printf("accelerometer=%p (%s)\n", accelerometer, accelerometer->getName().string()); sStartTime = systemTime(); q->enableSensor(accelerometer); q->setEventRate(accelerometer, ms2ns(10)); sp loop = new Looper(false); loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get()); do { //printf("about to poll...\n"); int32_t ret = loop->pollOnce(-1); switch (ret) { case ALOOPER_POLL_WAKE: //("ALOOPER_POLL_WAKE\n"); break; case ALOOPER_POLL_CALLBACK: //("ALOOPER_POLL_CALLBACK\n"); break; case ALOOPER_POLL_TIMEOUT: printf("ALOOPER_POLL_TIMEOUT\n"); break; case ALOOPER_POLL_ERROR: printf("ALOOPER_POLL_TIMEOUT\n"); break; default: printf("ugh? poll returned %d\n", ret); break; } } while (1); return 0; } services/sensorservice/traits.h0100644 0000000 0000000 00000006516 13077405420 016013 0ustar000000000 0000000 /* * 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_TRAITS_H #define ANDROID_TRAITS_H // ----------------------------------------------------------------------- // Typelists namespace android { // end-of-list marker class NullType {}; // type-list node template struct TypeList { typedef T Head; typedef U Tail; }; // helpers to build typelists #define TYPELIST_1(T1) TypeList #define TYPELIST_2(T1, T2) TypeList #define TYPELIST_3(T1, T2, T3) TypeList #define TYPELIST_4(T1, T2, T3, T4) TypeList // typelists algorithms namespace TL { template struct IndexOf; template struct IndexOf { enum { value = -1 }; }; template struct IndexOf, T> { enum { value = 0 }; }; template struct IndexOf, T> { private: enum { temp = IndexOf::value }; public: enum { value = temp == -1 ? -1 : 1 + temp }; }; }; // namespace TL // type selection based on a boolean template struct Select { typedef T Result; }; template struct Select { typedef U Result; }; // ----------------------------------------------------------------------- // Type traits template class TypeTraits { typedef TYPELIST_4( unsigned char, unsigned short, unsigned int, unsigned long int) UnsignedInts; typedef TYPELIST_4( signed char, signed short, signed int, signed long int) SignedInts; typedef TYPELIST_1( bool) OtherInts; typedef TYPELIST_3( float, double, long double) Floats; template struct PointerTraits { enum { result = false }; typedef NullType PointeeType; }; template struct PointerTraits { enum { result = true }; typedef U PointeeType; }; public: enum { isStdUnsignedInt = TL::IndexOf::value >= 0 }; enum { isStdSignedInt = TL::IndexOf::value >= 0 }; enum { isStdIntegral = TL::IndexOf::value >= 0 || isStdUnsignedInt || isStdSignedInt }; enum { isStdFloat = TL::IndexOf::value >= 0 }; enum { isPointer = PointerTraits::result }; enum { isStdArith = isStdIntegral || isStdFloat }; // best parameter type for given type typedef typename Select::Result ParameterType; }; // ----------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_TRAITS_H */ services/sensorservice/vec.h0100644 0000000 0000000 00000027702 13077405420 015262 0ustar000000000 0000000 /* * 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_VEC_H #define ANDROID_VEC_H #include #include #include #include "traits.h" // ----------------------------------------------------------------------- #define PURE __attribute__((pure)) namespace android { // ----------------------------------------------------------------------- // non-inline helpers template class vec; template struct vbase; namespace helpers { template inline T min(T a, T b) { return a inline T max(T a, T b) { return a>b ? a : b; } template < template class VEC, typename TYPE, size_t SIZE, size_t S> vec& doAssign( vec& lhs, const VEC& rhs) { const size_t minSize = min(SIZE, S); const size_t maxSize = max(SIZE, S); for (size_t i=0 ; i class VLHS, template class VRHS, typename TYPE, size_t SIZE > VLHS PURE doAdd( const VLHS& lhs, const VRHS& rhs) { VLHS r; for (size_t i=0 ; i class VLHS, template class VRHS, typename TYPE, size_t SIZE > VLHS PURE doSub( const VLHS& lhs, const VRHS& rhs) { VLHS r; for (size_t i=0 ; i class VEC, typename TYPE, size_t SIZE > VEC PURE doMulScalar( const VEC& lhs, typename TypeTraits::ParameterType rhs) { VEC r; for (size_t i=0 ; i class VEC, typename TYPE, size_t SIZE > VEC PURE doScalarMul( typename TypeTraits::ParameterType lhs, const VEC& rhs) { VEC r; for (size_t i=0 ; i. Without this, an extra conversion to vec<> would be needed. // // example: // vec4_t a; // vec3_t b; // vec3_t c = a.xyz + b; // // "a.xyz + b" is a mixed-operation between a vbase<> and a vec<>, requiring // a conversion of vbase<> to vec<>. The template gunk below avoids this, // by allowing the addition on these different vector types directly // template < template class VLHS, template class VRHS, typename TYPE, size_t SIZE > inline VLHS PURE operator + ( const VLHS& lhs, const VRHS& rhs) { return helpers::doAdd(lhs, rhs); } template < template class VLHS, template class VRHS, typename TYPE, size_t SIZE > inline VLHS PURE operator - ( const VLHS& lhs, const VRHS& rhs) { return helpers::doSub(lhs, rhs); } template < template class VEC, typename TYPE, size_t SIZE > inline VEC PURE operator * ( const VEC& lhs, typename TypeTraits::ParameterType rhs) { return helpers::doMulScalar(lhs, rhs); } template < template class VEC, typename TYPE, size_t SIZE > inline VEC PURE operator * ( typename TypeTraits::ParameterType lhs, const VEC& rhs) { return helpers::doScalarMul(lhs, rhs); } template < template class VLHS, template class VRHS, typename TYPE, size_t SIZE > TYPE PURE dot_product( const VLHS& lhs, const VRHS& rhs) { TYPE r(0); for (size_t i=0 ; i class V, typename TYPE, size_t SIZE > TYPE PURE length(const V& v) { return sqrt(dot_product(v, v)); } template < template class V, typename TYPE, size_t SIZE > TYPE PURE length_squared(const V& v) { return dot_product(v, v); } template < template class V, typename TYPE, size_t SIZE > V PURE normalize(const V& v) { return v * (1/length(v)); } template < template class VLHS, template class VRHS, typename TYPE > VLHS PURE cross_product( const VLHS& u, const VRHS& v) { VLHS r; r.x = u.y*v.z - u.z*v.y; r.y = u.z*v.x - u.x*v.z; r.z = u.x*v.y - u.y*v.x; return r; } template vec PURE operator - (const vec& lhs) { vec r; for (size_t i=0 ; i struct vbase { TYPE v[SIZE]; inline const TYPE& operator[](size_t i) const { return v[i]; } inline TYPE& operator[](size_t i) { return v[i]; } }; template<> struct vbase { union { float v[2]; struct { float x, y; }; struct { float s, t; }; }; inline const float& operator[](size_t i) const { return v[i]; } inline float& operator[](size_t i) { return v[i]; } }; template<> struct vbase { union { float v[3]; struct { float x, y, z; }; struct { float s, t, r; }; vbase xy; vbase st; }; inline const float& operator[](size_t i) const { return v[i]; } inline float& operator[](size_t i) { return v[i]; } }; template<> struct vbase { union { float v[4]; struct { float x, y, z, w; }; struct { float s, t, r, q; }; vbase xyz; vbase str; vbase xy; vbase st; }; inline const float& operator[](size_t i) const { return v[i]; } inline float& operator[](size_t i) { return v[i]; } }; // ----------------------------------------------------------------------- template class vec : public vbase { typedef typename TypeTraits::ParameterType pTYPE; typedef vbase base; public: // STL-like interface. typedef TYPE value_type; typedef TYPE& reference; typedef TYPE const& const_reference; typedef size_t size_type; typedef TYPE* iterator; typedef TYPE const* const_iterator; iterator begin() { return base::v; } iterator end() { return base::v + SIZE; } const_iterator begin() const { return base::v; } const_iterator end() const { return base::v + SIZE; } size_type size() const { return SIZE; } // ----------------------------------------------------------------------- // default constructors vec() { } vec(const vec& rhs) : base(rhs) { } vec(const base& rhs) : base(rhs) { } // ----------------------------------------------------------------------- // conversion constructors vec(pTYPE rhs) { for (size_t i=0 ; i class VEC, size_t S> explicit vec(const VEC& rhs) { helpers::doAssign(*this, rhs); } explicit vec(TYPE const* array) { for (size_t i=0 ; i class VEC, size_t S> vec& operator = (const VEC& rhs) { return helpers::doAssign(*this, rhs); } // ----------------------------------------------------------------------- // operation-assignment vec& operator += (const vec& rhs); vec& operator -= (const vec& rhs); vec& operator *= (pTYPE rhs); // ----------------------------------------------------------------------- // non-member function declaration and definition // NOTE: we declare the non-member function as friend inside the class // so that they are known to the compiler when the class is instantiated. // This helps the compiler doing template argument deduction when the // passed types are not identical. Essentially this helps with // type conversion so that you can multiply a vec by an scalar int // (for instance). friend inline vec PURE operator + (const vec& lhs, const vec& rhs) { return helpers::doAdd(lhs, rhs); } friend inline vec PURE operator - (const vec& lhs, const vec& rhs) { return helpers::doSub(lhs, rhs); } friend inline vec PURE operator * (const vec& lhs, pTYPE v) { return helpers::doMulScalar(lhs, v); } friend inline vec PURE operator * (pTYPE v, const vec& rhs) { return helpers::doScalarMul(v, rhs); } friend inline TYPE PURE dot_product(const vec& lhs, const vec& rhs) { return android::dot_product(lhs, rhs); } }; // ----------------------------------------------------------------------- template vec& vec::operator += (const vec& rhs) { vec& lhs(*this); for (size_t i=0 ; i vec& vec::operator -= (const vec& rhs) { vec& lhs(*this); for (size_t i=0 ; i vec& vec::operator *= (vec::pTYPE rhs) { vec& lhs(*this); for (size_t i=0 ; i vec2_t; typedef vec vec3_t; typedef vec vec4_t; // ----------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_VEC_H */ services/surfaceflinger/0040755 0000000 0000000 00000000000 13077405420 014434 5ustar000000000 0000000 services/surfaceflinger/Android.mk0100644 0000000 0000000 00000011763 13077405420 016352 0ustar000000000 0000000 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := \ Client.cpp \ DisplayDevice.cpp \ DispSync.cpp \ EventControlThread.cpp \ EventThread.cpp \ FenceTracker.cpp \ FrameTracker.cpp \ GpuService.cpp \ Layer.cpp \ LayerDim.cpp \ MessageQueue.cpp \ MonitoredProducer.cpp \ SurfaceFlingerConsumer.cpp \ Transform.cpp \ DisplayHardware/FramebufferSurface.cpp \ DisplayHardware/HWC2.cpp \ DisplayHardware/HWC2On1Adapter.cpp \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ Effects/Daltonizer.cpp \ EventLog/EventLogTags.logtags \ EventLog/EventLog.cpp \ RenderEngine/Description.cpp \ RenderEngine/Mesh.cpp \ RenderEngine/Program.cpp \ RenderEngine/ProgramCache.cpp \ RenderEngine/GLExtensions.cpp \ RenderEngine/RenderEngine.cpp \ RenderEngine/Texture.cpp \ RenderEngine/GLES10RenderEngine.cpp \ RenderEngine/GLES11RenderEngine.cpp \ RenderEngine/GLES20RenderEngine.cpp LOCAL_C_INCLUDES := \ frameworks/native/vulkan/include \ external/vulkan-validation-layers/libs/vkjson LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES #LOCAL_CFLAGS += -DENABLE_FENCE_TRACKING USE_HWC2 := false ifeq ($(USE_HWC2),true) LOCAL_CFLAGS += -DUSE_HWC2 LOCAL_SRC_FILES += \ SurfaceFlinger.cpp \ DisplayHardware/HWComposer.cpp else LOCAL_SRC_FILES += \ SurfaceFlinger_hwc1.cpp \ DisplayHardware/HWComposer_hwc1.cpp endif ifeq ($(TARGET_BOARD_PLATFORM),omap4) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING endif ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS endif ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) endif ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true) LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK endif # See build/target/board/generic/BoardConfig.mk for a description of this setting. ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),) LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS) else LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=0 endif # See build/target/board/generic/BoardConfig.mk for a description of this setting. ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),) LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS) else LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=0 endif ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),) LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS) else LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0 endif ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),) LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION) else LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0 endif LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_CFLAGS += -std=c++14 LOCAL_STATIC_LIBRARIES := libvkjson LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ libdl \ libhardware \ libutils \ libEGL \ libGLESv1_CM \ libGLESv2 \ libbinder \ libui \ libgui \ libpowermanager \ libvulkan LOCAL_MODULE := libsurfaceflinger LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_SHARED_LIBRARY) ############################################################### # build surfaceflinger's executable include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CPPFLAGS := -std=c++14 LOCAL_INIT_RC := surfaceflinger.rc ifneq ($(ENABLE_CPUSETS),) LOCAL_CFLAGS += -DENABLE_CPUSETS endif LOCAL_SRC_FILES := \ main_surfaceflinger.cpp LOCAL_SHARED_LIBRARIES := \ libsurfaceflinger \ libcutils \ liblog \ libbinder \ libutils \ libdl LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain LOCAL_MODULE := surfaceflinger ifdef TARGET_32_BIT_SURFACEFLINGER LOCAL_32_BIT_ONLY := true endif LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_EXECUTABLE) ############################################################### # uses jni which may not be available in PDK ifneq ($(wildcard libnativehelper/include),) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CPPFLAGS := -std=c++14 LOCAL_SRC_FILES := \ DdmConnection.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ libdl LOCAL_MODULE := libsurfaceflinger_ddmconnection LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_SHARED_LIBRARY) endif # libnativehelper services/surfaceflinger/Barrier.h0100644 0000000 0000000 00000003357 13077405420 016200 0ustar000000000 0000000 /* * Copyright (C) 2007 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_BARRIER_H #define ANDROID_BARRIER_H #include #include #include namespace android { class Barrier { public: inline Barrier() : state(CLOSED) { } inline ~Barrier() { } // Release any threads waiting at the Barrier. // Provides release semantics: preceding loads and stores will be visible // to other threads before they wake up. void open() { Mutex::Autolock _l(lock); state = OPENED; cv.broadcast(); } // Reset the Barrier, so wait() will block until open() has been called. void close() { Mutex::Autolock _l(lock); state = CLOSED; } // Wait until the Barrier is OPEN. // Provides acquire semantics: no subsequent loads or stores will occur // until wait() returns. void wait() const { Mutex::Autolock _l(lock); while (state == CLOSED) { cv.wait(lock); } } private: enum { OPENED, CLOSED }; mutable Mutex lock; mutable Condition cv; volatile int state; }; }; // namespace android #endif // ANDROID_BARRIER_H services/surfaceflinger/Client.cpp0100644 0000000 0000000 00000012432 13077405420 016355 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include #include #include "Client.h" #include "Layer.h" #include "SurfaceFlinger.h" namespace android { // --------------------------------------------------------------------------- const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); // --------------------------------------------------------------------------- Client::Client(const sp& flinger) : mFlinger(flinger) { } Client::~Client() { const size_t count = mLayers.size(); for (size_t i=0 ; i layer(mLayers.valueAt(i).promote()); if (layer != 0) { mFlinger->removeLayer(layer); } } } status_t Client::initCheck() const { return NO_ERROR; } void Client::attachLayer(const sp& handle, const sp& layer) { Mutex::Autolock _l(mLock); mLayers.add(handle, layer); } void Client::detachLayer(const Layer* layer) { Mutex::Autolock _l(mLock); // we do a linear search here, because this doesn't happen often const size_t count = mLayers.size(); for (size_t i=0 ; i Client::getLayerUser(const sp& handle) const { Mutex::Autolock _l(mLock); sp lbc; wp layer(mLayers.valueFor(handle)); if (layer != 0) { lbc = layer.promote(); ALOGE_IF(lbc==0, "getLayerUser(name=%p) is dead", handle.get()); } return lbc; } status_t Client::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // these must be checked IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); const int self_pid = getpid(); if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) { // we're called from a different process, do the real check if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { ALOGE("Permission Denial: " "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } } return BnSurfaceComposerClient::onTransact(code, data, reply, flags); } status_t Client::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) { /* * createSurface must be called from the GL thread so that it can * have access to the GL context. */ class MessageCreateLayer : public MessageBase { SurfaceFlinger* flinger; Client* client; sp* handle; sp* gbp; status_t result; const String8& name; uint32_t w, h; PixelFormat format; uint32_t flags; public: MessageCreateLayer(SurfaceFlinger* flinger, const String8& name, Client* client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) : flinger(flinger), client(client), handle(handle), gbp(gbp), result(NO_ERROR), name(name), w(w), h(h), format(format), flags(flags) { } status_t getResult() const { return result; } virtual bool handler() { result = flinger->createLayer(name, client, w, h, format, flags, handle, gbp); return true; } }; sp msg = new MessageCreateLayer(mFlinger.get(), name, this, w, h, format, flags, handle, gbp); mFlinger->postMessageSync(msg); return static_cast( msg.get() )->getResult(); } status_t Client::destroySurface(const sp& handle) { return mFlinger->onLayerRemoved(this, handle); } status_t Client::clearLayerFrameStats(const sp& handle) const { sp layer = getLayerUser(handle); if (layer == NULL) { return NAME_NOT_FOUND; } layer->clearFrameStats(); return NO_ERROR; } status_t Client::getLayerFrameStats(const sp& handle, FrameStats* outStats) const { sp layer = getLayerUser(handle); if (layer == NULL) { return NAME_NOT_FOUND; } layer->getFrameStats(outStats); return NO_ERROR; } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/Client.h0100644 0000000 0000000 00000004517 13077405420 016027 0ustar000000000 0000000 /* * Copyright (C) 2012 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_SF_CLIENT_H #define ANDROID_SF_CLIENT_H #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class Layer; class SurfaceFlinger; // --------------------------------------------------------------------------- class Client : public BnSurfaceComposerClient { public: Client(const sp& flinger); ~Client(); status_t initCheck() const; // protected by SurfaceFlinger::mStateLock void attachLayer(const sp& handle, const sp& layer); void detachLayer(const Layer* layer); sp getLayerUser(const sp& handle) const; private: // ISurfaceComposerClient interface virtual status_t createSurface( const String8& name, uint32_t w, uint32_t h,PixelFormat format, uint32_t flags, sp* handle, sp* gbp); virtual status_t destroySurface(const sp& handle); virtual status_t clearLayerFrameStats(const sp& handle) const; virtual status_t getLayerFrameStats(const sp& handle, FrameStats* outStats) const; virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); // constant sp mFlinger; // protected by mLock DefaultKeyedVector< wp, wp > mLayers; // thread-safe mutable Mutex mLock; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_CLIENT_H services/surfaceflinger/Colorizer.h0100644 0000000 0000000 00000003065 13077405420 016556 0ustar000000000 0000000 /* * Copyright 2013 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_SURFACE_FLINGER_COLORIZER_H #define ANDROID_SURFACE_FLINGER_COLORIZER_H namespace android { // --------------------------------------------------------------------------- class Colorizer { bool mEnabled; public: enum color { RED = 31, GREEN = 32, YELLOW = 33, BLUE = 34, MAGENTA = 35, CYAN = 36, WHITE = 37 }; Colorizer(bool enabled) : mEnabled(enabled) { } void colorize(String8& out, color c) { if (mEnabled) { out.appendFormat("\e[%dm", c); } } void bold(String8& out) { if (mEnabled) { out.append("\e[1m"); } } void reset(String8& out) { if (mEnabled) { out.append("\e[0m"); } } }; // --------------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_SURFACE_FLINGER_COLORIZER_H */ services/surfaceflinger/DdmConnection.cpp0100644 0000000 0000000 00000007322 13077405420 017665 0ustar000000000 0000000 /* * 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 #include #include "jni.h" #include "DdmConnection.h" namespace android { void DdmConnection_start(const char* name) { ALOGI("DdmConnection_start"); DdmConnection::start(name); } void DdmConnection::start(const char* name) { JavaVM* vm; JNIEnv* env; // start a VM JavaVMInitArgs args; JavaVMOption opt; opt.optionString = "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"; args.version = JNI_VERSION_1_4; args.options = &opt; args.nOptions = 1; args.ignoreUnrecognized = JNI_FALSE; // TODO: Should this just link against libnativehelper and use its // JNI_CreateJavaVM wrapper that essential does this dlopen/dlsym // work based on the current system default runtime? void* libart_dso = dlopen("libart.so", RTLD_NOW); ALOGE_IF(!libart_dso, "DdmConnection: %s", dlerror()); void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW); ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror()); if (!libart_dso || !libandroid_runtime_dso) { goto error; } jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args); JNI_CreateJavaVM = reinterpret_cast( dlsym(libart_dso, "JNI_CreateJavaVM")); ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror()); jint (*registerNatives)(JNIEnv* env, jclass clazz); registerNatives = reinterpret_cast( dlsym(libandroid_runtime_dso, "Java_com_android_internal_util_WithFramework_registerNatives")); ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); if (!JNI_CreateJavaVM || !registerNatives) { goto error; } if (JNI_CreateJavaVM(&vm, &env, &args) == 0) { jclass startClass; jmethodID startMeth; // register native code if (registerNatives(env, 0) == 0) { // set our name by calling DdmHandleAppName.setAppName() startClass = env->FindClass("android/ddm/DdmHandleAppName"); if (startClass) { startMeth = env->GetStaticMethodID(startClass, "setAppName", "(Ljava/lang/String;I)V"); if (startMeth) { jstring str = env->NewStringUTF(name); env->CallStaticVoidMethod(startClass, startMeth, str, getuid()); env->DeleteLocalRef(str); } } // initialize DDMS communication by calling // DdmRegister.registerHandlers() startClass = env->FindClass("android/ddm/DdmRegister"); if (startClass) { startMeth = env->GetStaticMethodID(startClass, "registerHandlers", "()V"); if (startMeth) { env->CallStaticVoidMethod(startClass, startMeth); } } } } return; error: if (libandroid_runtime_dso) { dlclose(libandroid_runtime_dso); } if (libart_dso) { dlclose(libart_dso); } } }; // namespace android services/surfaceflinger/DdmConnection.h0100644 0000000 0000000 00000001637 13077405420 017335 0ustar000000000 0000000 /* * 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_SF_DDM_CONNECTION #define ANDROID_SF_DDM_CONNECTION namespace android { // wrapper for dlsym extern "C" void DdmConnection_start(const char* name); class DdmConnection { public: static void start(const char* name); }; }; // namespace android #endif /* ANDROID_SF_DDM_CONNECTION */ services/surfaceflinger/DispSync.cpp0100644 0000000 0000000 00000054702 13077405420 016701 0ustar000000000 0000000 /* * Copyright (C) 2013 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 // This is needed for stdint.h to define INT64_MAX in C++ #define __STDC_LIMIT_MACROS #include #include #include #include #include #include #include #include "DispSync.h" #include "EventLog/EventLog.h" #include using std::max; using std::min; namespace android { // Setting this to true enables verbose tracing that can be used to debug // vsync event model or phase issues. static const bool kTraceDetailedInfo = false; // Setting this to true adds a zero-phase tracer for correlating with hardware // vsync events static const bool kEnableZeroPhaseTracer = false; // This is the threshold used to determine when hardware vsync events are // needed to re-synchronize the software vsync model with the hardware. The // error metric used is the mean of the squared difference between each // present time and the nearest software-predicted vsync. static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared // This is the offset from the present fence timestamps to the corresponding // vsync event. static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS; #undef LOG_TAG #define LOG_TAG "DispSyncThread" class DispSyncThread: public Thread { public: DispSyncThread(const char* name): mName(name), mStop(false), mPeriod(0), mPhase(0), mReferenceTime(0), mWakeupLatency(0), mFrameNumber(0) {} virtual ~DispSyncThread() {} void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) { if (kTraceDetailedInfo) ATRACE_CALL(); Mutex::Autolock lock(mMutex); mPeriod = period; mPhase = phase; mReferenceTime = referenceTime; ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64 " mReferenceTime = %" PRId64, mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime)); mCond.signal(); } void stop() { if (kTraceDetailedInfo) ATRACE_CALL(); Mutex::Autolock lock(mMutex); mStop = true; mCond.signal(); } virtual bool threadLoop() { status_t err; nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); while (true) { Vector callbackInvocations; nsecs_t targetTime = 0; { // Scope for lock Mutex::Autolock lock(mMutex); if (kTraceDetailedInfo) { ATRACE_INT64("DispSync:Frame", mFrameNumber); } ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber); ++mFrameNumber; if (mStop) { return false; } if (mPeriod == 0) { err = mCond.wait(mMutex); if (err != NO_ERROR) { ALOGE("error waiting for new events: %s (%d)", strerror(-err), err); return false; } continue; } targetTime = computeNextEventTimeLocked(now); bool isWakeup = false; if (now < targetTime) { if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting"); if (targetTime == INT64_MAX) { ALOGV("[%s] Waiting forever", mName); err = mCond.wait(mMutex); } else { ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime)); err = mCond.waitRelative(mMutex, targetTime - now); } if (err == TIMED_OUT) { isWakeup = true; } else if (err != NO_ERROR) { ALOGE("error waiting for next event: %s (%d)", strerror(-err), err); return false; } } now = systemTime(SYSTEM_TIME_MONOTONIC); // Don't correct by more than 1.5 ms static const nsecs_t kMaxWakeupLatency = us2ns(1500); if (isWakeup) { mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64; mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency); if (kTraceDetailedInfo) { ATRACE_INT64("DispSync:WakeupLat", now - targetTime); ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency); } } callbackInvocations = gatherCallbackInvocationsLocked(now); } if (callbackInvocations.size() > 0) { fireCallbackInvocations(callbackInvocations); } } return false; } status_t addEventListener(const char* name, nsecs_t phase, const sp& callback) { if (kTraceDetailedInfo) ATRACE_CALL(); Mutex::Autolock lock(mMutex); for (size_t i = 0; i < mEventListeners.size(); i++) { if (mEventListeners[i].mCallback == callback) { return BAD_VALUE; } } EventListener listener; listener.mName = name; listener.mPhase = phase; listener.mCallback = callback; // We want to allow the firstmost future event to fire without // allowing any past events to fire listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency; mEventListeners.push(listener); mCond.signal(); return NO_ERROR; } status_t removeEventListener(const sp& callback) { if (kTraceDetailedInfo) ATRACE_CALL(); Mutex::Autolock lock(mMutex); for (size_t i = 0; i < mEventListeners.size(); i++) { if (mEventListeners[i].mCallback == callback) { mEventListeners.removeAt(i); mCond.signal(); return NO_ERROR; } } return BAD_VALUE; } // This method is only here to handle the kIgnorePresentFences case. bool hasAnyEventListeners() { if (kTraceDetailedInfo) ATRACE_CALL(); Mutex::Autolock lock(mMutex); return !mEventListeners.empty(); } private: struct EventListener { const char* mName; nsecs_t mPhase; nsecs_t mLastEventTime; sp mCallback; }; struct CallbackInvocation { sp mCallback; nsecs_t mEventTime; }; nsecs_t computeNextEventTimeLocked(nsecs_t now) { if (kTraceDetailedInfo) ATRACE_CALL(); ALOGV("[%s] computeNextEventTimeLocked", mName); nsecs_t nextEventTime = INT64_MAX; for (size_t i = 0; i < mEventListeners.size(); i++) { nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now); if (t < nextEventTime) { nextEventTime = t; } } ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime)); return nextEventTime; } Vector gatherCallbackInvocationsLocked(nsecs_t now) { if (kTraceDetailedInfo) ATRACE_CALL(); ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now)); Vector callbackInvocations; nsecs_t onePeriodAgo = now - mPeriod; for (size_t i = 0; i < mEventListeners.size(); i++) { nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo); if (t < now) { CallbackInvocation ci; ci.mCallback = mEventListeners[i].mCallback; ci.mEventTime = t; ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName); callbackInvocations.push(ci); mEventListeners.editItemAt(i).mLastEventTime = t; } } return callbackInvocations; } nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) { if (kTraceDetailedInfo) ATRACE_CALL(); ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName, ns2us(baseTime)); nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency; ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime)); if (baseTime < lastEventTime) { baseTime = lastEventTime; ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime)); } baseTime -= mReferenceTime; ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime)); nsecs_t phase = mPhase + listener.mPhase; ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase)); baseTime -= phase; ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime)); // If our previous time is before the reference (because the reference // has since been updated), the division by mPeriod will truncate // towards zero instead of computing the floor. Since in all cases // before the reference we want the next time to be effectively now, we // set baseTime to -mPeriod so that numPeriods will be -1. // When we add 1 and the phase, we will be at the correct event time for // this period. if (baseTime < 0) { ALOGV("[%s] Correcting negative baseTime", mName); baseTime = -mPeriod; } nsecs_t numPeriods = baseTime / mPeriod; ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods); nsecs_t t = (numPeriods + 1) * mPeriod + phase; ALOGV("[%s] t = %" PRId64, mName, ns2us(t)); t += mReferenceTime; ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t)); // Check that it's been slightly more than half a period since the last // event so that we don't accidentally fall into double-rate vsyncs if (t - listener.mLastEventTime < (3 * mPeriod / 5)) { t += mPeriod; ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t)); } t -= mWakeupLatency; ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t)); return t; } void fireCallbackInvocations(const Vector& callbacks) { if (kTraceDetailedInfo) ATRACE_CALL(); for (size_t i = 0; i < callbacks.size(); i++) { callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); } } const char* const mName; bool mStop; nsecs_t mPeriod; nsecs_t mPhase; nsecs_t mReferenceTime; nsecs_t mWakeupLatency; int64_t mFrameNumber; Vector mEventListeners; Mutex mMutex; Condition mCond; }; #undef LOG_TAG #define LOG_TAG "DispSync" class ZeroPhaseTracer : public DispSync::Callback { public: ZeroPhaseTracer() : mParity(false) {} virtual void onDispSyncEvent(nsecs_t /*when*/) { mParity = !mParity; ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0); } private: bool mParity; }; DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) { mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); reset(); beginResync(); if (kTraceDetailedInfo) { // If we're not getting present fences then the ZeroPhaseTracer // would prevent HW vsync event from ever being turned off. // Even if we're just ignoring the fences, the zero-phase tracing is // not needed because any time there is an event registered we will // turn on the HW vsync events. if (!kIgnorePresentFences && kEnableZeroPhaseTracer) { addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer()); } } } DispSync::~DispSync() {} void DispSync::reset() { Mutex::Autolock lock(mMutex); mPhase = 0; mReferenceTime = 0; mModelUpdated = false; mNumResyncSamples = 0; mFirstResyncSample = 0; mNumResyncSamplesSincePresent = 0; resetErrorLocked(); } bool DispSync::addPresentFence(const sp& fence) { Mutex::Autolock lock(mMutex); mPresentFences[mPresentSampleOffset] = fence; mPresentTimes[mPresentSampleOffset] = 0; mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES; mNumResyncSamplesSincePresent = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { const sp& f(mPresentFences[i]); if (f != NULL) { nsecs_t t = f->getSignalTime(); if (t < INT64_MAX) { mPresentFences[i].clear(); mPresentTimes[i] = t + kPresentTimeOffset; } } } updateErrorLocked(); return !mModelUpdated || mError > kErrorThreshold; } void DispSync::beginResync() { Mutex::Autolock lock(mMutex); ALOGV("[%s] beginResync", mName); mModelUpdated = false; mNumResyncSamples = 0; } bool DispSync::addResyncSample(nsecs_t timestamp) { Mutex::Autolock lock(mMutex); ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp)); size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; mResyncSamples[idx] = timestamp; if (mNumResyncSamples == 0) { mPhase = 0; mReferenceTime = timestamp; ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, " "mReferenceTime = %" PRId64, mName, ns2us(mPeriod), ns2us(mReferenceTime)); mThread->updateModel(mPeriod, mPhase, mReferenceTime); } if (mNumResyncSamples < MAX_RESYNC_SAMPLES) { mNumResyncSamples++; } else { mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES; } updateModelLocked(); if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) { resetErrorLocked(); } if (kIgnorePresentFences) { // If we don't have the sync framework we will never have // addPresentFence called. This means we have no way to know whether // or not we're synchronized with the HW vsyncs, so we just request // that the HW vsync events be turned on whenever we need to generate // SW vsync events. return mThread->hasAnyEventListeners(); } // Check against kErrorThreshold / 2 to add some hysteresis before having to // resync again bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2); ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked"); return !modelLocked; } void DispSync::endResync() { } status_t DispSync::addEventListener(const char* name, nsecs_t phase, const sp& callback) { Mutex::Autolock lock(mMutex); return mThread->addEventListener(name, phase, callback); } void DispSync::setRefreshSkipCount(int count) { Mutex::Autolock lock(mMutex); ALOGD("setRefreshSkipCount(%d)", count); mRefreshSkipCount = count; updateModelLocked(); } status_t DispSync::removeEventListener(const sp& callback) { Mutex::Autolock lock(mMutex); return mThread->removeEventListener(callback); } void DispSync::setPeriod(nsecs_t period) { Mutex::Autolock lock(mMutex); mPeriod = period; mPhase = 0; mReferenceTime = 0; mThread->updateModel(mPeriod, mPhase, mReferenceTime); } nsecs_t DispSync::getPeriod() { // lock mutex as mPeriod changes multiple times in updateModelLocked Mutex::Autolock lock(mMutex); return mPeriod; } void DispSync::updateModelLocked() { ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples); if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) { ALOGV("[%s] Computing...", mName); nsecs_t durationSum = 0; nsecs_t minDuration = INT64_MAX; nsecs_t maxDuration = 0; for (size_t i = 1; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES; nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev]; durationSum += duration; minDuration = min(minDuration, duration); maxDuration = max(maxDuration, duration); } // Exclude the min and max from the average durationSum -= minDuration + maxDuration; mPeriod = durationSum / (mNumResyncSamples - 3); ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod)); double sampleAvgX = 0; double sampleAvgY = 0; double scale = 2.0 * M_PI / double(mPeriod); // Intentionally skip the first sample for (size_t i = 1; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; nsecs_t sample = mResyncSamples[idx] - mReferenceTime; double samplePhase = double(sample % mPeriod) * scale; sampleAvgX += cos(samplePhase); sampleAvgY += sin(samplePhase); } sampleAvgX /= double(mNumResyncSamples - 1); sampleAvgY /= double(mNumResyncSamples - 1); mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale); ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase)); if (mPhase < -(mPeriod / 2)) { mPhase += mPeriod; ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase)); } if (kTraceDetailedInfo) { ATRACE_INT64("DispSync:Period", mPeriod); ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2); } // Artificially inflate the period if requested. mPeriod += mPeriod * mRefreshSkipCount; mThread->updateModel(mPeriod, mPhase, mReferenceTime); mModelUpdated = true; } } void DispSync::updateErrorLocked() { if (!mModelUpdated) { return; } // Need to compare present fences against the un-adjusted refresh period, // since they might arrive between two events. nsecs_t period = mPeriod / (1 + mRefreshSkipCount); int numErrSamples = 0; nsecs_t sqErrSum = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { nsecs_t sample = mPresentTimes[i] - mReferenceTime; if (sample > mPhase) { nsecs_t sampleErr = (sample - mPhase) % period; if (sampleErr > period / 2) { sampleErr -= period; } sqErrSum += sampleErr * sampleErr; numErrSamples++; } } if (numErrSamples > 0) { mError = sqErrSum / numErrSamples; } else { mError = 0; } if (kTraceDetailedInfo) { ATRACE_INT64("DispSync:Error", mError); } } void DispSync::resetErrorLocked() { mPresentSampleOffset = 0; mError = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { mPresentFences[i].clear(); mPresentTimes[i] = 0; } } nsecs_t DispSync::computeNextRefresh(int periodOffset) const { Mutex::Autolock lock(mMutex); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t phase = mReferenceTime + mPhase; return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase; } void DispSync::dump(String8& result) const { Mutex::Autolock lock(mMutex); result.appendFormat("present fences are %s\n", kIgnorePresentFences ? "ignored" : "used"); result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount); result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase); result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError)); result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n", mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT); result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES); result.appendFormat("mResyncSamples:\n"); nsecs_t previous = -1; for (size_t i = 0; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; nsecs_t sampleTime = mResyncSamples[idx]; if (i == 0) { result.appendFormat(" %" PRId64 "\n", sampleTime); } else { result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n", sampleTime, sampleTime - previous); } previous = sampleTime; } result.appendFormat("mPresentFences / mPresentTimes [%d]:\n", NUM_PRESENT_SAMPLES); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); previous = 0; for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES; bool signaled = mPresentFences[idx] == NULL; nsecs_t presentTime = mPresentTimes[idx]; if (!signaled) { result.appendFormat(" [unsignaled fence]\n"); } else if (presentTime == 0) { result.appendFormat(" 0\n"); } else if (previous == 0) { result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime, (now - presentTime) / 1000000.0); } else { result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n", presentTime, presentTime - previous, (presentTime - previous) / (double) mPeriod, (now - presentTime) / 1000000.0); } previous = presentTime; } result.appendFormat("current monotonic time: %" PRId64 "\n", now); } } // namespace android services/surfaceflinger/DispSync.h0100644 0000000 0000000 00000016106 13077405420 016342 0ustar000000000 0000000 /* * Copyright (C) 2012 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_DISPSYNC_H #define ANDROID_DISPSYNC_H #include #include #include #include namespace android { // Ignore present (retire) fences if the device doesn't have support for the // sync framework #if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) static const bool kIgnorePresentFences = true; #else static const bool kIgnorePresentFences = false; #endif class String8; class Fence; class DispSyncThread; // DispSync maintains a model of the periodic hardware-based vsync events of a // display and uses that model to execute period callbacks at specific phase // offsets from the hardware vsync events. The model is constructed by // feeding consecutive hardware event timestamps to the DispSync object via // the addResyncSample method. // // The model is validated using timestamps from Fence objects that are passed // to the DispSync object via the addPresentFence method. These fence // timestamps should correspond to a hardware vsync event, but they need not // be consecutive hardware vsync times. If this method determines that the // current model accurately represents the hardware event times it will return // false to indicate that a resynchronization (via addResyncSample) is not // needed. class DispSync { public: class Callback: public virtual RefBase { public: virtual ~Callback() {}; virtual void onDispSyncEvent(nsecs_t when) = 0; }; DispSync(const char* name); ~DispSync(); // reset clears the resync samples and error value. void reset(); // addPresentFence adds a fence for use in validating the current vsync // event model. The fence need not be signaled at the time // addPresentFence is called. When the fence does signal, its timestamp // should correspond to a hardware vsync event. Unlike the // addResyncSample method, the timestamps of consecutive fences need not // correspond to consecutive hardware vsync events. // // This method should be called with the retire fence from each HWComposer // set call that affects the display. bool addPresentFence(const sp& fence); // The beginResync, addResyncSample, and endResync methods are used to re- // synchronize the DispSync's model to the hardware vsync events. The re- // synchronization process involves first calling beginResync, then // calling addResyncSample with a sequence of consecutive hardware vsync // event timestamps, and finally calling endResync when addResyncSample // indicates that no more samples are needed by returning false. // // This resynchronization process should be performed whenever the display // is turned on (i.e. once immediately after it's turned on) and whenever // addPresentFence returns true indicating that the model has drifted away // from the hardware vsync events. void beginResync(); bool addResyncSample(nsecs_t timestamp); void endResync(); // The setPeriod method sets the vsync event model's period to a specific // value. This should be used to prime the model when a display is first // turned on. It should NOT be used after that. void setPeriod(nsecs_t period); // The getPeriod method returns the current vsync period. nsecs_t getPeriod(); // setRefreshSkipCount specifies an additional number of refresh // cycles to skip. For example, on a 60Hz display, a skip count of 1 // will result in events happening at 30Hz. Default is zero. The idea // is to sacrifice smoothness for battery life. void setRefreshSkipCount(int count); // addEventListener registers a callback to be called repeatedly at the // given phase offset from the hardware vsync events. The callback is // called from a separate thread and it should return reasonably quickly // (i.e. within a few hundred microseconds). status_t addEventListener(const char* name, nsecs_t phase, const sp& callback); // removeEventListener removes an already-registered event callback. Once // this method returns that callback will no longer be called by the // DispSync object. status_t removeEventListener(const sp& callback); // computeNextRefresh computes when the next refresh is expected to begin. // The periodOffset value can be used to move forward or backward; an // offset of zero is the next refresh, -1 is the previous refresh, 1 is // the refresh after next. etc. nsecs_t computeNextRefresh(int periodOffset) const; // dump appends human-readable debug info to the result string. void dump(String8& result) const; private: void updateModelLocked(); void updateErrorLocked(); void resetErrorLocked(); enum { MAX_RESYNC_SAMPLES = 32 }; enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 }; enum { NUM_PRESENT_SAMPLES = 8 }; enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; const char* const mName; // mPeriod is the computed period of the modeled vsync events in // nanoseconds. nsecs_t mPeriod; // mPhase is the phase offset of the modeled vsync events. It is the // number of nanoseconds from time 0 to the first vsync event. nsecs_t mPhase; // mReferenceTime is the reference time of the modeled vsync events. // It is the nanosecond timestamp of the first vsync event after a resync. nsecs_t mReferenceTime; // mError is the computed model error. It is based on the difference // between the estimated vsync event times and those observed in the // mPresentTimes array. nsecs_t mError; // Whether we have updated the vsync event model since the last resync. bool mModelUpdated; // These member variables are the state used during the resynchronization // process to store information about the hardware vsync event times used // to compute the model. nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES]; size_t mFirstResyncSample; size_t mNumResyncSamples; int mNumResyncSamplesSincePresent; // These member variables store information about the present fences used // to validate the currently computed model. sp mPresentFences[NUM_PRESENT_SAMPLES]; nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES]; size_t mPresentSampleOffset; int mRefreshSkipCount; // mThread is the thread from which all the callbacks are called. sp mThread; // mMutex is used to protect access to all member variables. mutable Mutex mMutex; }; } #endif // ANDROID_DISPSYNC_H services/surfaceflinger/DisplayDevice.cpp0100644 0000000 0000000 00000044701 13077405420 017670 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "DisplayDevice" #include #include #include #include #include #include #include #include #include #include #include #include "DisplayHardware/DisplaySurface.h" #include "DisplayHardware/HWComposer.h" #ifdef USE_HWC2 #include "DisplayHardware/HWC2.h" #endif #include "RenderEngine/RenderEngine.h" #include "clz.h" #include "DisplayDevice.h" #include "SurfaceFlinger.h" #include "Layer.h" // ---------------------------------------------------------------------------- using namespace android; // ---------------------------------------------------------------------------- #ifdef EGL_ANDROID_swap_rectangle static constexpr bool kEGLAndroidSwapRectangle = true; #else static constexpr bool kEGLAndroidSwapRectangle = false; #endif #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle) // Dummy implementation in case it is missing. inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) { } #endif /* * Initialize the display to the specified values. * */ uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0; DisplayDevice::DisplayDevice( const sp& flinger, DisplayType type, int32_t hwcId, #ifndef USE_HWC2 int format, #endif bool isSecure, const wp& displayToken, const sp& displaySurface, const sp& producer, EGLConfig config) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), mDisplaySurface(displaySurface), mDisplay(EGL_NO_DISPLAY), mSurface(EGL_NO_SURFACE), mDisplayWidth(), mDisplayHeight(), #ifndef USE_HWC2 mFormat(), #endif mFlags(), mPageFlipCount(), mIsSecure(isSecure), mLayerStack(NO_LAYER_STACK), mOrientation(), mPowerMode(HWC_POWER_MODE_OFF), mActiveConfig(0) { Surface* surface; mNativeWindow = surface = new Surface(producer, false); ANativeWindow* const window = mNativeWindow.get(); /* * Create our display's surface */ EGLSurface eglSurface; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { #ifdef USE_HWC2 config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); #else config = RenderEngine::chooseEglConfig(display, format); #endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth); eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight); // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. We have to do this // in two places: // * Here, in case the display is composed entirely by HWC. // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the // window's swap interval in eglMakeCurrent, so they'll override the // interval we set here. if (mType >= DisplayDevice::DISPLAY_VIRTUAL) window->setSwapInterval(window, 0); mConfig = config; mDisplay = display; mSurface = eglSurface; #ifndef USE_HWC2 mFormat = format; #endif mPageFlipCount = 0; mViewport.makeInvalid(); mFrame.makeInvalid(); // virtual displays are always considered enabled mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; // Name the display. The name will be replaced shortly if the display // was created with createDisplay(). switch (mType) { case DISPLAY_PRIMARY: mDisplayName = "Built-in Screen"; break; case DISPLAY_EXTERNAL: mDisplayName = "HDMI Screen"; break; default: mDisplayName = "Virtual Screen"; // e.g. Overlay #n break; } // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); #ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS surface->allocateBuffers(); #endif } DisplayDevice::~DisplayDevice() { if (mSurface != EGL_NO_SURFACE) { eglDestroySurface(mDisplay, mSurface); mSurface = EGL_NO_SURFACE; } } void DisplayDevice::disconnect(HWComposer& hwc) { if (mHwcDisplayId >= 0) { hwc.disconnectDisplay(mHwcDisplayId); #ifndef USE_HWC2 if (mHwcDisplayId >= DISPLAY_VIRTUAL) hwc.freeDisplayId(mHwcDisplayId); #endif mHwcDisplayId = -1; } } bool DisplayDevice::isValid() const { return mFlinger != NULL; } int DisplayDevice::getWidth() const { return mDisplayWidth; } int DisplayDevice::getHeight() const { return mDisplayHeight; } #ifndef USE_HWC2 PixelFormat DisplayDevice::getFormat() const { return mFormat; } #endif EGLSurface DisplayDevice::getEGLSurface() const { return mSurface; } void DisplayDevice::setDisplayName(const String8& displayName) { if (!displayName.isEmpty()) { // never override the name with an empty name mDisplayName = displayName; } } uint32_t DisplayDevice::getPageFlipCount() const { return mPageFlipCount; } #ifndef USE_HWC2 status_t DisplayDevice::compositionComplete() const { return mDisplaySurface->compositionComplete(); } #endif void DisplayDevice::flip(const Region& dirty) const { mFlinger->getRenderEngine().checkErrors(); if (kEGLAndroidSwapRectangle) { if (mFlags & SWAP_RECTANGLE) { const Region newDirty(dirty.intersect(bounds())); const Rect b(newDirty.getBounds()); eglSetSwapRectangleANDROID(mDisplay, mSurface, b.left, b.top, b.width(), b.height()); } } mPageFlipCount++; } status_t DisplayDevice::beginFrame(bool mustRecompose) const { return mDisplaySurface->beginFrame(mustRecompose); } #ifdef USE_HWC2 status_t DisplayDevice::prepareFrame(HWComposer& hwc) { status_t error = hwc.prepare(*this); if (error != NO_ERROR) { return error; } DisplaySurface::CompositionType compositionType; bool hasClient = hwc.hasClientComposition(mHwcDisplayId); bool hasDevice = hwc.hasDeviceComposition(mHwcDisplayId); if (hasClient && hasDevice) { compositionType = DisplaySurface::COMPOSITION_MIXED; } else if (hasClient) { compositionType = DisplaySurface::COMPOSITION_GLES; } else if (hasDevice) { compositionType = DisplaySurface::COMPOSITION_HWC; } else { // Nothing to do -- when turning the screen off we get a frame like // this. Call it a HWC frame since we won't be doing any GLES work but // will do a prepare/set cycle. compositionType = DisplaySurface::COMPOSITION_HWC; } return mDisplaySurface->prepareFrame(compositionType); } #else status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const { DisplaySurface::CompositionType compositionType; bool haveGles = hwc.hasGlesComposition(mHwcDisplayId); bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId); if (haveGles && haveHwc) { compositionType = DisplaySurface::COMPOSITION_MIXED; } else if (haveGles) { compositionType = DisplaySurface::COMPOSITION_GLES; } else if (haveHwc) { compositionType = DisplaySurface::COMPOSITION_HWC; } else { // Nothing to do -- when turning the screen off we get a frame like // this. Call it a HWC frame since we won't be doing any GLES work but // will do a prepare/set cycle. compositionType = DisplaySurface::COMPOSITION_HWC; } return mDisplaySurface->prepareFrame(compositionType); } #endif void DisplayDevice::swapBuffers(HWComposer& hwc) const { #ifdef USE_HWC2 if (hwc.hasClientComposition(mHwcDisplayId)) { #else // We need to call eglSwapBuffers() if: // (1) we don't have a hardware composer, or // (2) we did GLES composition this frame, and either // (a) we have framebuffer target support (not present on legacy // devices, where HWComposer::commit() handles things); or // (b) this is a virtual display if (hwc.initCheck() != NO_ERROR || (hwc.hasGlesComposition(mHwcDisplayId) && (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) { #endif EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); if (!success) { EGLint error = eglGetError(); if (error == EGL_CONTEXT_LOST || mType == DisplayDevice::DISPLAY_PRIMARY) { LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x", mDisplay, mSurface, error); } else { ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x", mDisplay, mSurface, error); } } } status_t result = mDisplaySurface->advanceFrame(); if (result != NO_ERROR) { ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.string(), result); } } #ifdef USE_HWC2 void DisplayDevice::onSwapBuffersCompleted() const { mDisplaySurface->onFrameCommitted(); } #else void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const { if (hwc.initCheck() == NO_ERROR) { mDisplaySurface->onFrameCommitted(); } } #endif uint32_t DisplayDevice::getFlags() const { return mFlags; } EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const { EGLBoolean result = EGL_TRUE; EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); if (sur != mSurface) { result = eglMakeCurrent(dpy, mSurface, mSurface, ctx); if (result == EGL_TRUE) { if (mType >= DisplayDevice::DISPLAY_VIRTUAL) eglSwapInterval(dpy, 0); } } setViewportAndProjection(); return result; } void DisplayDevice::setViewportAndProjection() const { size_t w = mDisplayWidth; size_t h = mDisplayHeight; Rect sourceCrop(0, 0, w, h); mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, h, false, Transform::ROT_0); } const sp& DisplayDevice::getClientTargetAcquireFence() const { return mDisplaySurface->getClientTargetAcquireFence(); } // ---------------------------------------------------------------------------- void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp >& layers) { mVisibleLayersSortedByZ = layers; } const Vector< sp >& DisplayDevice::getVisibleLayersSortedByZ() const { return mVisibleLayersSortedByZ; } Region DisplayDevice::getDirtyRegion(bool repaintEverything) const { Region dirty; if (repaintEverything) { dirty.set(getBounds()); } else { const Transform& planeTransform(mGlobalTransform); dirty = planeTransform.transform(this->dirtyRegion); dirty.andSelf(getBounds()); } return dirty; } // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(int mode) { mPowerMode = mode; } int DisplayDevice::getPowerMode() const { return mPowerMode; } bool DisplayDevice::isDisplayOn() const { return (mPowerMode != HWC_POWER_MODE_OFF); } // ---------------------------------------------------------------------------- void DisplayDevice::setActiveConfig(int mode) { mActiveConfig = mode; } int DisplayDevice::getActiveConfig() const { return mActiveConfig; } // ---------------------------------------------------------------------------- void DisplayDevice::setLayerStack(uint32_t stack) { mLayerStack = stack; dirtyRegion.set(bounds()); } // ---------------------------------------------------------------------------- uint32_t DisplayDevice::getOrientationTransform() const { uint32_t transform = 0; switch (mOrientation) { case DisplayState::eOrientationDefault: transform = Transform::ROT_0; break; case DisplayState::eOrientation90: transform = Transform::ROT_90; break; case DisplayState::eOrientation180: transform = Transform::ROT_180; break; case DisplayState::eOrientation270: transform = Transform::ROT_270; break; } return transform; } status_t DisplayDevice::orientationToTransfrom( int orientation, int w, int h, Transform* tr) { uint32_t flags = 0; switch (orientation) { case DisplayState::eOrientationDefault: flags = Transform::ROT_0; break; case DisplayState::eOrientation90: flags = Transform::ROT_90; break; case DisplayState::eOrientation180: flags = Transform::ROT_180; break; case DisplayState::eOrientation270: flags = Transform::ROT_270; break; default: return BAD_VALUE; } tr->set(flags, w, h); return NO_ERROR; } void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) { dirtyRegion.set(getBounds()); if (mSurface != EGL_NO_SURFACE) { eglDestroySurface(mDisplay, mSurface); mSurface = EGL_NO_SURFACE; } mDisplaySurface->resizeBuffers(newWidth, newHeight); ANativeWindow* const window = mNativeWindow.get(); mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL); eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mDisplayWidth); eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight); LOG_FATAL_IF(mDisplayWidth != newWidth, "Unable to set new width to %d", newWidth); LOG_FATAL_IF(mDisplayHeight != newHeight, "Unable to set new height to %d", newHeight); } void DisplayDevice::setProjection(int orientation, const Rect& newViewport, const Rect& newFrame) { Rect viewport(newViewport); Rect frame(newFrame); const int w = mDisplayWidth; const int h = mDisplayHeight; Transform R; DisplayDevice::orientationToTransfrom(orientation, w, h, &R); if (!frame.isValid()) { // the destination frame can be invalid if it has never been set, // in that case we assume the whole display frame. frame = Rect(w, h); } if (viewport.isEmpty()) { // viewport can be invalid if it has never been set, in that case // we assume the whole display size. // it's also invalid to have an empty viewport, so we handle that // case in the same way. viewport = Rect(w, h); if (R.getOrientation() & Transform::ROT_90) { // viewport is always specified in the logical orientation // of the display (ie: post-rotation). swap(viewport.right, viewport.bottom); } } dirtyRegion.set(getBounds()); Transform TL, TP, S; float src_width = viewport.width(); float src_height = viewport.height(); float dst_width = frame.width(); float dst_height = frame.height(); if (src_width != dst_width || src_height != dst_height) { float sx = dst_width / src_width; float sy = dst_height / src_height; S.set(sx, 0, 0, sy); } float src_x = viewport.left; float src_y = viewport.top; float dst_x = frame.left; float dst_y = frame.top; TL.set(-src_x, -src_y); TP.set(dst_x, dst_y); // The viewport and frame are both in the logical orientation. // Apply the logical translation, scale to physical size, apply the // physical translation and finally rotate to the physical orientation. mGlobalTransform = R * TP * S * TL; const uint8_t type = mGlobalTransform.getType(); mNeedsFiltering = (!mGlobalTransform.preserveRects() || (type >= Transform::SCALE)); mScissor = mGlobalTransform.transform(viewport); if (mScissor.isEmpty()) { mScissor = getBounds(); } mOrientation = orientation; if (mType == DisplayType::DISPLAY_PRIMARY) { uint32_t transform = 0; switch (mOrientation) { case DisplayState::eOrientationDefault: transform = Transform::ROT_0; break; case DisplayState::eOrientation90: transform = Transform::ROT_90; break; case DisplayState::eOrientation180: transform = Transform::ROT_180; break; case DisplayState::eOrientation270: transform = Transform::ROT_270; break; } sPrimaryDisplayOrientation = transform; } mViewport = viewport; mFrame = frame; } uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { return sPrimaryDisplayOrientation; } void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); result.appendFormat( "+ DisplayDevice: %s\n" " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n" " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", mDisplayName.string(), mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(), mOrientation, tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size(), mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); result.append(surfaceDump); } services/surfaceflinger/DisplayDevice.h0100644 0000000 0000000 00000017161 13077405420 017335 0ustar000000000 0000000 /* * Copyright (C) 2007 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_DISPLAY_DEVICE_H #define ANDROID_DISPLAY_DEVICE_H #include "Transform.h" #include #ifndef USE_HWC2 #include #endif #include #include #include #ifdef USE_HWC2 #include #include #endif #include #include #include #include #ifdef USE_HWC2 #include #endif struct ANativeWindow; namespace android { struct DisplayInfo; class DisplaySurface; class Fence; class IGraphicBufferProducer; class Layer; class SurfaceFlinger; class HWComposer; class DisplayDevice : public LightRefBase { public: // region in layer-stack space mutable Region dirtyRegion; // region in screen space mutable Region swapRegion; // region in screen space Region undefinedRegion; bool lastCompositionHadVisibleLayers; enum DisplayType { DISPLAY_ID_INVALID = -1, DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL, DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL, NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES, }; enum { PARTIAL_UPDATES = 0x00020000, // video driver feature SWAP_RECTANGLE = 0x00080000, }; enum { NO_LAYER_STACK = 0xFFFFFFFF, }; DisplayDevice( const sp& flinger, DisplayType type, int32_t hwcId, #ifndef USE_HWC2 int format, #endif bool isSecure, const wp& displayToken, const sp& displaySurface, const sp& producer, EGLConfig config); ~DisplayDevice(); // whether this is a valid object. An invalid DisplayDevice is returned // when an non existing id is requested bool isValid() const; // isSecure indicates whether this display can be trusted to display // secure surfaces. bool isSecure() const { return mIsSecure; } // Flip the front and back buffers if the back buffer is "dirty". Might // be instantaneous, might involve copying the frame buffer around. void flip(const Region& dirty) const; int getWidth() const; int getHeight() const; #ifndef USE_HWC2 PixelFormat getFormat() const; #endif uint32_t getFlags() const; EGLSurface getEGLSurface() const; void setVisibleLayersSortedByZ(const Vector< sp >& layers); const Vector< sp >& getVisibleLayersSortedByZ() const; Region getDirtyRegion(bool repaintEverything) const; void setLayerStack(uint32_t stack); void setDisplaySize(const int newWidth, const int newHeight); void setProjection(int orientation, const Rect& viewport, const Rect& frame); int getOrientation() const { return mOrientation; } uint32_t getOrientationTransform() const; static uint32_t getPrimaryDisplayOrientationTransform(); const Transform& getTransform() const { return mGlobalTransform; } const Rect getViewport() const { return mViewport; } const Rect getFrame() const { return mFrame; } const Rect& getScissor() const { return mScissor; } bool needsFiltering() const { return mNeedsFiltering; } uint32_t getLayerStack() const { return mLayerStack; } int32_t getDisplayType() const { return mType; } int32_t getHwcDisplayId() const { return mHwcDisplayId; } const wp& getDisplayToken() const { return mDisplayToken; } // We pass in mustRecompose so we can keep VirtualDisplaySurface's state // machine happy without actually queueing a buffer if nothing has changed status_t beginFrame(bool mustRecompose) const; #ifdef USE_HWC2 status_t prepareFrame(HWComposer& hwc); #else status_t prepareFrame(const HWComposer& hwc) const; #endif void swapBuffers(HWComposer& hwc) const; #ifndef USE_HWC2 status_t compositionComplete() const; #endif // called after h/w composer has completed its set() call #ifdef USE_HWC2 void onSwapBuffersCompleted() const; #else void onSwapBuffersCompleted(HWComposer& hwc) const; #endif Rect getBounds() const { return Rect(mDisplayWidth, mDisplayHeight); } inline Rect bounds() const { return getBounds(); } void setDisplayName(const String8& displayName); const String8& getDisplayName() const { return mDisplayName; } EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const; void setViewportAndProjection() const; const sp& getClientTargetAcquireFence() const; /* ------------------------------------------------------------------------ * Display power mode management. */ int getPowerMode() const; void setPowerMode(int mode); bool isDisplayOn() const; /* ------------------------------------------------------------------------ * Display active config management. */ int getActiveConfig() const; void setActiveConfig(int mode); // release HWC resources (if any) for removable displays void disconnect(HWComposer& hwc); /* ------------------------------------------------------------------------ * Debugging */ uint32_t getPageFlipCount() const; void dump(String8& result) const; private: /* * Constants, set during initialization */ sp mFlinger; DisplayType mType; int32_t mHwcDisplayId; wp mDisplayToken; // ANativeWindow this display is rendering into sp mNativeWindow; sp mDisplaySurface; EGLConfig mConfig; EGLDisplay mDisplay; EGLSurface mSurface; int mDisplayWidth; int mDisplayHeight; #ifndef USE_HWC2 PixelFormat mFormat; #endif uint32_t mFlags; mutable uint32_t mPageFlipCount; String8 mDisplayName; bool mIsSecure; /* * Can only accessed from the main thread, these members * don't need synchronization. */ // list of visible layers on that display Vector< sp > mVisibleLayersSortedByZ; /* * Transaction state */ static status_t orientationToTransfrom(int orientation, int w, int h, Transform* tr); uint32_t mLayerStack; int mOrientation; static uint32_t sPrimaryDisplayOrientation; // user-provided visible area of the layer stack Rect mViewport; // user-provided rectangle where mViewport gets mapped to Rect mFrame; // pre-computed scissor to apply to the display Rect mScissor; Transform mGlobalTransform; bool mNeedsFiltering; // Current power mode int mPowerMode; // Current active config int mActiveConfig; }; }; // namespace android #endif // ANDROID_DISPLAY_DEVICE_H services/surfaceflinger/DisplayHardware/0040755 0000000 0000000 00000000000 13077405420 017517 5ustar000000000 0000000 services/surfaceflinger/DisplayHardware/DisplaySurface.h0100644 0000000 0000000 00000006771 13077405420 022616 0ustar000000000 0000000 /* * Copyright 2013 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_SF_DISPLAY_SURFACE_H #define ANDROID_SF_DISPLAY_SURFACE_H #include #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class IGraphicBufferProducer; class String8; class DisplaySurface : public virtual RefBase { public: // beginFrame is called at the beginning of the composition loop, before // the configuration is known. The DisplaySurface should do anything it // needs to do to enable HWComposer to decide how to compose the frame. // We pass in mustRecompose so we can keep VirtualDisplaySurface's state // machine happy without actually queueing a buffer if nothing has changed. virtual status_t beginFrame(bool mustRecompose) = 0; // prepareFrame is called after the composition configuration is known but // before composition takes place. The DisplaySurface can use the // composition type to decide how to manage the flow of buffers between // GLES and HWC for this frame. enum CompositionType { COMPOSITION_UNKNOWN = 0, COMPOSITION_GLES = 1, COMPOSITION_HWC = 2, COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC }; virtual status_t prepareFrame(CompositionType compositionType) = 0; #ifndef USE_HWC2 // Should be called when composition rendering is complete for a frame (but // eglSwapBuffers hasn't necessarily been called). Required by certain // older drivers for synchronization. // TODO: Remove this when we drop support for HWC 1.0. virtual status_t compositionComplete() = 0; #endif // Inform the surface that GLES composition is complete for this frame, and // the surface should make sure that HWComposer has the correct buffer for // this frame. Some implementations may only push a new buffer to // HWComposer if GLES composition took place, others need to push a new // buffer on every frame. // // advanceFrame must be followed by a call to onFrameCommitted before // advanceFrame may be called again. virtual status_t advanceFrame() = 0; // onFrameCommitted is called after the frame has been committed to the // hardware composer. The surface collects the release fence for this // frame's buffer. virtual void onFrameCommitted() = 0; virtual void dumpAsString(String8& result) const = 0; virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0; virtual const sp& getClientTargetAcquireFence() const = 0; protected: DisplaySurface() {} virtual ~DisplaySurface() {} }; // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_SF_DISPLAY_SURFACE_H services/surfaceflinger/DisplayHardware/FloatRect.h0100644 0000000 0000000 00000002315 13077405420 021551 0ustar000000000 0000000 /* * Copyright 2013 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_SF_FLOAT_RECT #define ANDROID_SF_FLOAT_RECT #include #include namespace android { class FloatRect { public: float left; float top; float right; float bottom; inline FloatRect() : left(0), top(0), right(0), bottom(0) { } inline FloatRect(const Rect& other) : left(other.left), top(other.top), right(other.right), bottom(other.bottom) { } inline float getWidth() const { return right - left; } inline float getHeight() const { return bottom - top; } }; }; // namespace android #endif // ANDROID_SF_FLOAT_RECT services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp0100644 0000000 0000000 00000020411 13077405420 023753 0ustar000000000 0000000 /* ** ** Copyright 2012 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. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "FramebufferSurface" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FramebufferSurface.h" #include "HWComposer.h" #ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS #define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) #endif // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- /* * This implements the (main) framebuffer management. This class is used * mostly by SurfaceFlinger, but also by command line GL application. * */ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, const sp& consumer) : ConsumerBase(consumer), mDisplayType(disp), mCurrentBufferSlot(-1), mCurrentBuffer(), mCurrentFence(Fence::NO_FENCE), #ifdef USE_HWC2 mHwc(hwc), mHasPendingRelease(false), mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT), mPreviousBuffer() #else mHwc(hwc) #endif { #ifdef USE_HWC2 ALOGV("Creating for display %d", disp); #endif mName = "FramebufferSurface"; mConsumer->setConsumerName(mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); #ifdef USE_HWC2 const auto& activeConfig = mHwc.getActiveConfig(disp); mConsumer->setDefaultBufferSize(activeConfig->getWidth(), activeConfig->getHeight()); #else mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); #endif mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1); } status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { return NO_ERROR; } status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { return NO_ERROR; } status_t FramebufferSurface::advanceFrame() { #ifdef USE_HWC2 sp buf; sp acquireFence(Fence::NO_FENCE); android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; status_t result = nextBuffer(buf, acquireFence, dataspace); if (result != NO_ERROR) { ALOGE("error latching next FramebufferSurface buffer: %s (%d)", strerror(-result), result); return result; } result = mHwc.setClientTarget(mDisplayType, acquireFence, buf, dataspace); if (result != NO_ERROR) { ALOGE("error posting framebuffer: %d", result); } return result; #else // Once we remove FB HAL support, we can call nextBuffer() from here // instead of using onFrameAvailable(). No real benefit, except it'll be // more like VirtualDisplaySurface. return NO_ERROR; #endif } #ifdef USE_HWC2 status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& outFence, android_dataspace_t& outDataspace) { #else status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& outFence) { #endif Mutex::Autolock lock(mMutex); BufferItem item; status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { outBuffer = mCurrentBuffer; return NO_ERROR; } else if (err != NO_ERROR) { ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); return err; } // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot // then we may have acquired the slot we already own. If we had released // our current buffer before we call acquireBuffer then that release call // would have returned STALE_BUFFER_SLOT, and we would have called // freeBufferLocked on that slot. Because the buffer slot has already // been overwritten with the new buffer all we have to do is skip the // releaseBuffer call and we should be in the same state we'd be in if we // had released the old buffer first. if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mSlot != mCurrentBufferSlot) { #ifdef USE_HWC2 mHasPendingRelease = true; mPreviousBufferSlot = mCurrentBufferSlot; mPreviousBuffer = mCurrentBuffer; #else // Release the previous buffer. err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err < NO_ERROR) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; } #endif } mCurrentBufferSlot = item.mSlot; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; mCurrentFence = item.mFence; outFence = item.mFence; outBuffer = mCurrentBuffer; #ifdef USE_HWC2 outDataspace = item.mDataSpace; #endif return NO_ERROR; } #ifndef USE_HWC2 // Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) { sp buf; sp acquireFence; status_t err = nextBuffer(buf, acquireFence); if (err != NO_ERROR) { ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", strerror(-err), err); return; } err = mHwc.fbPost(mDisplayType, acquireFence, buf); if (err != NO_ERROR) { ALOGE("error posting framebuffer: %d", err); } } #endif void FramebufferSurface::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); if (slotIndex == mCurrentBufferSlot) { mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; } } void FramebufferSurface::onFrameCommitted() { #ifdef USE_HWC2 if (mHasPendingRelease) { sp fence = mHwc.getRetireFence(mDisplayType); if (fence->isValid()) { status_t result = addReleaseFence(mPreviousBufferSlot, mPreviousBuffer, fence); ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the" " fence: %s (%d)", strerror(-result), result); } status_t result = releaseBufferLocked(mPreviousBufferSlot, mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:" " %s (%d)", strerror(-result), result); mPreviousBuffer.clear(); mHasPendingRelease = false; } #else sp fence = mHwc.getAndResetReleaseFence(mDisplayType); if (fence->isValid() && mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { status_t err = addReleaseFence(mCurrentBufferSlot, mCurrentBuffer, fence); ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", strerror(-err), err); } #endif } #ifndef USE_HWC2 status_t FramebufferSurface::compositionComplete() { return mHwc.fbCompositionComplete(); } #endif void FramebufferSurface::dumpAsString(String8& result) const { ConsumerBase::dump(result); } void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { #ifndef USE_HWC2 mHwc.fbDump(result); #endif ConsumerBase::dumpLocked(result, prefix); } const sp& FramebufferSurface::getClientTargetAcquireFence() const { return mCurrentFence; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- services/surfaceflinger/DisplayHardware/FramebufferSurface.h0100644 0000000 0000000 00000007116 13077405420 023427 0ustar000000000 0000000 /* * Copyright (C) 2007 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_SF_FRAMEBUFFER_SURFACE_H #define ANDROID_SF_FRAMEBUFFER_SURFACE_H #include #include #include #include "DisplaySurface.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class Rect; class String8; class HWComposer; // --------------------------------------------------------------------------- class FramebufferSurface : public ConsumerBase, public DisplaySurface { public: FramebufferSurface(HWComposer& hwc, int disp, const sp& consumer); virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); #ifndef USE_HWC2 virtual status_t compositionComplete(); #endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; // Cannot resize a buffers in a FramebufferSurface. Only works with virtual // displays. virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { }; virtual const sp& getClientTargetAcquireFence() const override; private: virtual ~FramebufferSurface() { }; // this class cannot be overloaded #ifndef USE_HWC2 virtual void onFrameAvailable(const BufferItem& item); #endif virtual void freeBufferLocked(int slotIndex); virtual void dumpLocked(String8& result, const char* prefix) const; // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. #ifdef USE_HWC2 status_t nextBuffer(sp& outBuffer, sp& outFence, android_dataspace_t& outDataspace); #else status_t nextBuffer(sp& outBuffer, sp& outFence); #endif // mDisplayType must match one of the HWC display types int mDisplayType; // mCurrentBufferIndex is the slot index of the current buffer or // INVALID_BUFFER_SLOT to indicate that either there is no current buffer // or the buffer is not associated with a slot. int mCurrentBufferSlot; // mCurrentBuffer is the current buffer or NULL to indicate that there is // no current buffer. sp mCurrentBuffer; // mCurrentFence is the current buffer's acquire fence sp mCurrentFence; // Hardware composer, owned by SurfaceFlinger. HWComposer& mHwc; #ifdef USE_HWC2 // Previous buffer to release after getting an updated retire fence bool mHasPendingRelease; int mPreviousBufferSlot; sp mPreviousBuffer; #endif }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H services/surfaceflinger/DisplayHardware/HWC2.cpp0100644 0000000 0000000 00000106022 13077405420 020724 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "HWC2" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "HWC2.h" #include "FloatRect.h" #include #include #include #include #include #include extern "C" { static void hotplug_hook(hwc2_callback_data_t callbackData, hwc2_display_t displayId, int32_t intConnected) { auto device = static_cast(callbackData); auto display = device->getDisplayById(displayId); if (display) { auto connected = static_cast(intConnected); device->callHotplug(std::move(display), connected); } else { ALOGE("Hotplug callback called with unknown display %" PRIu64, displayId); } } static void refresh_hook(hwc2_callback_data_t callbackData, hwc2_display_t displayId) { auto device = static_cast(callbackData); auto display = device->getDisplayById(displayId); if (display) { device->callRefresh(std::move(display)); } else { ALOGE("Refresh callback called with unknown display %" PRIu64, displayId); } } static void vsync_hook(hwc2_callback_data_t callbackData, hwc2_display_t displayId, int64_t timestamp) { auto device = static_cast(callbackData); auto display = device->getDisplayById(displayId); if (display) { device->callVsync(std::move(display), timestamp); } else { ALOGE("Vsync callback called with unknown display %" PRIu64, displayId); } } } using android::Fence; using android::FloatRect; using android::GraphicBuffer; using android::HdrCapabilities; using android::Rect; using android::Region; using android::sp; namespace HWC2 { // Device methods Device::Device(hwc2_device_t* device) : mHwcDevice(device), mCreateVirtualDisplay(nullptr), mDestroyVirtualDisplay(nullptr), mDump(nullptr), mGetMaxVirtualDisplayCount(nullptr), mRegisterCallback(nullptr), mAcceptDisplayChanges(nullptr), mCreateLayer(nullptr), mDestroyLayer(nullptr), mGetActiveConfig(nullptr), mGetChangedCompositionTypes(nullptr), mGetColorModes(nullptr), mGetDisplayAttribute(nullptr), mGetDisplayConfigs(nullptr), mGetDisplayName(nullptr), mGetDisplayRequests(nullptr), mGetDisplayType(nullptr), mGetDozeSupport(nullptr), mGetHdrCapabilities(nullptr), mGetReleaseFences(nullptr), mPresentDisplay(nullptr), mSetActiveConfig(nullptr), mSetClientTarget(nullptr), mSetColorMode(nullptr), mSetColorTransform(nullptr), mSetOutputBuffer(nullptr), mSetPowerMode(nullptr), mSetVsyncEnabled(nullptr), mValidateDisplay(nullptr), mSetCursorPosition(nullptr), mSetLayerBuffer(nullptr), mSetLayerSurfaceDamage(nullptr), mSetLayerBlendMode(nullptr), mSetLayerColor(nullptr), mSetLayerCompositionType(nullptr), mSetLayerDataspace(nullptr), mSetLayerDisplayFrame(nullptr), mSetLayerPlaneAlpha(nullptr), mSetLayerSidebandStream(nullptr), mSetLayerSourceCrop(nullptr), mSetLayerTransform(nullptr), mSetLayerVisibleRegion(nullptr), mSetLayerZOrder(nullptr), mCapabilities(), mDisplays(), mHotplug(), mPendingHotplugs(), mRefresh(), mPendingRefreshes(), mVsync(), mPendingVsyncs() { loadCapabilities(); loadFunctionPointers(); registerCallbacks(); } Device::~Device() { if (mHwcDevice == nullptr) { return; } for (auto element : mDisplays) { auto display = element.second; DisplayType displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != Error::None) { ALOGE("~Device: Failed to determine type of display %" PRIu64 ": %s (%d)", display->getId(), to_string(error).c_str(), static_cast(error)); continue; } if (displayType == HWC2::DisplayType::Physical) { error = display->setVsyncEnabled(HWC2::Vsync::Disable); if (error != Error::None) { ALOGE("~Device: Failed to disable vsync for display %" PRIu64 ": %s (%d)", display->getId(), to_string(error).c_str(), static_cast(error)); } } } hwc2_close(mHwcDevice); } // Required by HWC2 device std::string Device::dump() const { uint32_t numBytes = 0; mDump(mHwcDevice, &numBytes, nullptr); std::vector buffer(numBytes); mDump(mHwcDevice, &numBytes, buffer.data()); return std::string(buffer.data(), buffer.size()); } uint32_t Device::getMaxVirtualDisplayCount() const { return mGetMaxVirtualDisplayCount(mHwcDevice); } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, android_pixel_format_t* format, std::shared_ptr* outDisplay) { ALOGI("Creating virtual display"); hwc2_display_t displayId = 0; int32_t intFormat = static_cast(*format); int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height, &intFormat, &displayId); auto error = static_cast(intError); if (error != Error::None) { return error; } ALOGI("Created virtual display"); *format = static_cast(intFormat); *outDisplay = getDisplayById(displayId); (*outDisplay)->setVirtual(); return Error::None; } void Device::registerHotplugCallback(HotplugCallback hotplug) { ALOGV("registerHotplugCallback"); mHotplug = hotplug; for (auto& pending : mPendingHotplugs) { auto& display = pending.first; auto connected = pending.second; ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(), to_string(connected).c_str()); mHotplug(std::move(display), connected); } } void Device::registerRefreshCallback(RefreshCallback refresh) { mRefresh = refresh; for (auto& pending : mPendingRefreshes) { mRefresh(std::move(pending)); } } void Device::registerVsyncCallback(VsyncCallback vsync) { mVsync = vsync; for (auto& pending : mPendingVsyncs) { auto& display = pending.first; auto timestamp = pending.second; mVsync(std::move(display), timestamp); } } // For use by Device callbacks void Device::callHotplug(std::shared_ptr display, Connection connected) { if (connected == Connection::Connected) { if (!display->isConnected()) { display->loadConfigs(); display->setConnected(true); } } else { display->setConnected(false); mDisplays.erase(display->getId()); } if (mHotplug) { mHotplug(std::move(display), connected); } else { ALOGV("callHotplug called, but no valid callback registered, storing"); mPendingHotplugs.emplace_back(std::move(display), connected); } } void Device::callRefresh(std::shared_ptr display) { if (mRefresh) { mRefresh(std::move(display)); } else { ALOGV("callRefresh called, but no valid callback registered, storing"); mPendingRefreshes.emplace_back(std::move(display)); } } void Device::callVsync(std::shared_ptr display, nsecs_t timestamp) { if (mVsync) { mVsync(std::move(display), timestamp); } else { ALOGV("callVsync called, but no valid callback registered, storing"); mPendingVsyncs.emplace_back(std::move(display), timestamp); } } // Other Device methods std::shared_ptr Device::getDisplayById(hwc2_display_t id) { if (mDisplays.count(id) != 0) { return mDisplays.at(id); } auto display = std::make_shared(*this, id); mDisplays.emplace(id, display); return display; } // Device initialization methods void Device::loadCapabilities() { static_assert(sizeof(Capability) == sizeof(int32_t), "Capability size has changed"); uint32_t numCapabilities = 0; mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr); mCapabilities.resize(numCapabilities); auto asInt = reinterpret_cast(mCapabilities.data()); mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt); } bool Device::hasCapability(HWC2::Capability capability) const { return std::find(mCapabilities.cbegin(), mCapabilities.cend(), capability) != mCapabilities.cend(); } void Device::loadFunctionPointers() { // For all of these early returns, we log an error message inside // loadFunctionPointer specifying which function failed to load // Display function pointers if (!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay, mCreateVirtualDisplay)) return; if (!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay, mDestroyVirtualDisplay)) return; if (!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return; if (!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount, mGetMaxVirtualDisplayCount)) return; if (!loadFunctionPointer(FunctionDescriptor::RegisterCallback, mRegisterCallback)) return; // Device function pointers if (!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges, mAcceptDisplayChanges)) return; if (!loadFunctionPointer(FunctionDescriptor::CreateLayer, mCreateLayer)) return; if (!loadFunctionPointer(FunctionDescriptor::DestroyLayer, mDestroyLayer)) return; if (!loadFunctionPointer(FunctionDescriptor::GetActiveConfig, mGetActiveConfig)) return; if (!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes, mGetChangedCompositionTypes)) return; if (!loadFunctionPointer(FunctionDescriptor::GetColorModes, mGetColorModes)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute, mGetDisplayAttribute)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs, mGetDisplayConfigs)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDisplayName, mGetDisplayName)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests, mGetDisplayRequests)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDisplayType, mGetDisplayType)) return; if (!loadFunctionPointer(FunctionDescriptor::GetDozeSupport, mGetDozeSupport)) return; if (!loadFunctionPointer(FunctionDescriptor::GetHdrCapabilities, mGetHdrCapabilities)) return; if (!loadFunctionPointer(FunctionDescriptor::GetReleaseFences, mGetReleaseFences)) return; if (!loadFunctionPointer(FunctionDescriptor::PresentDisplay, mPresentDisplay)) return; if (!loadFunctionPointer(FunctionDescriptor::SetActiveConfig, mSetActiveConfig)) return; if (!loadFunctionPointer(FunctionDescriptor::SetClientTarget, mSetClientTarget)) return; if (!loadFunctionPointer(FunctionDescriptor::SetColorMode, mSetColorMode)) return; if (!loadFunctionPointer(FunctionDescriptor::SetColorTransform, mSetColorTransform)) return; if (!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer, mSetOutputBuffer)) return; if (!loadFunctionPointer(FunctionDescriptor::SetPowerMode, mSetPowerMode)) return; if (!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled, mSetVsyncEnabled)) return; if (!loadFunctionPointer(FunctionDescriptor::ValidateDisplay, mValidateDisplay)) return; // Layer function pointers if (!loadFunctionPointer(FunctionDescriptor::SetCursorPosition, mSetCursorPosition)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer, mSetLayerBuffer)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage, mSetLayerSurfaceDamage)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode, mSetLayerBlendMode)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerColor, mSetLayerColor)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType, mSetLayerCompositionType)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerDataspace, mSetLayerDataspace)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame, mSetLayerDisplayFrame)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha, mSetLayerPlaneAlpha)) return; if (hasCapability(Capability::SidebandStream)) { if (!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream, mSetLayerSidebandStream)) return; } if (!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop, mSetLayerSourceCrop)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerTransform, mSetLayerTransform)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion, mSetLayerVisibleRegion)) return; if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder, mSetLayerZOrder)) return; } void Device::registerCallbacks() { registerCallback(Callback::Hotplug, hotplug_hook); registerCallback(Callback::Refresh, refresh_hook); registerCallback(Callback::Vsync, vsync_hook); } // For use by Display void Device::destroyVirtualDisplay(hwc2_display_t display) { ALOGI("Destroying virtual display"); int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display); auto error = static_cast(intError); ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" " %s (%d)", display, to_string(error).c_str(), intError); } // Display methods Display::Display(Device& device, hwc2_display_t id) : mDevice(device), mId(id), mIsConnected(false), mIsVirtual(false) { ALOGV("Created display %" PRIu64, id); } Display::~Display() { ALOGV("Destroyed display %" PRIu64, mId); if (mIsVirtual) { mDevice.destroyVirtualDisplay(mId); } } Display::Config::Config(Display& display, hwc2_config_t id) : mDisplay(display), mId(id), mWidth(-1), mHeight(-1), mVsyncPeriod(-1), mDpiX(-1), mDpiY(-1) {} Display::Config::Builder::Builder(Display& display, hwc2_config_t id) : mConfig(new Config(display, id)) {} float Display::Config::Builder::getDefaultDensity() { // Default density is based on TVs: 1080p displays get XHIGH density, lower- // resolution displays get TV density. Maybe eventually we'll need to update // it for 4k displays, though hopefully those will just report accurate DPI // information to begin with. This is also used for virtual displays and // older HWC implementations, so be careful about orientation. auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight); if (longDimension >= 1080) { return ACONFIGURATION_DENSITY_XHIGH; } else { return ACONFIGURATION_DENSITY_TV; } } // Required by HWC2 display Error Display::acceptChanges() { int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId); return static_cast(intError); } Error Display::createLayer(std::shared_ptr* outLayer) { hwc2_layer_t layerId = 0; int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId); auto error = static_cast(intError); if (error != Error::None) { return error; } auto layer = std::make_shared(shared_from_this(), layerId); mLayers.emplace(layerId, layer); *outLayer = std::move(layer); return Error::None; } Error Display::getActiveConfig( std::shared_ptr* outConfig) const { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId, &configId); auto error = static_cast(intError); if (error != Error::None) { return error; } if (mConfigs.count(configId) != 0) { *outConfig = mConfigs.at(configId); } else { ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId, configId); // Return no error, but the caller needs to check for a null pointer to // detect this case *outConfig = nullptr; } return Error::None; } Error Display::getChangedCompositionTypes( std::unordered_map, Composition>* outTypes) { uint32_t numElements = 0; int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId, &numElements, nullptr, nullptr); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector layerIds(numElements); std::vector types(numElements); intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId, &numElements, layerIds.data(), types.data()); error = static_cast(intError); if (error != Error::None) { return error; } outTypes->clear(); outTypes->reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { auto type = static_cast(types[element]); ALOGV("getChangedCompositionTypes: adding %" PRIu64 " %s", layer->getId(), to_string(type).c_str()); outTypes->emplace(layer, type); } else { ALOGE("getChangedCompositionTypes: invalid layer %" PRIu64 " found" " on display %" PRIu64, layerIds[element], mId); } } return Error::None; } Error Display::getColorModes(std::vector* outModes) const { uint32_t numModes = 0; int32_t intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, &numModes, nullptr); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector modes(numModes); intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, &numModes, modes.data()); error = static_cast(intError); if (error != Error::None) { return error; } std::swap(*outModes, modes); return Error::None; } std::vector> Display::getConfigs() const { std::vector> configs; for (const auto& element : mConfigs) { configs.emplace_back(element.second); } return configs; } Error Display::getName(std::string* outName) const { uint32_t size; int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size, nullptr); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector rawName(size); intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size, rawName.data()); error = static_cast(intError); if (error != Error::None) { return error; } *outName = std::string(rawName.cbegin(), rawName.cend()); return Error::None; } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, std::unordered_map, LayerRequest>* outLayerRequests) { int32_t intDisplayRequests = 0; uint32_t numElements = 0; int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId, &intDisplayRequests, &numElements, nullptr, nullptr); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector layerIds(numElements); std::vector layerRequests(numElements); intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId, &intDisplayRequests, &numElements, layerIds.data(), layerRequests.data()); error = static_cast(intError); if (error != Error::None) { return error; } *outDisplayRequests = static_cast(intDisplayRequests); outLayerRequests->clear(); outLayerRequests->reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { auto layerRequest = static_cast(layerRequests[element]); outLayerRequests->emplace(layer, layerRequest); } else { ALOGE("getRequests: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); } } return Error::None; } Error Display::getType(DisplayType* outType) const { int32_t intType = 0; int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId, &intType); auto error = static_cast(intError); if (error != Error::None) { return error; } *outType = static_cast(intType); return Error::None; } Error Display::supportsDoze(bool* outSupport) const { int32_t intSupport = 0; int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId, &intSupport); auto error = static_cast(intError); if (error != Error::None) { return error; } *outSupport = static_cast(intSupport); return Error::None; } Error Display::getHdrCapabilities( std::unique_ptr* outCapabilities) const { uint32_t numTypes = 0; float maxLuminance = -1.0f; float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes, nullptr, &maxLuminance, &maxAverageLuminance, &minLuminance); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector types(numTypes); intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes, types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance); error = static_cast(intError); if (error != Error::None) { return error; } *outCapabilities = std::make_unique(std::move(types), maxLuminance, maxAverageLuminance, minLuminance); return Error::None; } Error Display::getReleaseFences( std::unordered_map, sp>* outFences) const { uint32_t numElements = 0; int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements, nullptr, nullptr); auto error = static_cast(intError); if (error != Error::None) { return error; } std::vector layerIds(numElements); std::vector fenceFds(numElements); intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements, layerIds.data(), fenceFds.data()); error = static_cast(intError); if (error != Error::None) { return error; } std::unordered_map, sp> releaseFences; releaseFences.reserve(numElements); for (uint32_t element = 0; element < numElements; ++element) { auto layer = getLayerById(layerIds[element]); if (layer) { sp fence(new Fence(fenceFds[element])); releaseFences.emplace(std::move(layer), fence); } else { ALOGE("getReleaseFences: invalid layer %" PRIu64 " found on display %" PRIu64, layerIds[element], mId); return Error::BadLayer; } } *outFences = std::move(releaseFences); return Error::None; } Error Display::present(sp* outRetireFence) { int32_t retireFenceFd = 0; int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId, &retireFenceFd); auto error = static_cast(intError); if (error != Error::None) { return error; } *outRetireFence = new Fence(retireFenceFd); return Error::None; } Error Display::setActiveConfig(const std::shared_ptr& config) { if (config->getDisplayId() != mId) { ALOGE("setActiveConfig received config %u for the wrong display %" PRIu64 " (expected %" PRIu64 ")", config->getId(), config->getDisplayId(), mId); return Error::BadConfig; } int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId, config->getId()); return static_cast(intError); } Error Display::setClientTarget(buffer_handle_t target, const sp& acquireFence, android_dataspace_t dataspace) { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target, fenceFd, static_cast(dataspace), {0, nullptr}); return static_cast(intError); } Error Display::setColorMode(int32_t mode) { int32_t intError = mDevice.mSetColorMode(mDevice.mHwcDevice, mId, mode); return static_cast(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { int32_t intError = mDevice.mSetColorTransform(mDevice.mHwcDevice, mId, matrix.asArray(), static_cast(hint)); return static_cast(intError); } Error Display::setOutputBuffer(const sp& buffer, const sp& releaseFence) { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle, fenceFd); return static_cast(intError); } Error Display::setPowerMode(PowerMode mode) { auto intMode = static_cast(mode); int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode); return static_cast(intError); } Error Display::setVsyncEnabled(Vsync enabled) { auto intEnabled = static_cast(enabled); int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId, intEnabled); return static_cast(intError); } Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId, &numTypes, &numRequests); auto error = static_cast(intError); if (error != Error::None && error != Error::HasChanges) { return error; } *outNumTypes = numTypes; *outNumRequests = numRequests; return error; } // For use by Device int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId, configId, static_cast(attribute), &value); auto error = static_cast(intError); if (error != Error::None) { ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId, configId, to_string(attribute).c_str(), to_string(error).c_str(), intError); return -1; } return value; } void Display::loadConfig(hwc2_config_t configId) { ALOGV("[%" PRIu64 "] loadConfig(%u)", mId, configId); auto config = Config::Builder(*this, configId) .setWidth(getAttribute(configId, Attribute::Width)) .setHeight(getAttribute(configId, Attribute::Height)) .setVsyncPeriod(getAttribute(configId, Attribute::VsyncPeriod)) .setDpiX(getAttribute(configId, Attribute::DpiX)) .setDpiY(getAttribute(configId, Attribute::DpiY)) .build(); mConfigs.emplace(configId, std::move(config)); } void Display::loadConfigs() { ALOGV("[%" PRIu64 "] loadConfigs", mId); uint32_t numConfigs = 0; int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs, nullptr); auto error = static_cast(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [1] failed: %s (%d)", mId, to_string(error).c_str(), intError); return; } std::vector configIds(numConfigs); intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs, configIds.data()); error = static_cast(intError); if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, to_string(error).c_str(), intError); return; } for (auto configId : configIds) { loadConfig(configId); } } // For use by Layer void Display::destroyLayer(hwc2_layer_t layerId) { int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId); auto error = static_cast(intError); ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" " failed: %s (%d)", mId, layerId, to_string(error).c_str(), intError); mLayers.erase(layerId); } // Other Display methods std::shared_ptr Display::getLayerById(hwc2_layer_t id) const { if (mLayers.count(id) == 0) { return nullptr; } auto layer = mLayers.at(id).lock(); return layer; } // Layer methods Layer::Layer(const std::shared_ptr& display, hwc2_layer_t id) : mDisplay(display), mDisplayId(display->getId()), mDevice(display->getDevice()), mId(id) { ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id, display->getId()); } Layer::~Layer() { auto display = mDisplay.lock(); if (display) { display->destroyLayer(mId); } } Error Layer::setCursorPosition(int32_t x, int32_t y) { int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice, mDisplayId, mId, x, y); return static_cast(intError); } Error Layer::setBuffer(buffer_handle_t buffer, const sp& acquireFence) { int32_t fenceFd = acquireFence->dup(); int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId, mId, buffer, fenceFd); return static_cast(intError); } Error Layer::setSurfaceDamage(const Region& damage) { // We encode default full-screen damage as INVALID_RECT upstream, but as 0 // rects for HWC int32_t intError = 0; if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice, mDisplayId, mId, {0, nullptr}); } else { size_t rectCount = 0; auto rectArray = damage.getArray(&rectCount); std::vector hwcRects; for (size_t rect = 0; rect < rectCount; ++rect) { hwcRects.push_back({rectArray[rect].left, rectArray[rect].top, rectArray[rect].right, rectArray[rect].bottom}); } hwc_region_t hwcRegion = {}; hwcRegion.numRects = rectCount; hwcRegion.rects = hwcRects.data(); intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice, mDisplayId, mId, hwcRegion); } return static_cast(intError); } Error Layer::setBlendMode(BlendMode mode) { auto intMode = static_cast(mode); int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice, mDisplayId, mId, intMode); return static_cast(intError); } Error Layer::setColor(hwc_color_t color) { int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId, mId, color); return static_cast(intError); } Error Layer::setCompositionType(Composition type) { auto intType = static_cast(type); int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice, mDisplayId, mId, intType); return static_cast(intError); } Error Layer::setDataspace(android_dataspace_t dataspace) { auto intDataspace = static_cast(dataspace); int32_t intError = mDevice.mSetLayerDataspace(mDevice.mHwcDevice, mDisplayId, mId, intDataspace); return static_cast(intError); } Error Layer::setDisplayFrame(const Rect& frame) { hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom}; int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice, mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setPlaneAlpha(float alpha) { int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice, mDisplayId, mId, alpha); return static_cast(intError); } Error Layer::setSidebandStream(const native_handle_t* stream) { if (!mDevice.hasCapability(Capability::SidebandStream)) { ALOGE("Attempted to call setSidebandStream without checking that the " "device supports sideband streams"); return Error::Unsupported; } int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice, mDisplayId, mId, stream); return static_cast(intError); } Error Layer::setSourceCrop(const FloatRect& crop) { hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom}; int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice, mDisplayId, mId, hwcRect); return static_cast(intError); } Error Layer::setTransform(Transform transform) { auto intTransform = static_cast(transform); int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice, mDisplayId, mId, intTransform); return static_cast(intError); } Error Layer::setVisibleRegion(const Region& region) { size_t rectCount = 0; auto rectArray = region.getArray(&rectCount); std::vector hwcRects; for (size_t rect = 0; rect < rectCount; ++rect) { hwcRects.push_back({rectArray[rect].left, rectArray[rect].top, rectArray[rect].right, rectArray[rect].bottom}); } hwc_region_t hwcRegion = {}; hwcRegion.numRects = rectCount; hwcRegion.rects = hwcRects.data(); int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice, mDisplayId, mId, hwcRegion); return static_cast(intError); } Error Layer::setZOrder(uint32_t z) { int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId, mId, z); return static_cast(intError); } } // namespace HWC2 services/surfaceflinger/DisplayHardware/HWC2.h0100644 0000000 0000000 00000033345 13077405420 020400 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SF_HWC2_H #define ANDROID_SF_HWC2_H #define HWC2_INCLUDE_STRINGIFICATION #define HWC2_USE_CPP11 #include #undef HWC2_INCLUDE_STRINGIFICATION #undef HWC2_USE_CPP11 #include #include #include #include #include #include #include #include #include namespace android { class Fence; class FloatRect; class GraphicBuffer; class Rect; class Region; } namespace HWC2 { class Display; class Layer; typedef std::function, Connection)> HotplugCallback; typedef std::function)> RefreshCallback; typedef std::function, nsecs_t)> VsyncCallback; class Device { public: Device(hwc2_device_t* device); ~Device(); friend class HWC2::Display; friend class HWC2::Layer; // Required by HWC2 std::string dump() const; const std::vector& getCapabilities() const { return mCapabilities; }; uint32_t getMaxVirtualDisplayCount() const; Error createVirtualDisplay(uint32_t width, uint32_t height, android_pixel_format_t* format, std::shared_ptr* outDisplay); void registerHotplugCallback(HotplugCallback hotplug); void registerRefreshCallback(RefreshCallback refresh); void registerVsyncCallback(VsyncCallback vsync); // For use by callbacks void callHotplug(std::shared_ptr display, Connection connected); void callRefresh(std::shared_ptr display); void callVsync(std::shared_ptr display, nsecs_t timestamp); // Other Device methods // This will create a Display if one is not found, but it will not be marked // as connected std::shared_ptr getDisplayById(hwc2_display_t id); bool hasCapability(HWC2::Capability capability) const; private: // Initialization methods template [[clang::warn_unused_result]] bool loadFunctionPointer( FunctionDescriptor desc, PFN& outPFN) { auto intDesc = static_cast(desc); auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc); if (pfn != nullptr) { outPFN = reinterpret_cast(pfn); return true; } else { ALOGE("Failed to load function %s", to_string(desc).c_str()); return false; } } template void registerCallback(Callback callback, HOOK hook) { static_assert(std::is_same::value, "Incompatible function pointer"); auto intCallback = static_cast(callback); auto callbackData = static_cast(this); auto pfn = reinterpret_cast(hook); mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn); } void loadCapabilities(); void loadFunctionPointers(); void registerCallbacks(); // For use by Display void destroyVirtualDisplay(hwc2_display_t display); // Member variables hwc2_device_t* mHwcDevice; // Device function pointers HWC2_PFN_CREATE_VIRTUAL_DISPLAY mCreateVirtualDisplay; HWC2_PFN_DESTROY_VIRTUAL_DISPLAY mDestroyVirtualDisplay; HWC2_PFN_DUMP mDump; HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT mGetMaxVirtualDisplayCount; HWC2_PFN_REGISTER_CALLBACK mRegisterCallback; // Display function pointers HWC2_PFN_ACCEPT_DISPLAY_CHANGES mAcceptDisplayChanges; HWC2_PFN_CREATE_LAYER mCreateLayer; HWC2_PFN_DESTROY_LAYER mDestroyLayer; HWC2_PFN_GET_ACTIVE_CONFIG mGetActiveConfig; HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES mGetChangedCompositionTypes; HWC2_PFN_GET_COLOR_MODES mGetColorModes; HWC2_PFN_GET_DISPLAY_ATTRIBUTE mGetDisplayAttribute; HWC2_PFN_GET_DISPLAY_CONFIGS mGetDisplayConfigs; HWC2_PFN_GET_DISPLAY_NAME mGetDisplayName; HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests; HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType; HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport; HWC2_PFN_GET_HDR_CAPABILITIES mGetHdrCapabilities; HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences; HWC2_PFN_PRESENT_DISPLAY mPresentDisplay; HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig; HWC2_PFN_SET_CLIENT_TARGET mSetClientTarget; HWC2_PFN_SET_COLOR_MODE mSetColorMode; HWC2_PFN_SET_COLOR_TRANSFORM mSetColorTransform; HWC2_PFN_SET_OUTPUT_BUFFER mSetOutputBuffer; HWC2_PFN_SET_POWER_MODE mSetPowerMode; HWC2_PFN_SET_VSYNC_ENABLED mSetVsyncEnabled; HWC2_PFN_VALIDATE_DISPLAY mValidateDisplay; // Layer function pointers HWC2_PFN_SET_CURSOR_POSITION mSetCursorPosition; HWC2_PFN_SET_LAYER_BUFFER mSetLayerBuffer; HWC2_PFN_SET_LAYER_SURFACE_DAMAGE mSetLayerSurfaceDamage; HWC2_PFN_SET_LAYER_BLEND_MODE mSetLayerBlendMode; HWC2_PFN_SET_LAYER_COLOR mSetLayerColor; HWC2_PFN_SET_LAYER_COMPOSITION_TYPE mSetLayerCompositionType; HWC2_PFN_SET_LAYER_DATASPACE mSetLayerDataspace; HWC2_PFN_SET_LAYER_DISPLAY_FRAME mSetLayerDisplayFrame; HWC2_PFN_SET_LAYER_PLANE_ALPHA mSetLayerPlaneAlpha; HWC2_PFN_SET_LAYER_SIDEBAND_STREAM mSetLayerSidebandStream; HWC2_PFN_SET_LAYER_SOURCE_CROP mSetLayerSourceCrop; HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform; HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion; HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder; std::vector mCapabilities; std::unordered_map> mDisplays; HotplugCallback mHotplug; std::vector, Connection>> mPendingHotplugs; RefreshCallback mRefresh; std::vector> mPendingRefreshes; VsyncCallback mVsync; std::vector, nsecs_t>> mPendingVsyncs; }; class Display : public std::enable_shared_from_this { public: Display(Device& device, hwc2_display_t id); ~Display(); friend class HWC2::Device; friend class HWC2::Layer; class Config { public: class Builder { public: Builder(Display& display, hwc2_config_t id); std::shared_ptr build() { return std::const_pointer_cast( std::move(mConfig)); } Builder& setWidth(int32_t width) { mConfig->mWidth = width; return *this; } Builder& setHeight(int32_t height) { mConfig->mHeight = height; return *this; } Builder& setVsyncPeriod(int32_t vsyncPeriod) { mConfig->mVsyncPeriod = vsyncPeriod; return *this; } Builder& setDpiX(int32_t dpiX) { if (dpiX == -1) { mConfig->mDpiX = getDefaultDensity(); } else { mConfig->mDpiX = dpiX / 1000.0f; } return *this; } Builder& setDpiY(int32_t dpiY) { if (dpiY == -1) { mConfig->mDpiY = getDefaultDensity(); } else { mConfig->mDpiY = dpiY / 1000.0f; } return *this; } private: float getDefaultDensity(); std::shared_ptr mConfig; }; hwc2_display_t getDisplayId() const { return mDisplay.getId(); } hwc2_config_t getId() const { return mId; } int32_t getWidth() const { return mWidth; } int32_t getHeight() const { return mHeight; } nsecs_t getVsyncPeriod() const { return mVsyncPeriod; } float getDpiX() const { return mDpiX; } float getDpiY() const { return mDpiY; } private: Config(Display& display, hwc2_config_t id); Display& mDisplay; hwc2_config_t mId; int32_t mWidth; int32_t mHeight; nsecs_t mVsyncPeriod; float mDpiX; float mDpiY; }; // Required by HWC2 [[clang::warn_unused_result]] Error acceptChanges(); [[clang::warn_unused_result]] Error createLayer( std::shared_ptr* outLayer); [[clang::warn_unused_result]] Error getActiveConfig( std::shared_ptr* outConfig) const; [[clang::warn_unused_result]] Error getChangedCompositionTypes( std::unordered_map, Composition>* outTypes); [[clang::warn_unused_result]] Error getColorModes( std::vector* outModes) const; // Doesn't call into the HWC2 device, so no errors are possible std::vector> getConfigs() const; [[clang::warn_unused_result]] Error getName(std::string* outName) const; [[clang::warn_unused_result]] Error getRequests( DisplayRequest* outDisplayRequests, std::unordered_map, LayerRequest>* outLayerRequests); [[clang::warn_unused_result]] Error getType(DisplayType* outType) const; [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( std::unique_ptr* outCapabilities) const; [[clang::warn_unused_result]] Error getReleaseFences( std::unordered_map, android::sp>* outFences) const; [[clang::warn_unused_result]] Error present( android::sp* outRetireFence); [[clang::warn_unused_result]] Error setActiveConfig( const std::shared_ptr& config); [[clang::warn_unused_result]] Error setClientTarget( buffer_handle_t target, const android::sp& acquireFence, android_dataspace_t dataspace); [[clang::warn_unused_result]] Error setColorMode(int32_t mode); [[clang::warn_unused_result]] Error setColorTransform( const android::mat4& matrix, android_color_transform_t hint); [[clang::warn_unused_result]] Error setOutputBuffer( const android::sp& buffer, const android::sp& releaseFence); [[clang::warn_unused_result]] Error setPowerMode(PowerMode mode); [[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled); [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests); // Other Display methods Device& getDevice() const { return mDevice; } hwc2_display_t getId() const { return mId; } bool isConnected() const { return mIsConnected; } private: // For use by Device // Virtual displays are always connected void setVirtual() { mIsVirtual = true; mIsConnected = true; } void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); void loadConfigs(); // For use by Layer void destroyLayer(hwc2_layer_t layerId); // This may fail (and return a null pointer) if no layer with this ID exists // on this display std::shared_ptr getLayerById(hwc2_layer_t id) const; // Member variables Device& mDevice; hwc2_display_t mId; bool mIsConnected; bool mIsVirtual; std::unordered_map> mLayers; std::unordered_map> mConfigs; }; class Layer { public: Layer(const std::shared_ptr& display, hwc2_layer_t id); ~Layer(); bool isAbandoned() const { return mDisplay.expired(); } hwc2_layer_t getId() const { return mId; } [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(buffer_handle_t buffer, const android::sp& acquireFence); [[clang::warn_unused_result]] Error setSurfaceDamage( const android::Region& damage); [[clang::warn_unused_result]] Error setBlendMode(BlendMode mode); [[clang::warn_unused_result]] Error setColor(hwc_color_t color); [[clang::warn_unused_result]] Error setCompositionType(Composition type); [[clang::warn_unused_result]] Error setDataspace( android_dataspace_t dataspace); [[clang::warn_unused_result]] Error setDisplayFrame( const android::Rect& frame); [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha); [[clang::warn_unused_result]] Error setSidebandStream( const native_handle_t* stream); [[clang::warn_unused_result]] Error setSourceCrop( const android::FloatRect& crop); [[clang::warn_unused_result]] Error setTransform(Transform transform); [[clang::warn_unused_result]] Error setVisibleRegion( const android::Region& region); [[clang::warn_unused_result]] Error setZOrder(uint32_t z); private: std::weak_ptr mDisplay; hwc2_display_t mDisplayId; Device& mDevice; hwc2_layer_t mId; }; } // namespace HWC2 #endif // ANDROID_SF_HWC2_H services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp0100644 0000000 0000000 00000256776 13077405420 022631 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "HWC2On1Adapter" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "HWC2On1Adapter.h" #include #include #include #include #include #include #include using namespace std::chrono_literals; static bool operator==(const hwc_color_t& lhs, const hwc_color_t& rhs) { return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a; } static bool operator==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) { return lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right && lhs.bottom == rhs.bottom; } static bool operator==(const hwc_frect_t& lhs, const hwc_frect_t& rhs) { return lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right && lhs.bottom == rhs.bottom; } template static inline bool operator!=(const T& lhs, const T& rhs) { return !(lhs == rhs); } static uint8_t getMinorVersion(struct hwc_composer_device_1* device) { auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; return (version >> 16) & 0xF; } template static hwc2_function_pointer_t asFP(T function) { static_assert(std::is_same::value, "Incompatible function pointer"); return reinterpret_cast(function); } using namespace HWC2; static constexpr Attribute ColorTransform = static_cast(6); namespace android { void HWC2On1Adapter::DisplayContentsDeleter::operator()( hwc_display_contents_1_t* contents) { if (contents != nullptr) { for (size_t l = 0; l < contents->numHwLayers; ++l) { auto& layer = contents->hwLayers[l]; std::free(const_cast(layer.visibleRegionScreen.rects)); } } std::free(contents); } class HWC2On1Adapter::Callbacks : public hwc_procs_t { public: Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) { invalidate = &invalidateHook; vsync = &vsyncHook; hotplug = &hotplugHook; } static void invalidateHook(const hwc_procs_t* procs) { auto callbacks = static_cast(procs); callbacks->mAdapter.hwc1Invalidate(); } static void vsyncHook(const hwc_procs_t* procs, int display, int64_t timestamp) { auto callbacks = static_cast(procs); callbacks->mAdapter.hwc1Vsync(display, timestamp); } static void hotplugHook(const hwc_procs_t* procs, int display, int connected) { auto callbacks = static_cast(procs); callbacks->mAdapter.hwc1Hotplug(display, connected); } private: HWC2On1Adapter& mAdapter; }; static int closeHook(hw_device_t* /*device*/) { // Do nothing, since the real work is done in the class destructor, but we // need to provide a valid function pointer for hwc2_close to call return 0; } HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device) : mDumpString(), mHwc1Device(hwc1Device), mHwc1MinorVersion(getMinorVersion(hwc1Device)), mHwc1SupportsVirtualDisplays(false), mHwc1Callbacks(std::make_unique(*this)), mCapabilities(), mLayers(), mHwc1VirtualDisplay(), mStateMutex(), mCallbacks(), mHasPendingInvalidate(false), mPendingVsyncs(), mPendingHotplugs(), mDisplays(), mHwc1DisplayMap() { common.close = closeHook; getCapabilities = getCapabilitiesHook; getFunction = getFunctionHook; populateCapabilities(); populatePrimary(); mHwc1Device->registerProcs(mHwc1Device, static_cast(mHwc1Callbacks.get())); } HWC2On1Adapter::~HWC2On1Adapter() { hwc_close_1(mHwc1Device); } void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities) { if (outCapabilities == nullptr) { *outCount = mCapabilities.size(); return; } auto capabilityIter = mCapabilities.cbegin(); for (size_t written = 0; written < *outCount; ++written) { if (capabilityIter == mCapabilities.cend()) { return; } outCapabilities[written] = static_cast(*capabilityIter); ++capabilityIter; } } hwc2_function_pointer_t HWC2On1Adapter::doGetFunction( FunctionDescriptor descriptor) { switch (descriptor) { // Device functions case FunctionDescriptor::CreateVirtualDisplay: return asFP( createVirtualDisplayHook); case FunctionDescriptor::DestroyVirtualDisplay: return asFP( destroyVirtualDisplayHook); case FunctionDescriptor::Dump: return asFP(dumpHook); case FunctionDescriptor::GetMaxVirtualDisplayCount: return asFP( getMaxVirtualDisplayCountHook); case FunctionDescriptor::RegisterCallback: return asFP(registerCallbackHook); // Display functions case FunctionDescriptor::AcceptDisplayChanges: return asFP( displayHook); case FunctionDescriptor::CreateLayer: return asFP( displayHook); case FunctionDescriptor::DestroyLayer: return asFP( displayHook); case FunctionDescriptor::GetActiveConfig: return asFP( displayHook); case FunctionDescriptor::GetChangedCompositionTypes: return asFP( displayHook); case FunctionDescriptor::GetColorModes: return asFP( displayHook); case FunctionDescriptor::GetDisplayAttribute: return asFP( getDisplayAttributeHook); case FunctionDescriptor::GetDisplayConfigs: return asFP( displayHook); case FunctionDescriptor::GetDisplayName: return asFP( displayHook); case FunctionDescriptor::GetDisplayRequests: return asFP( displayHook); case FunctionDescriptor::GetDisplayType: return asFP( displayHook); case FunctionDescriptor::GetDozeSupport: return asFP( displayHook); case FunctionDescriptor::GetHdrCapabilities: return asFP( displayHook); case FunctionDescriptor::GetReleaseFences: return asFP( displayHook); case FunctionDescriptor::PresentDisplay: return asFP( displayHook); case FunctionDescriptor::SetActiveConfig: return asFP( displayHook); case FunctionDescriptor::SetClientTarget: return asFP( displayHook); case FunctionDescriptor::SetColorMode: return asFP( displayHook); case FunctionDescriptor::SetColorTransform: return asFP(setColorTransformHook); case FunctionDescriptor::SetOutputBuffer: return asFP( displayHook); case FunctionDescriptor::SetPowerMode: return asFP(setPowerModeHook); case FunctionDescriptor::SetVsyncEnabled: return asFP(setVsyncEnabledHook); case FunctionDescriptor::ValidateDisplay: return asFP( displayHook); // Layer functions case FunctionDescriptor::SetCursorPosition: return asFP( layerHook); case FunctionDescriptor::SetLayerBuffer: return asFP( layerHook); case FunctionDescriptor::SetLayerSurfaceDamage: return asFP( layerHook); // Layer state functions case FunctionDescriptor::SetLayerBlendMode: return asFP( setLayerBlendModeHook); case FunctionDescriptor::SetLayerColor: return asFP( layerHook); case FunctionDescriptor::SetLayerCompositionType: return asFP( setLayerCompositionTypeHook); case FunctionDescriptor::SetLayerDataspace: return asFP(setLayerDataspaceHook); case FunctionDescriptor::SetLayerDisplayFrame: return asFP( layerHook); case FunctionDescriptor::SetLayerPlaneAlpha: return asFP( layerHook); case FunctionDescriptor::SetLayerSidebandStream: return asFP( layerHook); case FunctionDescriptor::SetLayerSourceCrop: return asFP( layerHook); case FunctionDescriptor::SetLayerTransform: return asFP(setLayerTransformHook); case FunctionDescriptor::SetLayerVisibleRegion: return asFP( layerHook); case FunctionDescriptor::SetLayerZOrder: return asFP(setLayerZOrderHook); default: ALOGE("doGetFunction: Unknown function descriptor: %d (%s)", static_cast(descriptor), to_string(descriptor).c_str()); return nullptr; } } // Device functions Error HWC2On1Adapter::createVirtualDisplay(uint32_t width, uint32_t height, hwc2_display_t* outDisplay) { std::unique_lock lock(mStateMutex); if (mHwc1VirtualDisplay) { // We have already allocated our only HWC1 virtual display ALOGE("createVirtualDisplay: HWC1 virtual display already allocated"); return Error::NoResources; } if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 && (width > MAX_VIRTUAL_DISPLAY_DIMENSION || height > MAX_VIRTUAL_DISPLAY_DIMENSION)) { ALOGE("createVirtualDisplay: Can't create a virtual display with" " a dimension > %u (tried %u x %u)", MAX_VIRTUAL_DISPLAY_DIMENSION, width, height); return Error::NoResources; } mHwc1VirtualDisplay = std::make_shared(*this, HWC2::DisplayType::Virtual); mHwc1VirtualDisplay->populateConfigs(width, height); const auto displayId = mHwc1VirtualDisplay->getId(); mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId; mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL); mDisplays.emplace(displayId, mHwc1VirtualDisplay); *outDisplay = displayId; return Error::None; } Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) { std::unique_lock lock(mStateMutex); if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) { return Error::BadDisplay; } mHwc1VirtualDisplay.reset(); mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL); mDisplays.erase(displayId); return Error::None; } void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) { if (outBuffer != nullptr) { auto copiedBytes = mDumpString.copy(outBuffer, *outSize); *outSize = static_cast(copiedBytes); return; } std::stringstream output; output << "-- HWC2On1Adapter --\n"; output << "Adapting to a HWC 1." << static_cast(mHwc1MinorVersion) << " device\n"; // Attempt to acquire the lock for 1 second, but proceed without the lock // after that, so we can still get some information if we're deadlocked std::unique_lock lock(mStateMutex, std::defer_lock); lock.try_lock_for(1s); if (mCapabilities.empty()) { output << "Capabilities: None\n"; } else { output << "Capabilities:\n"; for (auto capability : mCapabilities) { output << " " << to_string(capability) << '\n'; } } output << "Displays:\n"; for (const auto& element : mDisplays) { const auto& display = element.second; output << display->dump(); } output << '\n'; // Release the lock before calling into HWC1, and since we no longer require // mutual exclusion to access mCapabilities or mDisplays lock.unlock(); if (mHwc1Device->dump) { output << "HWC1 dump:\n"; std::vector hwc1Dump(4096); // Call with size - 1 to preserve a null character at the end mHwc1Device->dump(mHwc1Device, hwc1Dump.data(), static_cast(hwc1Dump.size() - 1)); output << hwc1Dump.data(); } mDumpString = output.str(); *outSize = static_cast(mDumpString.size()); } uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() { return mHwc1SupportsVirtualDisplays ? 1 : 0; } static bool isValid(Callback descriptor) { switch (descriptor) { case Callback::Hotplug: // Fall-through case Callback::Refresh: // Fall-through case Callback::Vsync: return true; default: return false; } } Error HWC2On1Adapter::registerCallback(Callback descriptor, hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) { if (!isValid(descriptor)) { return Error::BadParameter; } ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(), callbackData, pointer); std::unique_lock lock(mStateMutex); mCallbacks[descriptor] = {callbackData, pointer}; bool hasPendingInvalidate = false; std::vector displayIds; std::vector> pendingVsyncs; std::vector> pendingHotplugs; if (descriptor == Callback::Refresh) { hasPendingInvalidate = mHasPendingInvalidate; if (hasPendingInvalidate) { for (auto& displayPair : mDisplays) { displayIds.emplace_back(displayPair.first); } } mHasPendingInvalidate = false; } else if (descriptor == Callback::Vsync) { for (auto pending : mPendingVsyncs) { auto hwc1DisplayId = pending.first; if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) { ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId); continue; } auto displayId = mHwc1DisplayMap[hwc1DisplayId]; auto timestamp = pending.second; pendingVsyncs.emplace_back(displayId, timestamp); } mPendingVsyncs.clear(); } else if (descriptor == Callback::Hotplug) { // Hotplug the primary display pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY], static_cast(Connection::Connected)); for (auto pending : mPendingHotplugs) { auto hwc1DisplayId = pending.first; if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) { ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d", hwc1DisplayId); continue; } auto displayId = mHwc1DisplayMap[hwc1DisplayId]; auto connected = pending.second; pendingHotplugs.emplace_back(displayId, connected); } } // Call pending callbacks without the state lock held lock.unlock(); if (hasPendingInvalidate) { auto refresh = reinterpret_cast(pointer); for (auto displayId : displayIds) { refresh(callbackData, displayId); } } if (!pendingVsyncs.empty()) { auto vsync = reinterpret_cast(pointer); for (auto& pendingVsync : pendingVsyncs) { vsync(callbackData, pendingVsync.first, pendingVsync.second); } } if (!pendingHotplugs.empty()) { auto hotplug = reinterpret_cast(pointer); for (auto& pendingHotplug : pendingHotplugs) { hotplug(callbackData, pendingHotplug.first, pendingHotplug.second); } } return Error::None; } // Display functions std::atomic HWC2On1Adapter::Display::sNextId(1); HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type) : mId(sNextId++), mDevice(device), mDirtyCount(0), mStateMutex(), mZIsDirty(false), mHwc1RequestedContents(nullptr), mHwc1ReceivedContents(nullptr), mRetireFence(), mChanges(), mHwc1Id(-1), mConfigs(), mActiveConfig(nullptr), mName(), mType(type), mPowerMode(PowerMode::Off), mVsyncEnabled(Vsync::Invalid), mClientTarget(), mOutputBuffer(), mHasColorTransform(false), mLayers(), mHwc1LayerMap() {} Error HWC2On1Adapter::Display::acceptChanges() { std::unique_lock lock(mStateMutex); if (!mChanges) { ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId); return Error::NotValidated; } ALOGV("[%" PRIu64 "] acceptChanges", mId); for (auto& change : mChanges->getTypeChanges()) { auto layerId = change.first; auto type = change.second; auto layer = mDevice.mLayers[layerId]; layer->setCompositionType(type); } mChanges->clearTypeChanges(); mHwc1RequestedContents = std::move(mHwc1ReceivedContents); return Error::None; } Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) { std::unique_lock lock(mStateMutex); auto layer = *mLayers.emplace(std::make_shared(*this)); mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer)); *outLayerId = layer->getId(); ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId); return Error::None; } Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) { std::unique_lock lock(mStateMutex); const auto mapLayer = mDevice.mLayers.find(layerId); if (mapLayer == mDevice.mLayers.end()) { ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer", mId, layerId); return Error::BadLayer; } const auto layer = mapLayer->second; mDevice.mLayers.erase(mapLayer); const auto zRange = mLayers.equal_range(layer); for (auto current = zRange.first; current != zRange.second; ++current) { if (**current == *layer) { current = mLayers.erase(current); break; } } ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId); return Error::None; } Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) { std::unique_lock lock(mStateMutex); if (!mActiveConfig) { ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId, to_string(Error::BadConfig).c_str()); return Error::BadConfig; } auto configId = mActiveConfig->getId(); ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId); *outConfig = configId; return Error::None; } Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId, Attribute attribute, int32_t* outValue) { std::unique_lock lock(mStateMutex); if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) { ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId, configId); return Error::BadConfig; } *outValue = mConfigs[configId]->getAttribute(attribute); ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId, to_string(attribute).c_str(), *outValue); return Error::None; } Error HWC2On1Adapter::Display::getChangedCompositionTypes( uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) { std::unique_lock lock(mStateMutex); if (!mChanges) { ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated", mId); return Error::NotValidated; } if ((outLayers == nullptr) || (outTypes == nullptr)) { *outNumElements = mChanges->getTypeChanges().size(); return Error::None; } uint32_t numWritten = 0; for (const auto& element : mChanges->getTypeChanges()) { if (numWritten == *outNumElements) { break; } auto layerId = element.first; auto intType = static_cast(element.second); ALOGV("Adding %" PRIu64 " %s", layerId, to_string(element.second).c_str()); outLayers[numWritten] = layerId; outTypes[numWritten] = intType; ++numWritten; } *outNumElements = numWritten; return Error::None; } Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes, int32_t* outModes) { std::unique_lock lock(mStateMutex); if (!outModes) { *outNumModes = mColorModes.size(); return Error::None; } uint32_t numModes = std::min(*outNumModes, static_cast(mColorModes.size())); std::copy_n(mColorModes.cbegin(), numModes, outModes); *outNumModes = numModes; return Error::None; } Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs, hwc2_config_t* outConfigs) { std::unique_lock lock(mStateMutex); if (!outConfigs) { *outNumConfigs = mConfigs.size(); return Error::None; } uint32_t numWritten = 0; for (const auto& config : mConfigs) { if (numWritten == *outNumConfigs) { break; } outConfigs[numWritten] = config->getId(); ++numWritten; } *outNumConfigs = numWritten; return Error::None; } Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) { std::unique_lock lock(mStateMutex); if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) { *outSupport = 0; } else { *outSupport = 1; } return Error::None; } Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes, int32_t* /*outTypes*/, float* /*outMaxLuminance*/, float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) { // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0 *outNumTypes = 0; return Error::None; } Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) { std::unique_lock lock(mStateMutex); if (!outName) { *outSize = mName.size(); return Error::None; } auto numCopied = mName.copy(outName, *outSize); *outSize = numCopied; return Error::None; } Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outFences) { std::unique_lock lock(mStateMutex); uint32_t numWritten = 0; bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr); for (const auto& layer : mLayers) { if (outputsNonNull && (numWritten == *outNumElements)) { break; } auto releaseFence = layer->getReleaseFence(); if (releaseFence != Fence::NO_FENCE) { if (outputsNonNull) { outLayers[numWritten] = layer->getId(); outFences[numWritten] = releaseFence->dup(); } ++numWritten; } } *outNumElements = numWritten; return Error::None; } Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests, uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outLayerRequests) { std::unique_lock lock(mStateMutex); if (!mChanges) { return Error::NotValidated; } if (outLayers == nullptr || outLayerRequests == nullptr) { *outNumElements = mChanges->getNumLayerRequests(); return Error::None; } *outDisplayRequests = mChanges->getDisplayRequests(); uint32_t numWritten = 0; for (const auto& request : mChanges->getLayerRequests()) { if (numWritten == *outNumElements) { break; } outLayers[numWritten] = request.first; outLayerRequests[numWritten] = static_cast(request.second); ++numWritten; } return Error::None; } Error HWC2On1Adapter::Display::getType(int32_t* outType) { std::unique_lock lock(mStateMutex); *outType = static_cast(mType); return Error::None; } Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) { std::unique_lock lock(mStateMutex); if (mChanges) { Error error = mDevice.setAllDisplays(); if (error != Error::None) { ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId, to_string(error).c_str()); return error; } } *outRetireFence = mRetireFence.get()->dup(); ALOGV("[%" PRIu64 "] present returning retire fence %d", mId, *outRetireFence); return Error::None; } Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) { std::unique_lock lock(mStateMutex); auto config = getConfig(configId); if (!config) { return Error::BadConfig; } if (config == mActiveConfig) { return Error::None; } if (mDevice.mHwc1MinorVersion >= 4) { uint32_t hwc1Id = 0; auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id); if (error != Error::None) { return error; } int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, static_cast(hwc1Id)); if (intError != 0) { ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)", intError); return Error::BadConfig; } mActiveConfig = config; } return Error::None; } Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target, int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) { std::unique_lock lock(mStateMutex); ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence); mClientTarget.setBuffer(target); mClientTarget.setFence(acquireFence); // dataspace and damage can't be used by HWC1, so ignore them return Error::None; } Error HWC2On1Adapter::Display::setColorMode(int32_t mode) { std::unique_lock lock (mStateMutex); ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode); if (mode == mActiveColorMode) { return Error::None; } if (mColorModes.count(mode) == 0) { ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode); return Error::Unsupported; } uint32_t hwc1Config = 0; auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config); if (error != Error::None) { return error; } ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config); int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, hwc1Config); if (intError != 0) { ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError); return Error::Unsupported; } mActiveColorMode = mode; return Error::None; } Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) { std::unique_lock lock(mStateMutex); ALOGV("%" PRIu64 "] setColorTransform(%d)", mId, static_cast(hint)); mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY); return Error::None; } Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer, int32_t releaseFence) { std::unique_lock lock(mStateMutex); ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence); mOutputBuffer.setBuffer(buffer); mOutputBuffer.setFence(releaseFence); return Error::None; } static bool isValid(PowerMode mode) { switch (mode) { case PowerMode::Off: // Fall-through case PowerMode::DozeSuspend: // Fall-through case PowerMode::Doze: // Fall-through case PowerMode::On: return true; default: return false; } } static int getHwc1PowerMode(PowerMode mode) { switch (mode) { case PowerMode::Off: return HWC_POWER_MODE_OFF; case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND; case PowerMode::Doze: return HWC_POWER_MODE_DOZE; case PowerMode::On: return HWC_POWER_MODE_NORMAL; default: return HWC_POWER_MODE_OFF; } } Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) { if (!isValid(mode)) { return Error::BadParameter; } if (mode == mPowerMode) { return Error::None; } std::unique_lock lock(mStateMutex); int error = 0; if (mDevice.mHwc1MinorVersion < 4) { error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id, mode == PowerMode::Off); } else { error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device, mHwc1Id, getHwc1PowerMode(mode)); } ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)", error); ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str()); mPowerMode = mode; return Error::None; } static bool isValid(Vsync enable) { switch (enable) { case Vsync::Enable: // Fall-through case Vsync::Disable: return true; default: return false; } } Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) { if (!isValid(enable)) { return Error::BadParameter; } if (enable == mVsyncEnabled) { return Error::None; } std::unique_lock lock(mStateMutex); int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device, mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable); ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)", error); mVsyncEnabled = enable; return Error::None; } Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { std::unique_lock lock(mStateMutex); ALOGV("[%" PRIu64 "] Entering validate", mId); if (!mChanges) { if (!mDevice.prepareAllDisplays()) { return Error::BadDisplay; } } *outNumTypes = mChanges->getNumTypes(); *outNumRequests = mChanges->getNumLayerRequests(); ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes, *outNumRequests); for (auto request : mChanges->getTypeChanges()) { ALOGV("Layer %" PRIu64 " --> %s", request.first, to_string(request.second).c_str()); } return *outNumTypes > 0 ? Error::HasChanges : Error::None; } // Display helpers Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) { std::unique_lock lock(mStateMutex); const auto mapLayer = mDevice.mLayers.find(layerId); if (mapLayer == mDevice.mLayers.end()) { ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId); return Error::BadLayer; } const auto layer = mapLayer->second; const auto zRange = mLayers.equal_range(layer); bool layerOnDisplay = false; for (auto current = zRange.first; current != zRange.second; ++current) { if (**current == *layer) { if ((*current)->getZ() == z) { // Don't change anything if the Z hasn't changed return Error::None; } current = mLayers.erase(current); layerOnDisplay = true; break; } } if (!layerOnDisplay) { ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display", mId); return Error::BadLayer; } layer->setZ(z); mLayers.emplace(std::move(layer)); mZIsDirty = true; return Error::None; } static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = { HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_COLOR_TRANSFORM, HWC_DISPLAY_NO_ATTRIBUTE, }; static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = { HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_NO_ATTRIBUTE, }; static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR = sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t); static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR), "Attribute tables have unexpected sizes"); static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = { 6, // HWC_DISPLAY_NO_ATTRIBUTE = 0 0, // HWC_DISPLAY_VSYNC_PERIOD = 1, 1, // HWC_DISPLAY_WIDTH = 2, 2, // HWC_DISPLAY_HEIGHT = 3, 3, // HWC_DISPLAY_DPI_X = 4, 4, // HWC_DISPLAY_DPI_Y = 5, 5, // HWC_DISPLAY_COLOR_TRANSFORM = 6, }; static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = { 5, // HWC_DISPLAY_NO_ATTRIBUTE = 0 0, // HWC_DISPLAY_VSYNC_PERIOD = 1, 1, // HWC_DISPLAY_WIDTH = 2, 2, // HWC_DISPLAY_HEIGHT = 3, 3, // HWC_DISPLAY_DPI_X = 4, 4, // HWC_DISPLAY_DPI_Y = 5, }; template static constexpr bool attributesMatch() { bool match = (attribute == ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]); if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) { return match; } return match && (attribute == ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]); } static_assert(attributesMatch(), "Tables out of sync"); static_assert(attributesMatch(), "Tables out of sync"); static_assert(attributesMatch(), "Tables out of sync"); static_assert(attributesMatch(), "Tables out of sync"); static_assert(attributesMatch(), "Tables out of sync"); static_assert(attributesMatch(), "Tables out of sync"); void HWC2On1Adapter::Display::populateConfigs() { std::unique_lock lock(mStateMutex); ALOGV("[%" PRIu64 "] populateConfigs", mId); if (mHwc1Id == -1) { ALOGE("populateConfigs: HWC1 ID not set"); return; } const size_t MAX_NUM_CONFIGS = 128; uint32_t configs[MAX_NUM_CONFIGS] = {}; size_t numConfigs = MAX_NUM_CONFIGS; mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id, configs, &numConfigs); for (size_t c = 0; c < numConfigs; ++c) { uint32_t hwc1ConfigId = configs[c]; auto newConfig = std::make_shared(*this); int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {}; bool hasColor = true; auto result = mDevice.mHwc1Device->getDisplayAttributes( mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITH_COLOR, values); if (result != 0) { mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values); hasColor = false; } auto attributeMap = hasColor ? ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR; newConfig->setAttribute(Attribute::VsyncPeriod, values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]); newConfig->setAttribute(Attribute::Width, values[attributeMap[HWC_DISPLAY_WIDTH]]); newConfig->setAttribute(Attribute::Height, values[attributeMap[HWC_DISPLAY_HEIGHT]]); newConfig->setAttribute(Attribute::DpiX, values[attributeMap[HWC_DISPLAY_DPI_X]]); newConfig->setAttribute(Attribute::DpiY, values[attributeMap[HWC_DISPLAY_DPI_Y]]); if (hasColor) { newConfig->setAttribute(ColorTransform, values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]); } // We can only do this after attempting to read the color transform newConfig->setHwc1Id(hwc1ConfigId); for (auto& existingConfig : mConfigs) { if (existingConfig->merge(*newConfig)) { ALOGV("Merged config %d with existing config %u: %s", hwc1ConfigId, existingConfig->getId(), existingConfig->toString().c_str()); newConfig.reset(); break; } } // If it wasn't merged with any existing config, add it to the end if (newConfig) { newConfig->setId(static_cast(mConfigs.size())); ALOGV("Found new config %u: %s", newConfig->getId(), newConfig->toString().c_str()); mConfigs.emplace_back(std::move(newConfig)); } } initializeActiveConfig(); populateColorModes(); } void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) { std::unique_lock lock(mStateMutex); mConfigs.emplace_back(std::make_shared(*this)); auto& config = mConfigs[0]; config->setAttribute(Attribute::Width, static_cast(width)); config->setAttribute(Attribute::Height, static_cast(height)); config->setHwc1Id(0); config->setId(0); mActiveConfig = config; } bool HWC2On1Adapter::Display::prepare() { std::unique_lock lock(mStateMutex); // Only prepare display contents for displays HWC1 knows about if (mHwc1Id == -1) { return true; } // It doesn't make sense to prepare a display for which there is no active // config, so return early if (!mActiveConfig) { ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId); return false; } ALOGV("[%" PRIu64 "] Entering prepare", mId); auto currentCount = mHwc1RequestedContents ? mHwc1RequestedContents->numHwLayers : 0; auto requiredCount = mLayers.size() + 1; ALOGV("[%" PRIu64 "] Requires %zd layers, %zd allocated in %p", mId, requiredCount, currentCount, mHwc1RequestedContents.get()); bool layerCountChanged = (currentCount != requiredCount); if (layerCountChanged) { reallocateHwc1Contents(); } bool applyAllState = false; if (layerCountChanged || mZIsDirty) { assignHwc1LayerIds(); mZIsDirty = false; applyAllState = true; } mHwc1RequestedContents->retireFenceFd = -1; mHwc1RequestedContents->flags = 0; if (isDirty() || applyAllState) { mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED; } for (auto& layer : mLayers) { auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()]; hwc1Layer.releaseFenceFd = -1; layer->applyState(hwc1Layer, applyAllState); } mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer(); mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence(); prepareFramebufferTarget(); return true; } static void cloneHWCRegion(hwc_region_t& region) { auto size = sizeof(hwc_rect_t) * region.numRects; auto newRects = static_cast(std::malloc(size)); std::copy_n(region.rects, region.numRects, newRects); region.rects = newRects; } HWC2On1Adapter::Display::HWC1Contents HWC2On1Adapter::Display::cloneRequestedContents() const { std::unique_lock lock(mStateMutex); size_t size = sizeof(hwc_display_contents_1_t) + sizeof(hwc_layer_1_t) * (mHwc1RequestedContents->numHwLayers); auto contents = static_cast(std::malloc(size)); std::memcpy(contents, mHwc1RequestedContents.get(), size); for (size_t layerId = 0; layerId < contents->numHwLayers; ++layerId) { auto& layer = contents->hwLayers[layerId]; // Deep copy the regions to avoid double-frees cloneHWCRegion(layer.visibleRegionScreen); cloneHWCRegion(layer.surfaceDamage); } return HWC1Contents(contents); } void HWC2On1Adapter::Display::setReceivedContents(HWC1Contents contents) { std::unique_lock lock(mStateMutex); mHwc1ReceivedContents = std::move(contents); mChanges.reset(new Changes); size_t numLayers = mHwc1ReceivedContents->numHwLayers; for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) { const auto& receivedLayer = mHwc1ReceivedContents->hwLayers[hwc1Id]; if (mHwc1LayerMap.count(hwc1Id) == 0) { ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET, "setReceivedContents: HWC1 layer %zd doesn't have a" " matching HWC2 layer, and isn't the framebuffer target", hwc1Id); continue; } Layer& layer = *mHwc1LayerMap[hwc1Id]; updateTypeChanges(receivedLayer, layer); updateLayerRequests(receivedLayer, layer); } } bool HWC2On1Adapter::Display::hasChanges() const { std::unique_lock lock(mStateMutex); return mChanges != nullptr; } Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) { std::unique_lock lock(mStateMutex); if (!mChanges || (mChanges->getNumTypes() > 0)) { ALOGE("[%" PRIu64 "] set failed: not validated", mId); return Error::NotValidated; } // Set up the client/framebuffer target auto numLayers = hwcContents.numHwLayers; // Close acquire fences on FRAMEBUFFER layers, since they will not be used // by HWC for (size_t l = 0; l < numLayers - 1; ++l) { auto& layer = hwcContents.hwLayers[l]; if (layer.compositionType == HWC_FRAMEBUFFER) { ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l); close(layer.acquireFenceFd); layer.acquireFenceFd = -1; } } auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1]; if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) { clientTargetLayer.handle = mClientTarget.getBuffer(); clientTargetLayer.acquireFenceFd = mClientTarget.getFence(); } else { ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET", mId); } mChanges.reset(); return Error::None; } void HWC2On1Adapter::Display::addRetireFence(int fenceFd) { std::unique_lock lock(mStateMutex); mRetireFence.add(fenceFd); } void HWC2On1Adapter::Display::addReleaseFences( const hwc_display_contents_1_t& hwcContents) { std::unique_lock lock(mStateMutex); size_t numLayers = hwcContents.numHwLayers; for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) { const auto& receivedLayer = hwcContents.hwLayers[hwc1Id]; if (mHwc1LayerMap.count(hwc1Id) == 0) { if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) { ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a" " matching HWC2 layer, and isn't the framebuffer" " target", hwc1Id); } // Close the framebuffer target release fence since we will use the // display retire fence instead if (receivedLayer.releaseFenceFd != -1) { close(receivedLayer.releaseFenceFd); } continue; } Layer& layer = *mHwc1LayerMap[hwc1Id]; ALOGV("Adding release fence %d to layer %" PRIu64, receivedLayer.releaseFenceFd, layer.getId()); layer.addReleaseFence(receivedLayer.releaseFenceFd); } } bool HWC2On1Adapter::Display::hasColorTransform() const { std::unique_lock lock(mStateMutex); return mHasColorTransform; } static std::string hwc1CompositionString(int32_t type) { switch (type) { case HWC_FRAMEBUFFER: return "Framebuffer"; case HWC_OVERLAY: return "Overlay"; case HWC_BACKGROUND: return "Background"; case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget"; case HWC_SIDEBAND: return "Sideband"; case HWC_CURSOR_OVERLAY: return "CursorOverlay"; default: return std::string("Unknown (") + std::to_string(type) + ")"; } } static std::string hwc1TransformString(int32_t transform) { switch (transform) { case 0: return "None"; case HWC_TRANSFORM_FLIP_H: return "FlipH"; case HWC_TRANSFORM_FLIP_V: return "FlipV"; case HWC_TRANSFORM_ROT_90: return "Rotate90"; case HWC_TRANSFORM_ROT_180: return "Rotate180"; case HWC_TRANSFORM_ROT_270: return "Rotate270"; case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90"; case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90"; default: return std::string("Unknown (") + std::to_string(transform) + ")"; } } static std::string hwc1BlendModeString(int32_t mode) { switch (mode) { case HWC_BLENDING_NONE: return "None"; case HWC_BLENDING_PREMULT: return "Premultiplied"; case HWC_BLENDING_COVERAGE: return "Coverage"; default: return std::string("Unknown (") + std::to_string(mode) + ")"; } } static std::string rectString(hwc_rect_t rect) { std::stringstream output; output << "[" << rect.left << ", " << rect.top << ", "; output << rect.right << ", " << rect.bottom << "]"; return output.str(); } static std::string approximateFloatString(float f) { if (static_cast(f) == f) { return std::to_string(static_cast(f)); } int32_t truncated = static_cast(f * 10); bool approximate = (static_cast(truncated) != f * 10); const size_t BUFFER_SIZE = 32; char buffer[BUFFER_SIZE] = {}; auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%s%.1f", approximate ? "~" : "", f); return std::string(buffer, bytesWritten); } static std::string frectString(hwc_frect_t frect) { std::stringstream output; output << "[" << approximateFloatString(frect.left) << ", "; output << approximateFloatString(frect.top) << ", "; output << approximateFloatString(frect.right) << ", "; output << approximateFloatString(frect.bottom) << "]"; return output.str(); } static std::string colorString(hwc_color_t color) { std::stringstream output; output << "RGBA ["; output << static_cast(color.r) << ", "; output << static_cast(color.g) << ", "; output << static_cast(color.b) << ", "; output << static_cast(color.a) << "]"; return output.str(); } static std::string alphaString(float f) { const size_t BUFFER_SIZE = 8; char buffer[BUFFER_SIZE] = {}; auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f); return std::string(buffer, bytesWritten); } static std::string to_string(const hwc_layer_1_t& hwcLayer, int32_t hwc1MinorVersion) { const char* fill = " "; std::stringstream output; output << " Composition: " << hwc1CompositionString(hwcLayer.compositionType); if (hwcLayer.compositionType == HWC_BACKGROUND) { output << " Color: " << colorString(hwcLayer.backgroundColor) << '\n'; } else if (hwcLayer.compositionType == HWC_SIDEBAND) { output << " Stream: " << hwcLayer.sidebandStream << '\n'; } else { output << " Buffer: " << hwcLayer.handle << "/" << hwcLayer.acquireFenceFd << '\n'; } output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) << '\n'; output << fill << "Source crop: "; if (hwc1MinorVersion >= 3) { output << frectString(hwcLayer.sourceCropf) << '\n'; } else { output << rectString(hwcLayer.sourceCropi) << '\n'; } output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform); output << " Blend mode: " << hwc1BlendModeString(hwcLayer.blending); if (hwcLayer.planeAlpha != 0xFF) { output << " Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f); } output << '\n'; if (hwcLayer.hints != 0) { output << fill << "Hints:"; if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) { output << " TripleBuffer"; } if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) { output << " ClearFB"; } output << '\n'; } if (hwcLayer.flags != 0) { output << fill << "Flags:"; if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) { output << " SkipLayer"; } if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) { output << " IsCursorLayer"; } output << '\n'; } return output.str(); } static std::string to_string(const hwc_display_contents_1_t& hwcContents, int32_t hwc1MinorVersion) { const char* fill = " "; std::stringstream output; output << fill << "Geometry changed: " << ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n"); output << fill << hwcContents.numHwLayers << " Layer" << ((hwcContents.numHwLayers == 1) ? "\n" : "s\n"); for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) { output << fill << " Layer " << layer; output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion); } if (hwcContents.outbuf != nullptr) { output << fill << "Output buffer: " << hwcContents.outbuf << "/" << hwcContents.outbufAcquireFenceFd << '\n'; } return output.str(); } std::string HWC2On1Adapter::Display::dump() const { std::unique_lock lock(mStateMutex); std::stringstream output; output << " Display " << mId << ": "; output << to_string(mType) << " "; output << "HWC1 ID: " << mHwc1Id << " "; output << "Power mode: " << to_string(mPowerMode) << " "; output << "Vsync: " << to_string(mVsyncEnabled) << '\n'; output << " Color modes [active]:"; for (const auto& mode : mColorModes) { if (mode == mActiveColorMode) { output << " [" << mode << ']'; } else { output << " " << mode; } } output << '\n'; output << " " << mConfigs.size() << " Config" << (mConfigs.size() == 1 ? "" : "s") << " (* active)\n"; for (const auto& config : mConfigs) { output << (config == mActiveConfig ? " * " : " "); output << config->toString(true) << '\n'; } output << " " << mLayers.size() << " Layer" << (mLayers.size() == 1 ? "" : "s") << '\n'; for (const auto& layer : mLayers) { output << layer->dump(); } output << " Client target: " << mClientTarget.getBuffer() << '\n'; if (mOutputBuffer.getBuffer() != nullptr) { output << " Output buffer: " << mOutputBuffer.getBuffer() << '\n'; } if (mHwc1ReceivedContents) { output << " Last received HWC1 state\n"; output << to_string(*mHwc1ReceivedContents, mDevice.mHwc1MinorVersion); } else if (mHwc1RequestedContents) { output << " Last requested HWC1 state\n"; output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion); } return output.str(); } void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute, int32_t value) { mAttributes[attribute] = value; } int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const { if (mAttributes.count(attribute) == 0) { return -1; } return mAttributes.at(attribute); } void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) { int32_t colorTransform = getAttribute(ColorTransform); mHwc1Ids.emplace(colorTransform, id); } bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const { for (const auto& idPair : mHwc1Ids) { if (id == idPair.second) { return true; } } return false; } int32_t HWC2On1Adapter::Display::Config::getColorModeForHwc1Id( uint32_t id) const { for (const auto& idPair : mHwc1Ids) { if (id == idPair.second) { return idPair.first; } } return -1; } Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(int32_t mode, uint32_t* outId) const { for (const auto& idPair : mHwc1Ids) { if (mode == idPair.first) { *outId = idPair.second; return Error::None; } } ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId); return Error::BadParameter; } bool HWC2On1Adapter::Display::Config::merge(const Config& other) { auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height, HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX, HWC2::Attribute::DpiY}; for (auto attribute : attributes) { if (getAttribute(attribute) != other.getAttribute(attribute)) { return false; } } int32_t otherColorTransform = other.getAttribute(ColorTransform); if (mHwc1Ids.count(otherColorTransform) != 0) { ALOGE("Attempted to merge two configs (%u and %u) which appear to be " "identical", mHwc1Ids.at(otherColorTransform), other.mHwc1Ids.at(otherColorTransform)); return false; } mHwc1Ids.emplace(otherColorTransform, other.mHwc1Ids.at(otherColorTransform)); return true; } std::set HWC2On1Adapter::Display::Config::getColorTransforms() const { std::set colorTransforms; for (const auto& idPair : mHwc1Ids) { colorTransforms.emplace(idPair.first); } return colorTransforms; } std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const { std::string output; const size_t BUFFER_SIZE = 100; char buffer[BUFFER_SIZE] = {}; auto writtenBytes = snprintf(buffer, BUFFER_SIZE, "%u x %u", mAttributes.at(HWC2::Attribute::Width), mAttributes.at(HWC2::Attribute::Height)); output.append(buffer, writtenBytes); if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) { std::memset(buffer, 0, BUFFER_SIZE); writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz", 1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod)); output.append(buffer, writtenBytes); } if (mAttributes.count(HWC2::Attribute::DpiX) != 0 && mAttributes.at(HWC2::Attribute::DpiX) != -1) { std::memset(buffer, 0, BUFFER_SIZE); writtenBytes = snprintf(buffer, BUFFER_SIZE, ", DPI: %.1f x %.1f", mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f, mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f); output.append(buffer, writtenBytes); } std::memset(buffer, 0, BUFFER_SIZE); if (splitLine) { writtenBytes = snprintf(buffer, BUFFER_SIZE, "\n HWC1 ID/Color transform:"); } else { writtenBytes = snprintf(buffer, BUFFER_SIZE, ", HWC1 ID/Color transform:"); } output.append(buffer, writtenBytes); for (const auto& id : mHwc1Ids) { int32_t colorTransform = id.first; uint32_t hwc1Id = id.second; std::memset(buffer, 0, BUFFER_SIZE); if (colorTransform == mDisplay.mActiveColorMode) { writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id, colorTransform); } else { writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id, colorTransform); } output.append(buffer, writtenBytes); } return output; } std::shared_ptr HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const { if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) { return nullptr; } return mConfigs[configId]; } void HWC2On1Adapter::Display::populateColorModes() { mColorModes = mConfigs[0]->getColorTransforms(); for (const auto& config : mConfigs) { std::set intersection; auto configModes = config->getColorTransforms(); std::set_intersection(mColorModes.cbegin(), mColorModes.cend(), configModes.cbegin(), configModes.cend(), std::inserter(intersection, intersection.begin())); std::swap(intersection, mColorModes); } } void HWC2On1Adapter::Display::initializeActiveConfig() { if (mDevice.mHwc1Device->getActiveConfig == nullptr) { ALOGV("getActiveConfig is null, choosing config 0"); mActiveConfig = mConfigs[0]; mActiveColorMode = -1; return; } auto activeConfig = mDevice.mHwc1Device->getActiveConfig( mDevice.mHwc1Device, mHwc1Id); if (activeConfig >= 0) { for (const auto& config : mConfigs) { if (config->hasHwc1Id(activeConfig)) { ALOGV("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig); mActiveConfig = config; mActiveColorMode = config->getColorModeForHwc1Id(activeConfig); break; } } if (!mActiveConfig) { ALOGV("Unable to find active HWC1 config %u, defaulting to " "config 0", activeConfig); mActiveConfig = mConfigs[0]; mActiveColorMode = -1; } } } void HWC2On1Adapter::Display::reallocateHwc1Contents() { // Allocate an additional layer for the framebuffer target auto numLayers = mLayers.size() + 1; size_t size = sizeof(hwc_display_contents_1_t) + sizeof(hwc_layer_1_t) * numLayers; ALOGV("[%" PRIu64 "] reallocateHwc1Contents creating %zd layer%s", mId, numLayers, numLayers != 1 ? "s" : ""); auto contents = static_cast(std::calloc(size, 1)); contents->numHwLayers = numLayers; mHwc1RequestedContents.reset(contents); } void HWC2On1Adapter::Display::assignHwc1LayerIds() { mHwc1LayerMap.clear(); size_t nextHwc1Id = 0; for (auto& layer : mLayers) { mHwc1LayerMap[nextHwc1Id] = layer; layer->setHwc1Id(nextHwc1Id++); } } void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer, const Layer& layer) { auto layerId = layer.getId(); switch (hwc1Layer.compositionType) { case HWC_FRAMEBUFFER: if (layer.getCompositionType() != Composition::Client) { mChanges->addTypeChange(layerId, Composition::Client); } break; case HWC_OVERLAY: if (layer.getCompositionType() != Composition::Device) { mChanges->addTypeChange(layerId, Composition::Device); } break; case HWC_BACKGROUND: ALOGE_IF(layer.getCompositionType() != Composition::SolidColor, "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2" " wasn't expecting SolidColor"); break; case HWC_FRAMEBUFFER_TARGET: // Do nothing, since it shouldn't be modified by HWC1 break; case HWC_SIDEBAND: ALOGE_IF(layer.getCompositionType() != Composition::Sideband, "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2" " wasn't expecting Sideband"); break; case HWC_CURSOR_OVERLAY: ALOGE_IF(layer.getCompositionType() != Composition::Cursor, "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but" " HWC2 wasn't expecting Cursor"); break; } } void HWC2On1Adapter::Display::updateLayerRequests( const hwc_layer_1_t& hwc1Layer, const Layer& layer) { if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) { mChanges->addLayerRequest(layer.getId(), LayerRequest::ClearClientTarget); } } void HWC2On1Adapter::Display::prepareFramebufferTarget() { // We check that mActiveConfig is valid in Display::prepare int32_t width = mActiveConfig->getAttribute(Attribute::Width); int32_t height = mActiveConfig->getAttribute(Attribute::Height); auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()]; hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET; hwc1Target.releaseFenceFd = -1; hwc1Target.hints = 0; hwc1Target.flags = 0; hwc1Target.transform = 0; hwc1Target.blending = HWC_BLENDING_PREMULT; if (mDevice.getHwc1MinorVersion() < 3) { hwc1Target.sourceCropi = {0, 0, width, height}; } else { hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast(width), static_cast(height)}; } hwc1Target.displayFrame = {0, 0, width, height}; hwc1Target.planeAlpha = 255; hwc1Target.visibleRegionScreen.numRects = 1; auto rects = static_cast(std::malloc(sizeof(hwc_rect_t))); rects[0].left = 0; rects[0].top = 0; rects[0].right = width; rects[0].bottom = height; hwc1Target.visibleRegionScreen.rects = rects; // We will set this to the correct value in set hwc1Target.acquireFenceFd = -1; } // Layer functions std::atomic HWC2On1Adapter::Layer::sNextId(1); HWC2On1Adapter::Layer::Layer(Display& display) : mId(sNextId++), mDisplay(display), mDirtyCount(0), mBuffer(), mSurfaceDamage(), mBlendMode(*this, BlendMode::None), mColor(*this, {0, 0, 0, 0}), mCompositionType(*this, Composition::Invalid), mDisplayFrame(*this, {0, 0, -1, -1}), mPlaneAlpha(*this, 0.0f), mSidebandStream(*this, nullptr), mSourceCrop(*this, {0.0f, 0.0f, -1.0f, -1.0f}), mTransform(*this, Transform::None), mVisibleRegion(*this, std::vector()), mZ(0), mReleaseFence(), mHwc1Id(0), mHasUnsupportedDataspace(false), mHasUnsupportedPlaneAlpha(false) {} bool HWC2On1Adapter::SortLayersByZ::operator()( const std::shared_ptr& lhs, const std::shared_ptr& rhs) { return lhs->getZ() < rhs->getZ(); } Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer, int32_t acquireFence) { ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId); mBuffer.setBuffer(buffer); mBuffer.setFence(acquireFence); return Error::None; } Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) { if (mCompositionType.getValue() != Composition::Cursor) { return Error::BadLayer; } if (mDisplay.hasChanges()) { return Error::NotValidated; } auto displayId = mDisplay.getHwc1Id(); auto hwc1Device = mDisplay.getDevice().getHwc1Device(); hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y); return Error::None; } Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) { mSurfaceDamage.resize(damage.numRects); std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin()); return Error::None; } // Layer state functions Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) { mBlendMode.setPending(mode); return Error::None; } Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) { mColor.setPending(color); return Error::None; } Error HWC2On1Adapter::Layer::setCompositionType(Composition type) { mCompositionType.setPending(type); return Error::None; } Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t dataspace) { mHasUnsupportedDataspace = (dataspace != HAL_DATASPACE_UNKNOWN); return Error::None; } Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) { mDisplayFrame.setPending(frame); return Error::None; } Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) { mPlaneAlpha.setPending(alpha); return Error::None; } Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) { mSidebandStream.setPending(stream); return Error::None; } Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) { mSourceCrop.setPending(crop); return Error::None; } Error HWC2On1Adapter::Layer::setTransform(Transform transform) { mTransform.setPending(transform); return Error::None; } Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t rawVisible) { std::vector visible(rawVisible.rects, rawVisible.rects + rawVisible.numRects); mVisibleRegion.setPending(std::move(visible)); return Error::None; } Error HWC2On1Adapter::Layer::setZ(uint32_t z) { mZ = z; return Error::None; } void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) { ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId); mReleaseFence.add(fenceFd); } const sp& HWC2On1Adapter::Layer::getReleaseFence() const { return mReleaseFence.get(); } void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer, bool applyAllState) { applyCommonState(hwc1Layer, applyAllState); auto compositionType = mCompositionType.getPendingValue(); if (compositionType == Composition::SolidColor) { applySolidColorState(hwc1Layer, applyAllState); } else if (compositionType == Composition::Sideband) { applySidebandState(hwc1Layer, applyAllState); } else { applyBufferState(hwc1Layer); } applyCompositionType(hwc1Layer, applyAllState); } // Layer dump helpers static std::string regionStrings(const std::vector& visibleRegion, const std::vector& surfaceDamage) { std::string regions; regions += " Visible Region"; regions.resize(40, ' '); regions += "Surface Damage\n"; size_t numPrinted = 0; size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size()); while (numPrinted < maxSize) { std::string line(" "); if (visibleRegion.empty() && numPrinted == 0) { line += "None"; } else if (numPrinted < visibleRegion.size()) { line += rectString(visibleRegion[numPrinted]); } line.resize(40, ' '); if (surfaceDamage.empty() && numPrinted == 0) { line += "None"; } else if (numPrinted < surfaceDamage.size()) { line += rectString(surfaceDamage[numPrinted]); } line += '\n'; regions += line; ++numPrinted; } return regions; } std::string HWC2On1Adapter::Layer::dump() const { std::stringstream output; const char* fill = " "; output << fill << to_string(mCompositionType.getPendingValue()); output << " Layer HWC2/1: " << mId << "/" << mHwc1Id << " "; output << "Z: " << mZ; if (mCompositionType.getValue() == HWC2::Composition::SolidColor) { output << " " << colorString(mColor.getValue()); } else if (mCompositionType.getValue() == HWC2::Composition::Sideband) { output << " Handle: " << mSidebandStream.getValue() << '\n'; } else { output << " Buffer: " << mBuffer.getBuffer() << "/" << mBuffer.getFence() << '\n'; output << fill << " Display frame [LTRB]: " << rectString(mDisplayFrame.getValue()) << '\n'; output << fill << " Source crop: " << frectString(mSourceCrop.getValue()) << '\n'; output << fill << " Transform: " << to_string(mTransform.getValue()); output << " Blend mode: " << to_string(mBlendMode.getValue()); if (mPlaneAlpha.getValue() != 1.0f) { output << " Alpha: " << alphaString(mPlaneAlpha.getValue()) << '\n'; } else { output << '\n'; } output << regionStrings(mVisibleRegion.getValue(), mSurfaceDamage); } return output.str(); } static int getHwc1Blending(HWC2::BlendMode blendMode) { switch (blendMode) { case BlendMode::Coverage: return HWC_BLENDING_COVERAGE; case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT; default: return HWC_BLENDING_NONE; } } void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer, bool applyAllState) { auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion(); if (applyAllState || mBlendMode.isDirty()) { hwc1Layer.blending = getHwc1Blending(mBlendMode.getPendingValue()); mBlendMode.latch(); } if (applyAllState || mDisplayFrame.isDirty()) { hwc1Layer.displayFrame = mDisplayFrame.getPendingValue(); mDisplayFrame.latch(); } if (applyAllState || mPlaneAlpha.isDirty()) { auto pendingAlpha = mPlaneAlpha.getPendingValue(); if (minorVersion < 2) { mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f; } else { hwc1Layer.planeAlpha = static_cast(255.0f * pendingAlpha + 0.5f); } mPlaneAlpha.latch(); } if (applyAllState || mSourceCrop.isDirty()) { if (minorVersion < 3) { auto pending = mSourceCrop.getPendingValue(); hwc1Layer.sourceCropi.left = static_cast(std::ceil(pending.left)); hwc1Layer.sourceCropi.top = static_cast(std::ceil(pending.top)); hwc1Layer.sourceCropi.right = static_cast(std::floor(pending.right)); hwc1Layer.sourceCropi.bottom = static_cast(std::floor(pending.bottom)); } else { hwc1Layer.sourceCropf = mSourceCrop.getPendingValue(); } mSourceCrop.latch(); } if (applyAllState || mTransform.isDirty()) { hwc1Layer.transform = static_cast(mTransform.getPendingValue()); mTransform.latch(); } if (applyAllState || mVisibleRegion.isDirty()) { auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen; std::free(const_cast(hwc1VisibleRegion.rects)); auto pending = mVisibleRegion.getPendingValue(); hwc_rect_t* newRects = static_cast( std::malloc(sizeof(hwc_rect_t) * pending.size())); std::copy(pending.begin(), pending.end(), newRects); hwc1VisibleRegion.rects = const_cast(newRects); hwc1VisibleRegion.numRects = pending.size(); mVisibleRegion.latch(); } } void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer, bool applyAllState) { if (applyAllState || mColor.isDirty()) { hwc1Layer.backgroundColor = mColor.getPendingValue(); mColor.latch(); } } void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer, bool applyAllState) { if (applyAllState || mSidebandStream.isDirty()) { hwc1Layer.sidebandStream = mSidebandStream.getPendingValue(); mSidebandStream.latch(); } } void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) { hwc1Layer.handle = mBuffer.getBuffer(); hwc1Layer.acquireFenceFd = mBuffer.getFence(); } void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer, bool applyAllState) { // HWC1 never supports color transforms or dataspaces and only sometimes // supports plane alpha (depending on the version). These require us to drop // some or all layers to client composition. if (mHasUnsupportedDataspace || mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform()) { hwc1Layer.compositionType = HWC_FRAMEBUFFER; hwc1Layer.flags = HWC_SKIP_LAYER; return; } if (applyAllState || mCompositionType.isDirty()) { hwc1Layer.flags = 0; switch (mCompositionType.getPendingValue()) { case Composition::Client: hwc1Layer.compositionType = HWC_FRAMEBUFFER; hwc1Layer.flags |= HWC_SKIP_LAYER; break; case Composition::Device: hwc1Layer.compositionType = HWC_FRAMEBUFFER; break; case Composition::SolidColor: hwc1Layer.compositionType = HWC_BACKGROUND; break; case Composition::Cursor: hwc1Layer.compositionType = HWC_FRAMEBUFFER; if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) { hwc1Layer.hints |= HWC_IS_CURSOR_LAYER; } break; case Composition::Sideband: if (mDisplay.getDevice().getHwc1MinorVersion() < 4) { hwc1Layer.compositionType = HWC_SIDEBAND; } else { hwc1Layer.compositionType = HWC_FRAMEBUFFER; hwc1Layer.flags |= HWC_SKIP_LAYER; } break; default: hwc1Layer.compositionType = HWC_FRAMEBUFFER; hwc1Layer.flags |= HWC_SKIP_LAYER; break; } ALOGV("Layer %" PRIu64 " %s set to %d", mId, to_string(mCompositionType.getPendingValue()).c_str(), hwc1Layer.compositionType); ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping"); mCompositionType.latch(); } } // Adapter helpers void HWC2On1Adapter::populateCapabilities() { ALOGV("populateCapabilities"); if (mHwc1MinorVersion >= 3U) { int supportedTypes = 0; auto result = mHwc1Device->query(mHwc1Device, HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes); if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL) != 0)) { ALOGI("Found support for HWC virtual displays"); mHwc1SupportsVirtualDisplays = true; } } if (mHwc1MinorVersion >= 4U) { mCapabilities.insert(Capability::SidebandStream); } } HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) { std::unique_lock lock(mStateMutex); auto display = mDisplays.find(id); if (display == mDisplays.end()) { return nullptr; } return display->second.get(); } std::tuple HWC2On1Adapter::getLayer( hwc2_display_t displayId, hwc2_layer_t layerId) { auto display = getDisplay(displayId); if (!display) { return std::make_tuple(static_cast(nullptr), Error::BadDisplay); } auto layerEntry = mLayers.find(layerId); if (layerEntry == mLayers.end()) { return std::make_tuple(static_cast(nullptr), Error::BadLayer); } auto layer = layerEntry->second; if (layer->getDisplay().getId() != displayId) { return std::make_tuple(static_cast(nullptr), Error::BadLayer); } return std::make_tuple(layer.get(), Error::None); } void HWC2On1Adapter::populatePrimary() { ALOGV("populatePrimary"); std::unique_lock lock(mStateMutex); auto display = std::make_shared(*this, HWC2::DisplayType::Physical); mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId(); display->setHwc1Id(HWC_DISPLAY_PRIMARY); display->populateConfigs(); mDisplays.emplace(display->getId(), std::move(display)); } bool HWC2On1Adapter::prepareAllDisplays() { ATRACE_CALL(); std::unique_lock lock(mStateMutex); for (const auto& displayPair : mDisplays) { auto& display = displayPair.second; if (!display->prepare()) { return false; } } if (mHwc1DisplayMap.count(0) == 0) { ALOGE("prepareAllDisplays: Unable to find primary HWC1 display"); return false; } // Always push the primary display std::vector requestedContents; auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY]; auto& primaryDisplay = mDisplays[primaryDisplayId]; auto primaryDisplayContents = primaryDisplay->cloneRequestedContents(); requestedContents.push_back(std::move(primaryDisplayContents)); // Push the external display, if present if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) { auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL]; auto& externalDisplay = mDisplays[externalDisplayId]; auto externalDisplayContents = externalDisplay->cloneRequestedContents(); requestedContents.push_back(std::move(externalDisplayContents)); } else { // Even if an external display isn't present, we still need to send // at least two displays down to HWC1 requestedContents.push_back(nullptr); } // Push the hardware virtual display, if supported and present if (mHwc1MinorVersion >= 3) { if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) { auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL]; auto& virtualDisplay = mDisplays[virtualDisplayId]; auto virtualDisplayContents = virtualDisplay->cloneRequestedContents(); requestedContents.push_back(std::move(virtualDisplayContents)); } else { requestedContents.push_back(nullptr); } } mHwc1Contents.clear(); for (auto& displayContents : requestedContents) { mHwc1Contents.push_back(displayContents.get()); if (!displayContents) { continue; } ALOGV("Display %zd layers:", mHwc1Contents.size() - 1); for (size_t l = 0; l < displayContents->numHwLayers; ++l) { auto& layer = displayContents->hwLayers[l]; ALOGV(" %zd: %d", l, layer.compositionType); } } ALOGV("Calling HWC1 prepare"); { ATRACE_NAME("HWC1 prepare"); mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data()); } for (size_t c = 0; c < mHwc1Contents.size(); ++c) { auto& contents = mHwc1Contents[c]; if (!contents) { continue; } ALOGV("Display %zd layers:", c); for (size_t l = 0; l < contents->numHwLayers; ++l) { ALOGV(" %zd: %d", l, contents->hwLayers[l].compositionType); } } // Return the received contents to their respective displays for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) { if (mHwc1Contents[hwc1Id] == nullptr) { continue; } auto displayId = mHwc1DisplayMap[hwc1Id]; auto& display = mDisplays[displayId]; display->setReceivedContents(std::move(requestedContents[hwc1Id])); } return true; } Error HWC2On1Adapter::setAllDisplays() { ATRACE_CALL(); std::unique_lock lock(mStateMutex); // Make sure we're ready to validate for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) { if (mHwc1Contents[hwc1Id] == nullptr) { continue; } auto displayId = mHwc1DisplayMap[hwc1Id]; auto& display = mDisplays[displayId]; Error error = display->set(*mHwc1Contents[hwc1Id]); if (error != Error::None) { ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id, to_string(error).c_str()); return error; } } ALOGV("Calling HWC1 set"); { ATRACE_NAME("HWC1 set"); mHwc1Device->set(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data()); } // Add retire and release fences for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) { if (mHwc1Contents[hwc1Id] == nullptr) { continue; } auto displayId = mHwc1DisplayMap[hwc1Id]; auto& display = mDisplays[displayId]; auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd; ALOGV("setAllDisplays: Adding retire fence %d to display %zd", retireFenceFd, hwc1Id); display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd); display->addReleaseFences(*mHwc1Contents[hwc1Id]); } return Error::None; } void HWC2On1Adapter::hwc1Invalidate() { ALOGV("Received hwc1Invalidate"); std::unique_lock lock(mStateMutex); // If the HWC2-side callback hasn't been registered yet, buffer this until // it is registered if (mCallbacks.count(Callback::Refresh) == 0) { mHasPendingInvalidate = true; return; } const auto& callbackInfo = mCallbacks[Callback::Refresh]; std::vector displays; for (const auto& displayPair : mDisplays) { displays.emplace_back(displayPair.first); } // Call back without the state lock held lock.unlock(); auto refresh = reinterpret_cast(callbackInfo.pointer); for (auto display : displays) { refresh(callbackInfo.data, display); } } void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) { ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp); std::unique_lock lock(mStateMutex); // If the HWC2-side callback hasn't been registered yet, buffer this until // it is registered if (mCallbacks.count(Callback::Vsync) == 0) { mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp); return; } if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) { ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId); return; } const auto& callbackInfo = mCallbacks[Callback::Vsync]; auto displayId = mHwc1DisplayMap[hwc1DisplayId]; // Call back without the state lock held lock.unlock(); auto vsync = reinterpret_cast(callbackInfo.pointer); vsync(callbackInfo.data, displayId, timestamp); } void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) { ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected); if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) { ALOGE("hwc1Hotplug: Received hotplug for non-external display"); return; } std::unique_lock lock(mStateMutex); // If the HWC2-side callback hasn't been registered yet, buffer this until // it is registered if (mCallbacks.count(Callback::Hotplug) == 0) { mPendingHotplugs.emplace_back(hwc1DisplayId, connected); return; } hwc2_display_t displayId = UINT64_MAX; if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) { if (connected == 0) { ALOGW("hwc1Hotplug: Received disconnect for unconnected display"); return; } // Create a new display on connect auto display = std::make_shared(*this, HWC2::DisplayType::Physical); display->setHwc1Id(HWC_DISPLAY_EXTERNAL); display->populateConfigs(); displayId = display->getId(); mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId; mDisplays.emplace(displayId, std::move(display)); } else { if (connected != 0) { ALOGW("hwc1Hotplug: Received connect for previously connected " "display"); return; } // Disconnect an existing display displayId = mHwc1DisplayMap[hwc1DisplayId]; mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL); mDisplays.erase(displayId); } const auto& callbackInfo = mCallbacks[Callback::Hotplug]; // Call back without the state lock held lock.unlock(); auto hotplug = reinterpret_cast(callbackInfo.pointer); auto hwc2Connected = (connected == 0) ? HWC2::Connection::Disconnected : HWC2::Connection::Connected; hotplug(callbackInfo.data, displayId, static_cast(hwc2Connected)); } } // namespace android services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h0100644 0000000 0000000 00000063251 13077405420 022256 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SF_HWC2_ON_1_ADAPTER_H #define ANDROID_SF_HWC2_ON_1_ADAPTER_H #define HWC2_INCLUDE_STRINGIFICATION #define HWC2_USE_CPP11 #include #undef HWC2_INCLUDE_STRINGIFICATION #undef HWC2_USE_CPP11 #include #include #include #include #include #include #include #include #include struct hwc_composer_device_1; struct hwc_display_contents_1; struct hwc_layer_1; namespace android { class HWC2On1Adapter : public hwc2_device_t { public: HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device); ~HWC2On1Adapter(); struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; } uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; } private: static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) { return static_cast(device); } // getCapabilities void doGetCapabilities(uint32_t* outCount, int32_t* /*hwc2_capability_t*/ outCapabilities); static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount, int32_t* /*hwc2_capability_t*/ outCapabilities) { getAdapter(device)->doGetCapabilities(outCount, outCapabilities); } // getFunction hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor); static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device, int32_t intDesc) { auto descriptor = static_cast(intDesc); return getAdapter(device)->doGetFunction(descriptor); } // Device functions HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height, hwc2_display_t* outDisplay); static int32_t createVirtualDisplayHook(hwc2_device_t* device, uint32_t width, uint32_t height, int32_t* /*format*/, hwc2_display_t* outDisplay) { // HWC1 implementations cannot override the buffer format requested by // the consumer auto error = getAdapter(device)->createVirtualDisplay(width, height, outDisplay); return static_cast(error); } HWC2::Error destroyVirtualDisplay(hwc2_display_t display); static int32_t destroyVirtualDisplayHook(hwc2_device_t* device, hwc2_display_t display) { auto error = getAdapter(device)->destroyVirtualDisplay(display); return static_cast(error); } std::string mDumpString; void dump(uint32_t* outSize, char* outBuffer); static void dumpHook(hwc2_device_t* device, uint32_t* outSize, char* outBuffer) { getAdapter(device)->dump(outSize, outBuffer); } uint32_t getMaxVirtualDisplayCount(); static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) { return getAdapter(device)->getMaxVirtualDisplayCount(); } HWC2::Error registerCallback(HWC2::Callback descriptor, hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer); static int32_t registerCallbackHook(hwc2_device_t* device, int32_t intDesc, hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) { auto descriptor = static_cast(intDesc); auto error = getAdapter(device)->registerCallback(descriptor, callbackData, pointer); return static_cast(error); } // Display functions class Layer; class SortLayersByZ { public: bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs); }; class DisplayContentsDeleter { public: void operator()(struct hwc_display_contents_1* contents); }; class DeferredFence { public: DeferredFence() : mMutex(), mFences({Fence::NO_FENCE, Fence::NO_FENCE}) {} void add(int32_t fenceFd) { mFences.emplace(new Fence(fenceFd)); mFences.pop(); } const sp& get() const { return mFences.front(); } private: mutable std::mutex mMutex; std::queue> mFences; }; class FencedBuffer { public: FencedBuffer() : mBuffer(nullptr), mFence(Fence::NO_FENCE) {} void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; } void setFence(int fenceFd) { mFence = new Fence(fenceFd); } buffer_handle_t getBuffer() const { return mBuffer; } int getFence() const { return mFence->dup(); } private: buffer_handle_t mBuffer; sp mFence; }; class Display { public: typedef std::unique_ptr HWC1Contents; Display(HWC2On1Adapter& device, HWC2::DisplayType type); hwc2_display_t getId() const { return mId; } HWC2On1Adapter& getDevice() const { return mDevice; } // Does not require locking because it is set before adding the // Displays to the Adapter's list of displays void setHwc1Id(int32_t id) { mHwc1Id = id; } int32_t getHwc1Id() const { return mHwc1Id; } void incDirty() { ++mDirtyCount; } void decDirty() { --mDirtyCount; } bool isDirty() const { return mDirtyCount > 0 || mZIsDirty; } // HWC2 Display functions HWC2::Error acceptChanges(); HWC2::Error createLayer(hwc2_layer_t* outLayerId); HWC2::Error destroyLayer(hwc2_layer_t layerId); HWC2::Error getActiveConfig(hwc2_config_t* outConfigId); HWC2::Error getAttribute(hwc2_config_t configId, HWC2::Attribute attribute, int32_t* outValue); HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes); HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes); HWC2::Error getConfigs(uint32_t* outNumConfigs, hwc2_config_t* outConfigIds); HWC2::Error getDozeSupport(int32_t* outSupport); HWC2::Error getHdrCapabilities(uint32_t* outNumTypes, int32_t* outTypes, float* outMaxLuminance, float* outMaxAverageLuminance, float* outMinLuminance); HWC2::Error getName(uint32_t* outSize, char* outName); HWC2::Error getReleaseFences(uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outFences); HWC2::Error getRequests(int32_t* outDisplayRequests, uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outLayerRequests); HWC2::Error getType(int32_t* outType); HWC2::Error present(int32_t* outRetireFence); HWC2::Error setActiveConfig(hwc2_config_t configId); HWC2::Error setClientTarget(buffer_handle_t target, int32_t acquireFence, int32_t dataspace, hwc_region_t damage); HWC2::Error setColorMode(int32_t mode); HWC2::Error setColorTransform(android_color_transform_t hint); HWC2::Error setOutputBuffer(buffer_handle_t buffer, int32_t releaseFence); HWC2::Error setPowerMode(HWC2::PowerMode mode); HWC2::Error setVsyncEnabled(HWC2::Vsync enabled); HWC2::Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests); HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z); // Read configs from HWC1 device void populateConfigs(); // Set configs for a virtual display void populateConfigs(uint32_t width, uint32_t height); bool prepare(); HWC1Contents cloneRequestedContents() const; void setReceivedContents(HWC1Contents contents); bool hasChanges() const; HWC2::Error set(hwc_display_contents_1& hwcContents); void addRetireFence(int fenceFd); void addReleaseFences(const hwc_display_contents_1& hwcContents); bool hasColorTransform() const; std::string dump() const; private: class Config { public: Config(Display& display) : mDisplay(display), mAttributes() {} bool isOnDisplay(const Display& display) const { return display.getId() == mDisplay.getId(); } void setAttribute(HWC2::Attribute attribute, int32_t value); int32_t getAttribute(HWC2::Attribute attribute) const; void setHwc1Id(uint32_t id); bool hasHwc1Id(uint32_t id) const; int32_t getColorModeForHwc1Id(uint32_t id) const; HWC2::Error getHwc1IdForColorMode(int32_t mode, uint32_t* outId) const; void setId(hwc2_config_t id) { mId = id; } hwc2_config_t getId() const { return mId; } // Attempts to merge two configs that differ only in color // mode. Returns whether the merge was successful bool merge(const Config& other); std::set getColorTransforms() const; // splitLine divides the output into two lines suitable for // dumpsys SurfaceFlinger std::string toString(bool splitLine = false) const; private: Display& mDisplay; hwc2_config_t mId; std::unordered_map mAttributes; // Maps from color transform to HWC1 config ID std::unordered_map mHwc1Ids; }; class Changes { public: uint32_t getNumTypes() const { return static_cast(mTypeChanges.size()); } uint32_t getNumLayerRequests() const { return static_cast(mLayerRequests.size()); } const std::unordered_map& getTypeChanges() const { return mTypeChanges; } const std::unordered_map& getLayerRequests() const { return mLayerRequests; } int32_t getDisplayRequests() const { int32_t requests = 0; for (auto request : mDisplayRequests) { requests |= static_cast(request); } return requests; } void addTypeChange(hwc2_layer_t layerId, HWC2::Composition type) { mTypeChanges.insert({layerId, type}); } void clearTypeChanges() { mTypeChanges.clear(); } void addLayerRequest(hwc2_layer_t layerId, HWC2::LayerRequest request) { mLayerRequests.insert({layerId, request}); } private: std::unordered_map mTypeChanges; std::unordered_map mLayerRequests; std::unordered_set mDisplayRequests; }; std::shared_ptr getConfig(hwc2_config_t configId) const; void populateColorModes(); void initializeActiveConfig(); void reallocateHwc1Contents(); void assignHwc1LayerIds(); void updateTypeChanges(const struct hwc_layer_1& hwc1Layer, const Layer& layer); void updateLayerRequests(const struct hwc_layer_1& hwc1Layer, const Layer& layer); void prepareFramebufferTarget(); static std::atomic sNextId; const hwc2_display_t mId; HWC2On1Adapter& mDevice; std::atomic mDirtyCount; // The state of this display should only be modified from // SurfaceFlinger's main loop, with the exception of when dump is // called. To prevent a bad state from crashing us during a dump // call, all public calls into Display must acquire this mutex. // // It is recursive because we don't want to deadlock in validate // (or present) when we call HWC2On1Adapter::prepareAllDisplays // (or setAllDisplays), which calls back into Display functions // which require locking. mutable std::recursive_mutex mStateMutex; bool mZIsDirty; HWC1Contents mHwc1RequestedContents; HWC1Contents mHwc1ReceivedContents; DeferredFence mRetireFence; // Will only be non-null after the layer has been validated but // before it has been presented std::unique_ptr mChanges; int32_t mHwc1Id; std::vector> mConfigs; std::shared_ptr mActiveConfig; std::set mColorModes; int32_t mActiveColorMode; std::string mName; HWC2::DisplayType mType; HWC2::PowerMode mPowerMode; HWC2::Vsync mVsyncEnabled; FencedBuffer mClientTarget; FencedBuffer mOutputBuffer; bool mHasColorTransform; std::multiset, SortLayersByZ> mLayers; std::unordered_map> mHwc1LayerMap; }; template static int32_t callDisplayFunction(hwc2_device_t* device, hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...), Args... args) { auto display = getAdapter(device)->getDisplay(displayId); if (!display) { return static_cast(HWC2::Error::BadDisplay); } auto error = ((*display).*member)(std::forward(args)...); return static_cast(error); } template static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId, Args... args) { return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc, std::forward(args)...); } static int32_t getDisplayAttributeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config, int32_t intAttribute, int32_t* outValue) { auto attribute = static_cast(intAttribute); return callDisplayFunction(device, display, &Display::getAttribute, config, attribute, outValue); } static int32_t setColorTransformHook(hwc2_device_t* device, hwc2_display_t display, const float* /*matrix*/, int32_t /*android_color_transform_t*/ intHint) { // We intentionally throw away the matrix, because if the hint is // anything other than IDENTITY, we have to fall back to client // composition anyway auto hint = static_cast(intHint); return callDisplayFunction(device, display, &Display::setColorTransform, hint); } static int32_t setPowerModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t intMode) { auto mode = static_cast(intMode); return callDisplayFunction(device, display, &Display::setPowerMode, mode); } static int32_t setVsyncEnabledHook(hwc2_device_t* device, hwc2_display_t display, int32_t intEnabled) { auto enabled = static_cast(intEnabled); return callDisplayFunction(device, display, &Display::setVsyncEnabled, enabled); } // Layer functions template class LatchedState { public: LatchedState(Layer& parent, T initialValue) : mParent(parent), mPendingValue(initialValue), mValue(initialValue) {} void setPending(T value) { if (value == mPendingValue) { return; } if (mPendingValue == mValue) { mParent.incDirty(); } else if (value == mValue) { mParent.decDirty(); } mPendingValue = value; } T getValue() const { return mValue; } T getPendingValue() const { return mPendingValue; } bool isDirty() const { return mPendingValue != mValue; } void latch() { if (isDirty()) { mValue = mPendingValue; mParent.decDirty(); } } private: Layer& mParent; T mPendingValue; T mValue; }; class Layer { public: Layer(Display& display); bool operator==(const Layer& other) { return mId == other.mId; } bool operator!=(const Layer& other) { return !(*this == other); } hwc2_layer_t getId() const { return mId; } Display& getDisplay() const { return mDisplay; } void incDirty() { if (mDirtyCount++ == 0) mDisplay.incDirty(); } void decDirty() { if (--mDirtyCount == 0) mDisplay.decDirty(); } bool isDirty() const { return mDirtyCount > 0; } // HWC2 Layer functions HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence); HWC2::Error setCursorPosition(int32_t x, int32_t y); HWC2::Error setSurfaceDamage(hwc_region_t damage); // HWC2 Layer state functions HWC2::Error setBlendMode(HWC2::BlendMode mode); HWC2::Error setColor(hwc_color_t color); HWC2::Error setCompositionType(HWC2::Composition type); HWC2::Error setDataspace(android_dataspace_t dataspace); HWC2::Error setDisplayFrame(hwc_rect_t frame); HWC2::Error setPlaneAlpha(float alpha); HWC2::Error setSidebandStream(const native_handle_t* stream); HWC2::Error setSourceCrop(hwc_frect_t crop); HWC2::Error setTransform(HWC2::Transform transform); HWC2::Error setVisibleRegion(hwc_region_t visible); HWC2::Error setZ(uint32_t z); HWC2::Composition getCompositionType() const { return mCompositionType.getValue(); } uint32_t getZ() const { return mZ; } void addReleaseFence(int fenceFd); const sp& getReleaseFence() const; void setHwc1Id(size_t id) { mHwc1Id = id; } size_t getHwc1Id() const { return mHwc1Id; } void applyState(struct hwc_layer_1& hwc1Layer, bool applyAllState); std::string dump() const; private: void applyCommonState(struct hwc_layer_1& hwc1Layer, bool applyAllState); void applySolidColorState(struct hwc_layer_1& hwc1Layer, bool applyAllState); void applySidebandState(struct hwc_layer_1& hwc1Layer, bool applyAllState); void applyBufferState(struct hwc_layer_1& hwc1Layer); void applyCompositionType(struct hwc_layer_1& hwc1Layer, bool applyAllState); static std::atomic sNextId; const hwc2_layer_t mId; Display& mDisplay; size_t mDirtyCount; FencedBuffer mBuffer; std::vector mSurfaceDamage; LatchedState mBlendMode; LatchedState mColor; LatchedState mCompositionType; LatchedState mDisplayFrame; LatchedState mPlaneAlpha; LatchedState mSidebandStream; LatchedState mSourceCrop; LatchedState mTransform; LatchedState> mVisibleRegion; uint32_t mZ; DeferredFence mReleaseFence; size_t mHwc1Id; bool mHasUnsupportedDataspace; bool mHasUnsupportedPlaneAlpha; }; template static int32_t callLayerFunction(hwc2_device_t* device, hwc2_display_t displayId, hwc2_layer_t layerId, HWC2::Error (Layer::*member)(Args...), Args... args) { auto result = getAdapter(device)->getLayer(displayId, layerId); auto error = std::get(result); if (error == HWC2::Error::None) { auto layer = std::get(result); error = ((*layer).*member)(std::forward(args)...); } return static_cast(error); } template static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId, hwc2_layer_t layerId, Args... args) { return HWC2On1Adapter::callLayerFunction(device, displayId, layerId, memFunc, std::forward(args)...); } // Layer state functions static int32_t setLayerBlendModeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) { auto mode = static_cast(intMode); return callLayerFunction(device, display, layer, &Layer::setBlendMode, mode); } static int32_t setLayerCompositionTypeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, int32_t intType) { auto type = static_cast(intType); return callLayerFunction(device, display, layer, &Layer::setCompositionType, type); } static int32_t setLayerDataspaceHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) { auto dataspace = static_cast(intDataspace); return callLayerFunction(device, display, layer, &Layer::setDataspace, dataspace); } static int32_t setLayerTransformHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) { auto transform = static_cast(intTransform); return callLayerFunction(device, display, layer, &Layer::setTransform, transform); } static int32_t setLayerZOrderHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, uint32_t z) { return callDisplayFunction(device, display, &Display::updateLayerZ, layer, z); } // Adapter internals void populateCapabilities(); Display* getDisplay(hwc2_display_t id); std::tuple getLayer(hwc2_display_t displayId, hwc2_layer_t layerId); void populatePrimary(); bool prepareAllDisplays(); std::vector mHwc1Contents; HWC2::Error setAllDisplays(); void hwc1Invalidate(); void hwc1Vsync(int hwc1DisplayId, int64_t timestamp); void hwc1Hotplug(int hwc1DisplayId, int connected); // These are set in the constructor and before any asynchronous events are // possible struct hwc_composer_device_1* const mHwc1Device; const uint8_t mHwc1MinorVersion; bool mHwc1SupportsVirtualDisplays; class Callbacks; const std::unique_ptr mHwc1Callbacks; std::unordered_set mCapabilities; // These are only accessed from the main SurfaceFlinger thread (not from // callbacks or dump std::map> mLayers; std::shared_ptr mHwc1VirtualDisplay; // These are potentially accessed from multiple threads, and are protected // by this mutex. This needs to be recursive, since the HWC1 implementation // can call back into the invalidate callback on the same thread that is // calling prepare. std::recursive_timed_mutex mStateMutex; struct CallbackInfo { hwc2_callback_data_t data; hwc2_function_pointer_t pointer; }; std::unordered_map mCallbacks; bool mHasPendingInvalidate; std::vector> mPendingVsyncs; std::vector> mPendingHotplugs; std::map> mDisplays; std::unordered_map mHwc1DisplayMap; }; } // namespace android #endif services/surfaceflinger/DisplayHardware/HWComposer.cpp0100644 0000000 0000000 00000066274 13077405420 022265 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "HWComposer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "HWComposer.h" #include "HWC2On1Adapter.h" #include "HWC2.h" #include "../Layer.h" // needed only for debugging #include "../SurfaceFlinger.h" namespace android { #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION // --------------------------------------------------------------------------- HWComposer::HWComposer(const sp& flinger) : mFlinger(flinger), mAdapter(), mHwcDevice(), mDisplayData(2), mFreeDisplaySlots(), mHwcDisplaySlots(), mCBContext(), mEventHandler(nullptr), mVSyncCounts(), mRemainingHwcVirtualDisplays(0) { for (size_t i=0 ; iregisterHotplugCallback(hotplugHook); auto invalidateHook = std::bind(&HWComposer::invalidate, this, std::placeholders::_1); mHwcDevice->registerRefreshCallback(invalidateHook); auto vsyncHook = std::bind(&HWComposer::vsync, this, std::placeholders::_1, std::placeholders::_2); mHwcDevice->registerVsyncCallback(vsyncHook); } } // Load and prepare the hardware composer module. Sets mHwc. void HWComposer::loadHwcModule() { ALOGV("loadHwcModule"); hw_module_t const* module; if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { ALOGE("%s module not found, aborting", HWC_HARDWARE_MODULE_ID); abort(); } hw_device_t* device = nullptr; int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device); if (error != 0) { ALOGE("Failed to open HWC device (%s), aborting", strerror(-error)); abort(); } uint32_t majorVersion = (device->version >> 24) & 0xF; if (majorVersion == 2) { mHwcDevice = std::make_unique( reinterpret_cast(device)); } else { mAdapter = std::make_unique( reinterpret_cast(device)); uint8_t minorVersion = mAdapter->getHwc1MinorVersion(); if (minorVersion < 1) { ALOGE("Cannot adapt to HWC version %d.%d", static_cast((minorVersion >> 8) & 0xF), static_cast(minorVersion & 0xF)); abort(); } mHwcDevice = std::make_unique( static_cast(mAdapter.get())); } mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } bool HWComposer::isValidDisplay(int32_t displayId) const { return static_cast(displayId) < mDisplayData.size() && mDisplayData[displayId].hwcDisplay; } void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { bool valid = true; switch (from) { case HWC2::Composition::Client: valid = false; break; case HWC2::Composition::Device: case HWC2::Composition::SolidColor: valid = (to == HWC2::Composition::Client); break; case HWC2::Composition::Cursor: case HWC2::Composition::Sideband: valid = (to == HWC2::Composition::Client || to == HWC2::Composition::Device); break; default: break; } if (!valid) { ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(), to_string(to).c_str()); } } void HWComposer::hotplug(const std::shared_ptr& display, HWC2::Connection connected) { ALOGV("hotplug: %" PRIu64 ", %s", display->getId(), to_string(connected).c_str()); int32_t disp = 0; if (!mDisplayData[0].hwcDisplay) { ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary" " display would be connected"); mDisplayData[0].hwcDisplay = display; mHwcDisplaySlots[display->getId()] = 0; disp = DisplayDevice::DISPLAY_PRIMARY; } else { // Disconnect is handled through HWComposer::disconnectDisplay via // SurfaceFlinger's onHotplugReceived callback handling if (connected == HWC2::Connection::Connected) { mDisplayData[1].hwcDisplay = display; mHwcDisplaySlots[display->getId()] = 1; } disp = DisplayDevice::DISPLAY_EXTERNAL; } mEventHandler->onHotplugReceived(disp, connected == HWC2::Connection::Connected); } void HWComposer::invalidate(const std::shared_ptr& /*display*/) { mFlinger->repaintEverything(); } void HWComposer::vsync(const std::shared_ptr& display, int64_t timestamp) { auto displayType = HWC2::DisplayType::Invalid; auto error = display->getType(&displayType); if (error != HWC2::Error::None) { ALOGE("vsync: Failed to determine type of display %" PRIu64, display->getId()); return; } if (displayType == HWC2::DisplayType::Virtual) { ALOGE("Virtual display %" PRIu64 " passed to vsync callback", display->getId()); return; } if (mHwcDisplaySlots.count(display->getId()) == 0) { ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback", display->getId()); return; } int32_t disp = mHwcDisplaySlots[display->getId()]; { Mutex::Autolock _l(mLock); // There have been reports of HWCs that signal several vsync events // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events // out here so they don't cause havoc downstream. if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); return; } mLastHwVSync[disp] = timestamp; } char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); mEventHandler->onVSyncReceived(disp, timestamp); } status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, android_pixel_format_t* format, int32_t *outId) { if (mRemainingHwcVirtualDisplays == 0) { ALOGE("allocateVirtualDisplay: No remaining virtual displays"); return NO_MEMORY; } std::shared_ptr display; auto error = mHwcDevice->createVirtualDisplay(width, height, format, &display); if (error != HWC2::Error::None) { ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display"); return NO_MEMORY; } size_t displaySlot = 0; if (!mFreeDisplaySlots.empty()) { displaySlot = *mFreeDisplaySlots.begin(); mFreeDisplaySlots.erase(displaySlot); } else if (mDisplayData.size() < INT32_MAX) { // Don't bother allocating a slot larger than we can return displaySlot = mDisplayData.size(); mDisplayData.resize(displaySlot + 1); } else { ALOGE("allocateVirtualDisplay: Unable to allocate a display slot"); return NO_MEMORY; } mDisplayData[displaySlot].hwcDisplay = display; --mRemainingHwcVirtualDisplays; *outId = static_cast(displaySlot); return NO_ERROR; } std::shared_ptr HWComposer::createLayer(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("Failed to create layer on invalid display %d", displayId); return nullptr; } auto display = mDisplayData[displayId].hwcDisplay; std::shared_ptr layer; auto error = display->createLayer(&layer); if (error != HWC2::Error::None) { ALOGE("Failed to create layer on display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return nullptr; } return layer; } nsecs_t HWComposer::getRefreshTimestamp(int32_t disp) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on // the refresh period and whatever closest timestamp we have. Mutex::Autolock _l(mLock); nsecs_t now = systemTime(CLOCK_MONOTONIC); auto vsyncPeriod = getActiveConfig(disp)->getVsyncPeriod(); return now - ((now - mLastHwVSync[disp]) % vsyncPeriod); } bool HWComposer::isConnected(int32_t disp) const { if (!isValidDisplay(disp)) { ALOGE("isConnected: Attempted to access invalid display %d", disp); return false; } return mDisplayData[disp].hwcDisplay->isConnected(); } std::vector> HWComposer::getConfigs(int32_t displayId) const { if (!isValidDisplay(displayId)) { ALOGE("getConfigs: Attempted to access invalid display %d", displayId); return {}; } auto& displayData = mDisplayData[displayId]; auto configs = mDisplayData[displayId].hwcDisplay->getConfigs(); if (displayData.configMap.empty()) { for (size_t i = 0; i < configs.size(); ++i) { displayData.configMap[i] = configs[i]; } } return configs; } std::shared_ptr HWComposer::getActiveConfig(int32_t displayId) const { if (!isValidDisplay(displayId)) { ALOGE("getActiveConfigs: Attempted to access invalid display %d", displayId); return nullptr; } std::shared_ptr config; auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config); if (error == HWC2::Error::BadConfig) { ALOGV("getActiveConfig: No config active, returning null"); return nullptr; } else if (error != HWC2::Error::None) { ALOGE("getActiveConfig failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return nullptr; } else if (!config) { ALOGE("getActiveConfig returned an unknown config for display %d", displayId); return nullptr; } return config; } void HWComposer::setVsyncEnabled(int32_t disp, HWC2::Vsync enabled) { if (disp < 0 || disp >= HWC_DISPLAY_VIRTUAL) { ALOGD("setVsyncEnabled: Ignoring for virtual display %d", disp); return; } if (!isValidDisplay(disp)) { ALOGE("setVsyncEnabled: Attempted to access invalid display %d", disp); return; } // NOTE: we use our own internal lock here because we have to call // into the HWC with the lock held, and we want to make sure // that even if HWC blocks (which it shouldn't), it won't // affect other threads. Mutex::Autolock _l(mVsyncLock); auto& displayData = mDisplayData[disp]; if (enabled != displayData.vsyncEnabled) { ATRACE_CALL(); auto error = displayData.hwcDisplay->setVsyncEnabled(enabled); if (error == HWC2::Error::None) { displayData.vsyncEnabled = enabled; char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp); ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0); } else { ALOGE("setVsyncEnabled: Failed to set vsync to %s on %d/%" PRIu64 ": %s (%d)", to_string(enabled).c_str(), disp, mDisplayData[disp].hwcDisplay->getId(), to_string(error).c_str(), static_cast(error)); } } } status_t HWComposer::setClientTarget(int32_t displayId, const sp& acquireFence, const sp& target, android_dataspace_t dataspace) { if (!isValidDisplay(displayId)) { return BAD_INDEX; } ALOGV("setClientTarget for display %d", displayId); auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; buffer_handle_t handle = nullptr; if ((target != nullptr) && target->getNativeBuffer()) { handle = target->getNativeBuffer()->handle; } auto error = hwcDisplay->setClientTarget(handle, acquireFence, dataspace); if (error != HWC2::Error::None) { ALOGE("Failed to set client target for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return BAD_VALUE; } return NO_ERROR; } status_t HWComposer::prepare(DisplayDevice& displayDevice) { ATRACE_CALL(); Mutex::Autolock _l(mDisplayLock); auto displayId = displayDevice.getHwcDisplayId(); if (!isValidDisplay(displayId)) { return BAD_INDEX; } auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; if (!hwcDisplay->isConnected()) { return NO_ERROR; } uint32_t numTypes = 0; uint32_t numRequests = 0; auto error = hwcDisplay->validate(&numTypes, &numRequests); if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) { ALOGE("prepare: validate failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return BAD_INDEX; } std::unordered_map, HWC2::Composition> changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); if (error != HWC2::Error::None) { ALOGE("prepare: getChangedCompositionTypes failed on display %d: " "%s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return BAD_INDEX; } displayData.displayRequests = static_cast(0); std::unordered_map, HWC2::LayerRequest> layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayData.displayRequests, &layerRequests); if (error != HWC2::Error::None) { ALOGE("prepare: getRequests failed on display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return BAD_INDEX; } displayData.hasClientComposition = false; displayData.hasDeviceComposition = false; for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) { auto hwcLayer = layer->getHwcLayer(displayId); if (changedTypes.count(hwcLayer) != 0) { // We pass false so we only update our state and don't call back // into the HWC device validateChange(layer->getCompositionType(displayId), changedTypes[hwcLayer]); layer->setCompositionType(displayId, changedTypes[hwcLayer], false); } switch (layer->getCompositionType(displayId)) { case HWC2::Composition::Client: displayData.hasClientComposition = true; break; case HWC2::Composition::Device: case HWC2::Composition::SolidColor: case HWC2::Composition::Cursor: case HWC2::Composition::Sideband: displayData.hasDeviceComposition = true; break; default: break; } if (layerRequests.count(hwcLayer) != 0 && layerRequests[hwcLayer] == HWC2::LayerRequest::ClearClientTarget) { layer->setClearClientTarget(displayId, true); } else { if (layerRequests.count(hwcLayer) != 0) { ALOGE("prepare: Unknown layer request: %s", to_string(layerRequests[hwcLayer]).c_str()); } layer->setClearClientTarget(displayId, false); } } error = hwcDisplay->acceptChanges(); if (error != HWC2::Error::None) { ALOGE("prepare: acceptChanges failed: %s", to_string(error).c_str()); return BAD_INDEX; } return NO_ERROR; } bool HWComposer::hasDeviceComposition(int32_t displayId) const { if (!isValidDisplay(displayId)) { ALOGE("hasDeviceComposition: Invalid display %d", displayId); return false; } return mDisplayData[displayId].hasDeviceComposition; } bool HWComposer::hasClientComposition(int32_t displayId) const { if (!isValidDisplay(displayId)) { ALOGE("hasClientComposition: Invalid display %d", displayId); return true; } return mDisplayData[displayId].hasClientComposition; } sp HWComposer::getRetireFence(int32_t displayId) const { if (!isValidDisplay(displayId)) { ALOGE("getRetireFence failed for invalid display %d", displayId); return Fence::NO_FENCE; } return mDisplayData[displayId].lastRetireFence; } sp HWComposer::getLayerReleaseFence(int32_t displayId, const std::shared_ptr& layer) const { if (!isValidDisplay(displayId)) { ALOGE("getLayerReleaseFence: Invalid display"); return Fence::NO_FENCE; } auto displayFences = mDisplayData[displayId].releaseFences; if (displayFences.count(layer) == 0) { ALOGV("getLayerReleaseFence: Release fence not found"); return Fence::NO_FENCE; } return displayFences[layer]; } status_t HWComposer::commit(int32_t displayId) { ATRACE_CALL(); if (!isValidDisplay(displayId)) { return BAD_INDEX; } auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; auto error = hwcDisplay->present(&displayData.lastRetireFence); if (error != HWC2::Error::None) { ALOGE("commit: present failed for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return UNKNOWN_ERROR; } std::unordered_map, sp> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); if (error != HWC2::Error::None) { ALOGE("commit: Failed to get release fences for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return UNKNOWN_ERROR; } displayData.releaseFences = std::move(releaseFences); return NO_ERROR; } status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) { ALOGV("setPowerMode(%d, %d)", displayId, intMode); if (!isValidDisplay(displayId)) { ALOGE("setPowerMode: Bad display"); return BAD_INDEX; } if (displayId >= VIRTUAL_DISPLAY_ID_BASE) { ALOGE("setPowerMode: Virtual display %d passed in, returning", displayId); return BAD_INDEX; } auto mode = static_cast(intMode); if (mode == HWC2::PowerMode::Off) { setVsyncEnabled(displayId, HWC2::Vsync::Disable); } auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; switch (mode) { case HWC2::PowerMode::Off: case HWC2::PowerMode::On: ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); { auto error = hwcDisplay->setPowerMode(mode); if (error != HWC2::Error::None) { ALOGE("setPowerMode: Unable to set power mode %s for " "display %d: %s (%d)", to_string(mode).c_str(), displayId, to_string(error).c_str(), static_cast(error)); } } break; case HWC2::PowerMode::Doze: case HWC2::PowerMode::DozeSuspend: ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); { bool supportsDoze = false; auto error = hwcDisplay->supportsDoze(&supportsDoze); if (error != HWC2::Error::None) { ALOGE("setPowerMode: Unable to query doze support for " "display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); } if (!supportsDoze) { mode = HWC2::PowerMode::On; } error = hwcDisplay->setPowerMode(mode); if (error != HWC2::Error::None) { ALOGE("setPowerMode: Unable to set power mode %s for " "display %d: %s (%d)", to_string(mode).c_str(), displayId, to_string(error).c_str(), static_cast(error)); } } break; default: ALOGV("setPowerMode: Not calling HWC"); break; } return NO_ERROR; } status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) { if (!isValidDisplay(displayId)) { ALOGE("setActiveConfig: Display %d is not valid", displayId); return BAD_INDEX; } auto& displayData = mDisplayData[displayId]; if (displayData.configMap.count(configId) == 0) { ALOGE("setActiveConfig: Invalid config %zd", configId); return BAD_INDEX; } auto error = displayData.hwcDisplay->setActiveConfig( displayData.configMap[configId]); if (error != HWC2::Error::None) { ALOGE("setActiveConfig: Failed to set config %zu on display %d: " "%s (%d)", configId, displayId, to_string(error).c_str(), static_cast(error)); return UNKNOWN_ERROR; } return NO_ERROR; } void HWComposer::disconnectDisplay(int displayId) { LOG_ALWAYS_FATAL_IF(displayId < 0); auto& displayData = mDisplayData[displayId]; auto displayType = HWC2::DisplayType::Invalid; auto error = displayData.hwcDisplay->getType(&displayType); if (error != HWC2::Error::None) { ALOGE("disconnectDisplay: Failed to determine type of display %d", displayId); return; } // If this was a virtual display, add its slot back for reuse by future // virtual displays if (displayType == HWC2::DisplayType::Virtual) { mFreeDisplaySlots.insert(displayId); ++mRemainingHwcVirtualDisplays; } auto hwcId = displayData.hwcDisplay->getId(); mHwcDisplaySlots.erase(hwcId); displayData.reset(); } status_t HWComposer::setOutputBuffer(int32_t displayId, const sp& acquireFence, const sp& buffer) { if (!isValidDisplay(displayId)) { ALOGE("setOutputBuffer: Display %d is not valid", displayId); return BAD_INDEX; } auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; auto displayType = HWC2::DisplayType::Invalid; auto error = hwcDisplay->getType(&displayType); if (error != HWC2::Error::None) { ALOGE("setOutputBuffer: Failed to determine type of display %d", displayId); return NAME_NOT_FOUND; } if (displayType != HWC2::DisplayType::Virtual) { ALOGE("setOutputBuffer: Display %d is not virtual", displayId); return INVALID_OPERATION; } error = hwcDisplay->setOutputBuffer(buffer, acquireFence); if (error != HWC2::Error::None) { ALOGE("setOutputBuffer: Failed to set buffer on display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return UNKNOWN_ERROR; } return NO_ERROR; } void HWComposer::clearReleaseFences(int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("clearReleaseFences: Display %d is not valid", displayId); return; } mDisplayData[displayId].releaseFences.clear(); } std::unique_ptr HWComposer::getHdrCapabilities( int32_t displayId) { if (!isValidDisplay(displayId)) { ALOGE("getHdrCapabilities: Display %d is not valid", displayId); return nullptr; } auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; std::unique_ptr capabilities; auto error = hwcDisplay->getHdrCapabilities(&capabilities); if (error != HWC2::Error::None) { ALOGE("getOutputCapabilities: Failed to get capabilities on display %d:" " %s (%d)", displayId, to_string(error).c_str(), static_cast(error)); return nullptr; } return capabilities; } // Converts a PixelFormat to a human-readable string. Max 11 chars. // (Could use a table of prefab String8 objects.) /* static String8 getFormatStr(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888"); case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888"); case PIXEL_FORMAT_RGB_888: return String8("RGB_888"); case PIXEL_FORMAT_RGB_565: return String8("RGB_565"); case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888"); case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return String8("ImplDef"); default: String8 result; result.appendFormat("? %08x", format); return result; } } */ void HWComposer::dump(String8& result) const { // TODO: In order to provide a dump equivalent to HWC1, we need to shadow // all the state going into the layers. This is probably better done in // Layer itself, but it's going to take a bit of work to get there. result.append(mHwcDevice->dump().c_str()); } // --------------------------------------------------------------------------- HWComposer::DisplayData::DisplayData() : hasClientComposition(false), hasDeviceComposition(false), hwcDisplay(), lastRetireFence(Fence::NO_FENCE), outbufHandle(nullptr), outbufAcquireFence(Fence::NO_FENCE), vsyncEnabled(HWC2::Vsync::Disable) { ALOGV("Created new DisplayData"); } HWComposer::DisplayData::~DisplayData() { } void HWComposer::DisplayData::reset() { ALOGV("DisplayData reset"); *this = DisplayData(); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/DisplayHardware/HWComposer.h0100644 0000000 0000000 00000016214 13077405420 021717 0ustar000000000 0000000 /* * Copyright (C) 2010 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 USE_HWC2 #include "HWComposer_hwc1.h" #else #ifndef ANDROID_SF_HWCOMPOSER_H #define ANDROID_SF_HWCOMPOSER_H #include "HWC2.h" #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); struct framebuffer_device_t; namespace HWC2 { class Device; class Display; } namespace android { // --------------------------------------------------------------------------- class DisplayDevice; class Fence; class FloatRect; class GraphicBuffer; class HWC2On1Adapter; class NativeHandle; class Region; class String8; class SurfaceFlinger; class HWComposer { public: class EventHandler { friend class HWComposer; virtual void onVSyncReceived(int32_t disp, nsecs_t timestamp) = 0; virtual void onHotplugReceived(int32_t disp, bool connected) = 0; protected: virtual ~EventHandler() {} }; HWComposer(const sp& flinger); ~HWComposer(); void setEventHandler(EventHandler* handler); // Attempts to allocate a virtual display. If the virtual display is created // on the HWC device, outId will contain its HWC ID. status_t allocateVirtualDisplay(uint32_t width, uint32_t height, android_pixel_format_t* format, int32_t* outId); // Attempts to create a new layer on this display std::shared_ptr createLayer(int32_t displayId); // Asks the HAL what it can do status_t prepare(DisplayDevice& displayDevice); status_t setClientTarget(int32_t displayId, const sp& acquireFence, const sp& target, android_dataspace_t dataspace); // Finalize the layers and present them status_t commit(int32_t displayId); // set power mode status_t setPowerMode(int32_t displayId, int mode); // set active config status_t setActiveConfig(int32_t displayId, size_t configId); // reset state when an external, non-virtual display is disconnected void disconnectDisplay(int32_t displayId); // does this display have layers handled by HWC bool hasDeviceComposition(int32_t displayId) const; // does this display have layers handled by GLES bool hasClientComposition(int32_t displayId) const; // get the retire fence for the previous frame (i.e., corresponding to the // last call to presentDisplay sp getRetireFence(int32_t displayId) const; // Get last release fence for the given layer sp getLayerReleaseFence(int32_t displayId, const std::shared_ptr& layer) const; // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if displayId is not a virtual display. status_t setOutputBuffer(int32_t displayId, const sp& acquireFence, const sp& buf); // After SurfaceFlinger has retrieved the release fences for all the frames, // it can call this to clear the shared pointers in the release fence map void clearReleaseFences(int32_t displayId); // Returns the HDR capabilities of the given display std::unique_ptr getHdrCapabilities(int32_t displayId); // Events handling --------------------------------------------------------- void setVsyncEnabled(int32_t disp, HWC2::Vsync enabled); struct DisplayConfig { uint32_t width; uint32_t height; float xdpi; float ydpi; nsecs_t refresh; int colorTransform; }; // Query display parameters. Pass in a display index (e.g. // HWC_DISPLAY_PRIMARY). nsecs_t getRefreshTimestamp(int32_t disp) const; bool isConnected(int32_t disp) const; // Non-const because it can update configMap inside of mDisplayData std::vector> getConfigs(int32_t displayId) const; std::shared_ptr getActiveConfig(int32_t displayId) const; // for debugging ---------------------------------------------------------- void dump(String8& out) const; private: static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2; void loadHwcModule(); bool isValidDisplay(int32_t displayId) const; static void validateChange(HWC2::Composition from, HWC2::Composition to); struct cb_context; void invalidate(const std::shared_ptr& display); void vsync(const std::shared_ptr& display, int64_t timestamp); void hotplug(const std::shared_ptr& display, HWC2::Connection connected); struct DisplayData { DisplayData(); ~DisplayData(); void reset(); bool hasClientComposition; bool hasDeviceComposition; std::shared_ptr hwcDisplay; HWC2::DisplayRequest displayRequests; sp lastRetireFence; // signals when the last set op retires std::unordered_map, sp> releaseFences; buffer_handle_t outbufHandle; sp outbufAcquireFence; mutable std::unordered_map> configMap; // protected by mVsyncLock HWC2::Vsync vsyncEnabled; }; sp mFlinger; std::unique_ptr mAdapter; std::unique_ptr mHwcDevice; std::vector mDisplayData; std::set mFreeDisplaySlots; std::unordered_map mHwcDisplaySlots; // protect mDisplayData from races between prepare and dump mutable Mutex mDisplayLock; cb_context* mCBContext; EventHandler* mEventHandler; size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; uint32_t mRemainingHwcVirtualDisplays; // protected by mLock mutable Mutex mLock; mutable std::unordered_map mLastHwVSync; // thread-safe mutable Mutex mVsyncLock; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_HWCOMPOSER_H #endif // #ifdef USE_HWC2 services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp0100644 0000000 0000000 00000136704 13077405420 023203 0ustar000000000 0000000 /* * Copyright (C) 2010 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "HWComposer.h" #include "../Layer.h" // needed only for debugging #include "../SurfaceFlinger.h" namespace android { #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { uint32_t hwcVersion = hwc->common.version; return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; } static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) { uint32_t hwcVersion = hwc->common.version; return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK; } static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc, uint32_t version) { return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK); } // --------------------------------------------------------------------------- struct HWComposer::cb_context { struct callbacks : public hwc_procs_t { // these are here to facilitate the transition when adding // new callbacks (an implementation can check for NULL before // calling a new callback). void (*zero[4])(void); }; callbacks procs; HWComposer* hwc; }; // --------------------------------------------------------------------------- HWComposer::HWComposer( const sp& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false) { for (size_t i =0 ; i> 24) & 0xff, (hwcApiVersion(mHwc) >> 16) & 0xff); if (mHwc->registerProcs) { mCBContext->hwc = this; mCBContext->procs.invalidate = &hook_invalidate; mCBContext->procs.vsync = &hook_vsync; if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) mCBContext->procs.hotplug = &hook_hotplug; else mCBContext->procs.hotplug = NULL; memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); mHwc->registerProcs(mHwc, &mCBContext->procs); } // don't need a vsync thread if we have a hardware composer needVSyncThread = false; // always turn vsync off when we start eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); // the number of displays we actually have depends on the // hw composer version if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { // 1.3 adds support for virtual displays mNumDisplays = MAX_HWC_DISPLAYS; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // 1.1 adds support for multiple displays mNumDisplays = NUM_BUILTIN_DISPLAYS; } else { mNumDisplays = 1; } } if (mFbDev) { ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), "should only have fbdev if no hwc or hwc is 1.0"); DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); disp.connected = true; disp.format = mFbDev->format; DisplayConfig config = DisplayConfig(); config.width = mFbDev->width; config.height = mFbDev->height; config.xdpi = mFbDev->xdpi; config.ydpi = mFbDev->ydpi; config.refresh = nsecs_t(1e9 / mFbDev->fps); disp.configs.push_back(config); disp.currentConfig = 0; } else if (mHwc) { // here we're guaranteed to have at least HWC 1.1 for (size_t i =0 ; irequestExitAndWait(); } if (mHwc) { hwc_close_1(mHwc); } if (mFbDev) { framebuffer_close(mFbDev); } delete mCBContext; } // Load and prepare the hardware composer module. Sets mHwc. void HWComposer::loadHwcModule() { hw_module_t const* module; if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID); return; } int err = hwc_open_1(module, &mHwc); if (err) { ALOGE("%s device failed to initialize (%s)", HWC_HARDWARE_COMPOSER, strerror(-err)); return; } if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) || hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION || hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) { ALOGE("%s device version %#x unsupported, will not be used", HWC_HARDWARE_COMPOSER, mHwc->common.version); hwc_close_1(mHwc); mHwc = NULL; return; } } // Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev. int HWComposer::loadFbHalModule() { hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err != 0) { ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID); return err; } return framebuffer_open(module, &mFbDev); } status_t HWComposer::initCheck() const { return mHwc ? NO_ERROR : NO_INIT; } void HWComposer::hook_invalidate(const struct hwc_procs* procs) { cb_context* ctx = reinterpret_cast( const_cast(procs)); ctx->hwc->invalidate(); } void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp, int64_t timestamp) { cb_context* ctx = reinterpret_cast( const_cast(procs)); ctx->hwc->vsync(disp, timestamp); } void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp, int connected) { cb_context* ctx = reinterpret_cast( const_cast(procs)); ctx->hwc->hotplug(disp, connected); } void HWComposer::invalidate() { mFlinger->repaintEverything(); } void HWComposer::vsync(int disp, int64_t timestamp) { if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { { Mutex::Autolock _l(mLock); // There have been reports of HWCs that signal several vsync events // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events // out here so they don't cause havoc downstream. if (timestamp == mLastHwVSync[disp]) { ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", timestamp); return; } mLastHwVSync[disp] = timestamp; } char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); mEventHandler.onVSyncReceived(disp, timestamp); } } void HWComposer::hotplug(int disp, int connected) { if (disp >= VIRTUAL_DISPLAY_ID_BASE) { ALOGE("hotplug event received for invalid display: disp=%d connected=%d", disp, connected); return; } queryDisplayProperties(disp); // Do not teardown or recreate the primary display if (disp != HWC_DISPLAY_PRIMARY) { mEventHandler.onHotplugReceived(disp, bool(connected)); } } static float getDefaultDensity(uint32_t width, uint32_t height) { // Default density is based on TVs: 1080p displays get XHIGH density, // lower-resolution displays get TV density. Maybe eventually we'll need // to update it for 4K displays, though hopefully those just report // accurate DPI information to begin with. This is also used for virtual // displays and even primary displays with older hwcomposers, so be // careful about orientation. uint32_t h = width < height ? width : height; if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH; else return ACONFIGURATION_DENSITY_TV; } static const uint32_t DISPLAY_ATTRIBUTES[] = { HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_COLOR_TRANSFORM, HWC_DISPLAY_NO_ATTRIBUTE, }; #define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0]) static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = { HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_NO_ATTRIBUTE, }; status_t HWComposer::queryDisplayProperties(int disp) { LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); // use zero as default value for unspecified attributes int32_t values[NUM_DISPLAY_ATTRIBUTES - 1]; memset(values, 0, sizeof(values)); const size_t MAX_NUM_CONFIGS = 128; uint32_t configs[MAX_NUM_CONFIGS] = {0}; size_t numConfigs = MAX_NUM_CONFIGS; status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs); if (err != NO_ERROR) { // this can happen if an unpluggable display is not connected mDisplayData[disp].connected = false; return err; } mDisplayData[disp].currentConfig = 0; for (size_t c = 0; c < numConfigs; ++c) { err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], DISPLAY_ATTRIBUTES, values); // If this is a pre-1.5 HWC, it may not know about color transform, so // try again with a smaller set of attributes if (err != NO_ERROR) { err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], PRE_HWC15_DISPLAY_ATTRIBUTES, values); } if (err != NO_ERROR) { // we can't get this display's info. turn it off. mDisplayData[disp].connected = false; return err; } DisplayConfig config = DisplayConfig(); for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { switch (DISPLAY_ATTRIBUTES[i]) { case HWC_DISPLAY_VSYNC_PERIOD: config.refresh = nsecs_t(values[i]); break; case HWC_DISPLAY_WIDTH: config.width = values[i]; break; case HWC_DISPLAY_HEIGHT: config.height = values[i]; break; case HWC_DISPLAY_DPI_X: config.xdpi = values[i] / 1000.0f; break; case HWC_DISPLAY_DPI_Y: config.ydpi = values[i] / 1000.0f; break; case HWC_DISPLAY_COLOR_TRANSFORM: config.colorTransform = values[i]; break; default: ALOG_ASSERT(false, "unknown display attribute[%zu] %#x", i, DISPLAY_ATTRIBUTES[i]); break; } } if (config.xdpi == 0.0f || config.ydpi == 0.0f) { float dpi = getDefaultDensity(config.width, config.height); config.xdpi = dpi; config.ydpi = dpi; } mDisplayData[disp].configs.push_back(config); } // FIXME: what should we set the format to? mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888; mDisplayData[disp].connected = true; return NO_ERROR; } status_t HWComposer::setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h, uint32_t format) { if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) || !mAllocatedDisplayIDs.hasBit(id)) { return BAD_INDEX; } size_t configId = mDisplayData[id].currentConfig; mDisplayData[id].format = format; DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId); config.width = w; config.height = h; config.xdpi = config.ydpi = getDefaultDensity(w, h); return NO_ERROR; } int32_t HWComposer::allocateDisplayId() { if (mAllocatedDisplayIDs.count() >= mNumDisplays) { return NO_MEMORY; } int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit(); mAllocatedDisplayIDs.markBit(id); mDisplayData[id].connected = true; mDisplayData[id].configs.resize(1); mDisplayData[id].currentConfig = 0; return id; } status_t HWComposer::freeDisplayId(int32_t id) { if (id < NUM_BUILTIN_DISPLAYS) { // cannot free the reserved IDs return BAD_VALUE; } if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { return BAD_INDEX; } mAllocatedDisplayIDs.clearBit(id); mDisplayData[id].connected = false; return NO_ERROR; } nsecs_t HWComposer::getRefreshTimestamp(int disp) const { // this returns the last refresh timestamp. // if the last one is not available, we estimate it based on // the refresh period and whatever closest timestamp we have. Mutex::Autolock _l(mLock); nsecs_t now = systemTime(CLOCK_MONOTONIC); size_t configId = mDisplayData[disp].currentConfig; return now - ((now - mLastHwVSync[disp]) % mDisplayData[disp].configs[configId].refresh); } sp HWComposer::getDisplayFence(int disp) const { return mDisplayData[disp].lastDisplayFence; } uint32_t HWComposer::getFormat(int disp) const { if (static_cast(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { return HAL_PIXEL_FORMAT_RGBA_8888; } else { return mDisplayData[disp].format; } } bool HWComposer::isConnected(int disp) const { return mDisplayData[disp].connected; } uint32_t HWComposer::getWidth(int disp) const { size_t currentConfig = mDisplayData[disp].currentConfig; return mDisplayData[disp].configs[currentConfig].width; } uint32_t HWComposer::getHeight(int disp) const { size_t currentConfig = mDisplayData[disp].currentConfig; return mDisplayData[disp].configs[currentConfig].height; } float HWComposer::getDpiX(int disp) const { size_t currentConfig = mDisplayData[disp].currentConfig; return mDisplayData[disp].configs[currentConfig].xdpi; } float HWComposer::getDpiY(int disp) const { size_t currentConfig = mDisplayData[disp].currentConfig; return mDisplayData[disp].configs[currentConfig].ydpi; } nsecs_t HWComposer::getRefreshPeriod(int disp) const { size_t currentConfig = mDisplayData[disp].currentConfig; return mDisplayData[disp].configs[currentConfig].refresh; } const Vector& HWComposer::getConfigs(int disp) const { return mDisplayData[disp].configs; } size_t HWComposer::getCurrentConfig(int disp) const { return mDisplayData[disp].currentConfig; } void HWComposer::eventControl(int disp, int event, int enabled) { if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)", event, disp, enabled); return; } if (event != EVENT_VSYNC) { ALOGW("eventControl got unexpected event %d (disp=%d en=%d)", event, disp, enabled); return; } status_t err = NO_ERROR; if (mHwc && !mDebugForceFakeVSync) { // NOTE: we use our own internal lock here because we have to call // into the HWC with the lock held, and we want to make sure // that even if HWC blocks (which it shouldn't), it won't // affect other threads. Mutex::Autolock _l(mEventControlLock); const int32_t eventBit = 1UL << event; const int32_t newValue = enabled ? eventBit : 0; const int32_t oldValue = mDisplayData[disp].events & eventBit; if (newValue != oldValue) { ATRACE_CALL(); err = mHwc->eventControl(mHwc, disp, event, enabled); if (!err) { int32_t& events(mDisplayData[disp].events); events = (events & ~eventBit) | newValue; char tag[16]; snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp); ATRACE_INT(tag, enabled); } } // error here should not happen -- not sure what we should // do if it does. ALOGE_IF(err, "eventControl(%d, %d) failed %s", event, enabled, strerror(-err)); } if (err == NO_ERROR && mVSyncThread != NULL) { mVSyncThread->setEnabled(enabled); } } status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { return BAD_INDEX; } if (mHwc) { DisplayData& disp(mDisplayData[id]); if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // we need space for the HWC_FRAMEBUFFER_TARGET numLayers++; } if (disp.capacity < numLayers || disp.list == NULL) { size_t size = sizeof(hwc_display_contents_1_t) + numLayers * sizeof(hwc_layer_1_t); free(disp.list); disp.list = (hwc_display_contents_1_t*)malloc(size); disp.capacity = numLayers; } if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1]; memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t)); const DisplayConfig& currentConfig = disp.configs[disp.currentConfig]; const hwc_rect_t r = { 0, 0, (int) currentConfig.width, (int) currentConfig.height }; disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; disp.framebufferTarget->hints = 0; disp.framebufferTarget->flags = 0; disp.framebufferTarget->handle = disp.fbTargetHandle; disp.framebufferTarget->transform = 0; disp.framebufferTarget->blending = HWC_BLENDING_PREMULT; if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { disp.framebufferTarget->sourceCropf.left = 0; disp.framebufferTarget->sourceCropf.top = 0; disp.framebufferTarget->sourceCropf.right = currentConfig.width; disp.framebufferTarget->sourceCropf.bottom = currentConfig.height; } else { disp.framebufferTarget->sourceCrop = r; } disp.framebufferTarget->displayFrame = r; disp.framebufferTarget->visibleRegionScreen.numRects = 1; disp.framebufferTarget->visibleRegionScreen.rects = &disp.framebufferTarget->displayFrame; disp.framebufferTarget->acquireFenceFd = -1; disp.framebufferTarget->releaseFenceFd = -1; disp.framebufferTarget->planeAlpha = 0xFF; } disp.list->retireFenceFd = -1; disp.list->flags = HWC_GEOMETRY_CHANGED; disp.list->numHwLayers = numLayers; } return NO_ERROR; } status_t HWComposer::setFramebufferTarget(int32_t id, const sp& acquireFence, const sp& buf) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { return BAD_INDEX; } DisplayData& disp(mDisplayData[id]); if (!disp.framebufferTarget) { // this should never happen, but apparently eglCreateWindowSurface() // triggers a Surface::queueBuffer() on some // devices (!?) -- log and ignore. ALOGE("HWComposer: framebufferTarget is null"); return NO_ERROR; } int acquireFenceFd = -1; if (acquireFence->isValid()) { acquireFenceFd = acquireFence->dup(); } // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd); disp.fbTargetHandle = buf->handle; disp.framebufferTarget->handle = disp.fbTargetHandle; disp.framebufferTarget->acquireFenceFd = acquireFenceFd; return NO_ERROR; } status_t HWComposer::prepare() { Mutex::Autolock _l(mDisplayLock); for (size_t i=0 ; icompositionType = HWC_FRAMEBUFFER_TARGET; } if (!disp.connected && disp.list != NULL) { ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu", i, disp.list->numHwLayers); } mLists[i] = disp.list; if (mLists[i]) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { mLists[i]->outbuf = disp.outbufHandle; mLists[i]->outbufAcquireFenceFd = -1; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // garbage data to catch improper use mLists[i]->dpy = (hwc_display_t)0xDEADBEEF; mLists[i]->sur = (hwc_surface_t)0xDEADBEEF; } else { mLists[i]->dpy = EGL_NO_DISPLAY; mLists[i]->sur = EGL_NO_SURFACE; } } } int err = mHwc->prepare(mHwc, mNumDisplays, mLists); ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err)); if (err == NO_ERROR) { // here we're just making sure that "skip" layers are set // to HWC_FRAMEBUFFER and we're also counting how many layers // we have of each type. // // If there are no window layers, we treat the display has having FB // composition, because SurfaceFlinger will use GLES to draw the // wormhole region. for (size_t i=0 ; inumHwLayers ; i++) { hwc_layer_1_t& l = disp.list->hwLayers[i]; //ALOGD("prepare: %d, type=%d, handle=%p", // i, l.compositionType, l.handle); if (l.flags & HWC_SKIP_LAYER) { l.compositionType = HWC_FRAMEBUFFER; } if (l.compositionType == HWC_FRAMEBUFFER) { disp.hasFbComp = true; } if (l.compositionType == HWC_OVERLAY) { disp.hasOvComp = true; } if (l.compositionType == HWC_CURSOR_OVERLAY) { disp.hasOvComp = true; } } if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) { disp.hasFbComp = true; } } else { disp.hasFbComp = true; } } } return (status_t)err; } bool HWComposer::hasHwcComposition(int32_t id) const { if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return false; return mDisplayData[id].hasOvComp; } bool HWComposer::hasGlesComposition(int32_t id) const { if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return true; return mDisplayData[id].hasFbComp; } sp HWComposer::getAndResetReleaseFence(int32_t id) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return Fence::NO_FENCE; int fd = INVALID_OPERATION; if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { const DisplayData& disp(mDisplayData[id]); if (disp.framebufferTarget) { fd = disp.framebufferTarget->releaseFenceFd; disp.framebufferTarget->acquireFenceFd = -1; disp.framebufferTarget->releaseFenceFd = -1; } } return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; } status_t HWComposer::commit() { int err = NO_ERROR; if (mHwc) { if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // On version 1.0, the OpenGL ES target surface is communicated // by the (dpy, sur) fields and we are guaranteed to have only // a single display. mLists[0]->dpy = eglGetCurrentDisplay(); mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); } for (size_t i=VIRTUAL_DISPLAY_ID_BASE; ioutbuf = disp.outbufHandle; mLists[i]->outbufAcquireFenceFd = disp.outbufAcquireFence->dup(); } } err = mHwc->set(mHwc, mNumDisplays, mLists); for (size_t i=0 ; iretireFenceFd != -1) { disp.lastRetireFence = new Fence(disp.list->retireFenceFd); disp.list->retireFenceFd = -1; } disp.list->flags &= ~HWC_GEOMETRY_CHANGED; } } } return (status_t)err; } status_t HWComposer::setPowerMode(int disp, int mode) { LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); if (mHwc) { if (mode == HWC_POWER_MODE_OFF) { eventControl(disp, HWC_EVENT_VSYNC, 0); } if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { return (status_t)mHwc->setPowerMode(mHwc, disp, mode); } else { return (status_t)mHwc->blank(mHwc, disp, mode == HWC_POWER_MODE_OFF ? 1 : 0); } } return NO_ERROR; } status_t HWComposer::setActiveConfig(int disp, int mode) { LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); DisplayData& dd(mDisplayData[disp]); dd.currentConfig = mode; if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { return (status_t)mHwc->setActiveConfig(mHwc, disp, mode); } else { LOG_FATAL_IF(mode != 0); } return NO_ERROR; } void HWComposer::disconnectDisplay(int disp) { LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY); DisplayData& dd(mDisplayData[disp]); free(dd.list); dd.list = NULL; dd.framebufferTarget = NULL; // points into dd.list dd.fbTargetHandle = NULL; dd.outbufHandle = NULL; dd.lastRetireFence = Fence::NO_FENCE; dd.lastDisplayFence = Fence::NO_FENCE; dd.outbufAcquireFence = Fence::NO_FENCE; // clear all the previous configs and repopulate when a new // device is added dd.configs.clear(); } int HWComposer::getVisualID() const { if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED // is supported by the implementation. we can only be in this case // if we have HWC 1.1 return HAL_PIXEL_FORMAT_RGBA_8888; //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } else { return mFbDev->format; } } bool HWComposer::supportsFramebufferTarget() const { return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); } int HWComposer::fbPost(int32_t id, const sp& acquireFence, const sp& buffer) { if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { return setFramebufferTarget(id, acquireFence, buffer); } else { acquireFence->waitForever("HWComposer::fbPost"); return mFbDev->post(mFbDev, buffer->handle); } } int HWComposer::fbCompositionComplete() { if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) return NO_ERROR; if (mFbDev->compositionComplete) { return mFbDev->compositionComplete(mFbDev); } else { return INVALID_OPERATION; } } void HWComposer::fbDump(String8& result) { if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) { const size_t SIZE = 4096; char buffer[SIZE]; mFbDev->dump(mFbDev, buffer, SIZE); result.append(buffer); } } status_t HWComposer::setOutputBuffer(int32_t id, const sp& acquireFence, const sp& buf) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return BAD_INDEX; if (id < VIRTUAL_DISPLAY_ID_BASE) return INVALID_OPERATION; DisplayData& disp(mDisplayData[id]); disp.outbufHandle = buf->handle; disp.outbufAcquireFence = acquireFence; return NO_ERROR; } sp HWComposer::getLastRetireFence(int32_t id) const { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) return Fence::NO_FENCE; return mDisplayData[id].lastRetireFence; } status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos) { if (mHwc->setCursorPositionAsync) { return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top); } else { return NO_ERROR; } } /* * Helper template to implement a concrete HWCLayer * This holds the pointer to the concrete hwc layer type * and implements the "iterable" side of HWCLayer. */ template class Iterable : public HWComposer::HWCLayer { protected: HWCTYPE* const mLayerList; HWCTYPE* mCurrentLayer; Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer), mIndex(0) { } inline HWCTYPE const * getLayer() const { return mCurrentLayer; } inline HWCTYPE* getLayer() { return mCurrentLayer; } virtual ~Iterable() { } size_t mIndex; private: // returns a copy of ourselves virtual HWComposer::HWCLayer* dup() { return new CONCRETE( static_cast(*this) ); } virtual status_t setLayer(size_t index) { mIndex = index; mCurrentLayer = &mLayerList[index]; return NO_ERROR; } }; /* * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0. * This implements the HWCLayer side of HWCIterableLayer. */ class HWCLayerVersion1 : public Iterable { struct hwc_composer_device_1* mHwc; public: HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer, Vector* visibleRegions, Vector* surfaceDamageRegions) : Iterable(layer), mHwc(hwc), mVisibleRegions(visibleRegions), mSurfaceDamageRegions(surfaceDamageRegions) {} virtual int32_t getCompositionType() const { return getLayer()->compositionType; } virtual uint32_t getHints() const { return getLayer()->hints; } virtual sp getAndResetReleaseFence() { int fd = getLayer()->releaseFenceFd; getLayer()->releaseFenceFd = -1; return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; } virtual void setAcquireFenceFd(int fenceFd) { getLayer()->acquireFenceFd = fenceFd; } virtual void setPerFrameDefaultState() { //getLayer()->compositionType = HWC_FRAMEBUFFER; } virtual void setPlaneAlpha(uint8_t alpha) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { getLayer()->planeAlpha = alpha; } else { if (alpha < 0xFF) { getLayer()->flags |= HWC_SKIP_LAYER; } } } virtual void setDefaultState() { hwc_layer_1_t* const l = getLayer(); l->compositionType = HWC_FRAMEBUFFER; l->hints = 0; l->flags = HWC_SKIP_LAYER; l->handle = 0; l->transform = 0; l->blending = HWC_BLENDING_NONE; l->visibleRegionScreen.numRects = 0; l->visibleRegionScreen.rects = NULL; l->acquireFenceFd = -1; l->releaseFenceFd = -1; l->planeAlpha = 0xFF; } virtual void setSkip(bool skip) { if (skip) { getLayer()->flags |= HWC_SKIP_LAYER; } else { getLayer()->flags &= ~HWC_SKIP_LAYER; } } virtual void setIsCursorLayerHint(bool isCursor) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { if (isCursor) { getLayer()->flags |= HWC_IS_CURSOR_LAYER; } else { getLayer()->flags &= ~HWC_IS_CURSOR_LAYER; } } } virtual void setBlending(uint32_t blending) { getLayer()->blending = blending; } virtual void setTransform(uint32_t transform) { getLayer()->transform = transform; } virtual void setFrame(const Rect& frame) { getLayer()->displayFrame = reinterpret_cast(frame); } virtual void setCrop(const FloatRect& crop) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { getLayer()->sourceCropf = reinterpret_cast(crop); } else { /* * Since h/w composer didn't support a flot crop rect before version 1.3, * using integer coordinates instead produces a different output from the GL code in * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to * window size ratio is large and a window crop is defined * (i.e.: if we scale the buffer a lot and we also crop it with a window crop). */ hwc_rect_t& r = getLayer()->sourceCrop; r.left = int(ceilf(crop.left)); r.top = int(ceilf(crop.top)); r.right = int(floorf(crop.right)); r.bottom= int(floorf(crop.bottom)); } } virtual void setVisibleRegionScreen(const Region& reg) { hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen; mVisibleRegions->editItemAt(mIndex) = reg; visibleRegion.rects = reinterpret_cast( mVisibleRegions->itemAt(mIndex).getArray( &visibleRegion.numRects)); } virtual void setSurfaceDamage(const Region& reg) { if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) { return; } hwc_region_t& surfaceDamage = getLayer()->surfaceDamage; // We encode default full-screen damage as INVALID_RECT upstream, but as // 0 rects for HWComposer if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) { surfaceDamage.numRects = 0; surfaceDamage.rects = NULL; return; } mSurfaceDamageRegions->editItemAt(mIndex) = reg; surfaceDamage.rects = reinterpret_cast( mSurfaceDamageRegions->itemAt(mIndex).getArray( &surfaceDamage.numRects)); } virtual void setSidebandStream(const sp& stream) { ALOG_ASSERT(stream->handle() != NULL); getLayer()->compositionType = HWC_SIDEBAND; getLayer()->sidebandStream = stream->handle(); } virtual void setBuffer(const sp& buffer) { if (buffer == 0 || buffer->handle == 0) { getLayer()->compositionType = HWC_FRAMEBUFFER; getLayer()->flags |= HWC_SKIP_LAYER; getLayer()->handle = 0; } else { if (getLayer()->compositionType == HWC_SIDEBAND) { // If this was a sideband layer but the stream was removed, reset // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare. getLayer()->compositionType = HWC_FRAMEBUFFER; } getLayer()->handle = buffer->handle; } } virtual void onDisplayed() { getLayer()->acquireFenceFd = -1; } protected: // Pointers to the vectors of Region backing-memory held in DisplayData. // Only the Region at mIndex corresponds to this Layer. Vector* mVisibleRegions; Vector* mSurfaceDamageRegions; }; /* * returns an iterator initialized at a given index in the layer list */ HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { return LayerListIterator(); } DisplayData& disp(mDisplayData[id]); if (!mHwc || !disp.list || index > disp.list->numHwLayers) { return LayerListIterator(); } if (disp.visibleRegions.size() < disp.list->numHwLayers) { disp.visibleRegions.resize(disp.list->numHwLayers); } if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) { disp.surfaceDamageRegions.resize(disp.list->numHwLayers); } return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers, &disp.visibleRegions, &disp.surfaceDamageRegions), index); } /* * returns an iterator on the beginning of the layer list */ HWComposer::LayerListIterator HWComposer::begin(int32_t id) { return getLayerIterator(id, 0); } /* * returns an iterator on the end of the layer list */ HWComposer::LayerListIterator HWComposer::end(int32_t id) { size_t numLayers = 0; if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) { const DisplayData& disp(mDisplayData[id]); if (mHwc && disp.list) { numLayers = disp.list->numHwLayers; if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET, // which we ignore when iterating through the layer list. ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id); if (numLayers) { numLayers--; } } } } return getLayerIterator(id, numLayers); } // Converts a PixelFormat to a human-readable string. Max 11 chars. // (Could use a table of prefab String8 objects.) static String8 getFormatStr(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888"); case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888"); case PIXEL_FORMAT_RGB_888: return String8("RGB_888"); case PIXEL_FORMAT_RGB_565: return String8("RGB_565"); case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888"); case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return String8("ImplDef"); default: String8 result; result.appendFormat("? %08x", format); return result; } } void HWComposer::dump(String8& result) const { Mutex::Autolock _l(mDisplayLock); if (mHwc) { result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); for (size_t i=0 ; i >& visibleLayersSortedByZ = mFlinger->getLayerSortedByZForHwcDisplay(i); result.appendFormat(" Display[%zd] configurations (* current):\n", i); for (size_t c = 0; c < disp.configs.size(); ++c) { const DisplayConfig& config(disp.configs[c]); result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f" ", refresh=%" PRId64 ", colorTransform=%d\n", c == disp.currentConfig ? "* " : "", c, config.width, config.height, config.xdpi, config.ydpi, config.refresh, config.colorTransform); } if (disp.list) { result.appendFormat( " numHwLayers=%zu, flags=%08x\n", disp.list->numHwLayers, disp.list->flags); result.append( " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n" "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n"); // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___... for (size_t i=0 ; inumHwLayers ; i++) { const hwc_layer_1_t&l = disp.list->hwLayers[i]; int32_t format = -1; String8 name("unknown"); if (i < visibleLayersSortedByZ.size()) { const sp& layer(visibleLayersSortedByZ[i]); const sp& buffer( layer->getActiveBuffer()); if (buffer != NULL) { format = buffer->getPixelFormat(); } name = layer->getName(); } int type = l.compositionType; if (type == HWC_FRAMEBUFFER_TARGET) { name = "HWC_FRAMEBUFFER_TARGET"; format = disp.format; } static char const* compositionTypeName[] = { "GLES", "HWC", "BKGND", "FB TARGET", "SIDEBAND", "HWC_CURSOR", "UNKNOWN"}; if (type >= NELEM(compositionTypeName)) type = NELEM(compositionTypeName) - 1; String8 formatStr = getFormatStr(format); if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { result.appendFormat( " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n", compositionTypeName[type], intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom, l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, name.string()); } else { result.appendFormat( " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n", compositionTypeName[type], intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, name.string()); } } } } } if (mHwc && mHwc->dump) { const size_t SIZE = 4096; char buffer[SIZE]; mHwc->dump(mHwc, buffer, SIZE); result.append(buffer); } } // --------------------------------------------------------------------------- HWComposer::VSyncThread::VSyncThread(HWComposer& hwc) : mHwc(hwc), mEnabled(false), mNextFakeVSync(0), mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY)) { } void HWComposer::VSyncThread::setEnabled(bool enabled) { Mutex::Autolock _l(mLock); if (mEnabled != enabled) { mEnabled = enabled; mCondition.signal(); } } void HWComposer::VSyncThread::onFirstRef() { run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } bool HWComposer::VSyncThread::threadLoop() { { // scope for lock Mutex::Autolock _l(mLock); while (!mEnabled) { mCondition.wait(mLock); } } const nsecs_t period = mRefreshPeriod; const nsecs_t now = systemTime(CLOCK_MONOTONIC); nsecs_t next_vsync = mNextFakeVSync; nsecs_t sleep = next_vsync - now; if (sleep < 0) { // we missed, find where the next vsync should be sleep = (period - ((now - next_vsync) % period)); next_vsync = now + sleep; } mNextFakeVSync = next_vsync + period; struct timespec spec; spec.tv_sec = next_vsync / 1000000000; spec.tv_nsec = next_vsync % 1000000000; int err; do { err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); } while (err<0 && errno == EINTR); if (err == 0) { mHwc.mEventHandler.onVSyncReceived(0, next_vsync); } return true; } HWComposer::DisplayData::DisplayData() : configs(), currentConfig(0), format(HAL_PIXEL_FORMAT_RGBA_8888), connected(false), hasFbComp(false), hasOvComp(false), capacity(0), list(NULL), framebufferTarget(NULL), fbTargetHandle(0), lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE), outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE), events(0) {} HWComposer::DisplayData::~DisplayData() { free(list); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h0100644 0000000 0000000 00000031174 13077405420 022643 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SF_HWCOMPOSER_HWC1_H #define ANDROID_SF_HWCOMPOSER_HWC1_H #include #include #include #include #include #include #include #include #include #include #include extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); struct hwc_composer_device_1; struct hwc_display_contents_1; struct hwc_layer_1; struct hwc_procs; struct framebuffer_device_t; namespace android { // --------------------------------------------------------------------------- class Fence; class FloatRect; class GraphicBuffer; class NativeHandle; class Region; class String8; class SurfaceFlinger; class HWComposer { public: class EventHandler { friend class HWComposer; virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0; virtual void onHotplugReceived(int disp, bool connected) = 0; protected: virtual ~EventHandler() {} }; enum { NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES, MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES, VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL, }; HWComposer( const sp& flinger, EventHandler& handler); ~HWComposer(); status_t initCheck() const; // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to // be used with createWorkList (and all other methods requiring an ID // below). // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are // always valid. // Returns -1 if an ID cannot be allocated int32_t allocateDisplayId(); // Recycles the given virtual display ID and frees the associated worklist. // IDs below NUM_BUILTIN_DISPLAYS are not recycled. status_t freeDisplayId(int32_t id); // Asks the HAL what it can do status_t prepare(); // commits the list status_t commit(); // set power mode status_t setPowerMode(int disp, int mode); // set active config status_t setActiveConfig(int disp, int mode); // reset state when an external, non-virtual display is disconnected void disconnectDisplay(int disp); // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. status_t createWorkList(int32_t id, size_t numLayers); bool supportsFramebufferTarget() const; // does this display have layers handled by HWC bool hasHwcComposition(int32_t id) const; // does this display have layers handled by GLES bool hasGlesComposition(int32_t id) const; // get the releaseFence file descriptor for a display's framebuffer layer. // the release fence is only valid after commit() sp getAndResetReleaseFence(int32_t id); // needed forward declarations class LayerListIterator; // return the visual id to be used to find a suitable EGLConfig for // *ALL* displays. int getVisualID() const; // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface). int fbPost(int32_t id, const sp& acquireFence, const sp& buf); int fbCompositionComplete(); void fbDump(String8& result); // Set the output buffer and acquire fence for a virtual display. // Returns INVALID_OPERATION if id is not a virtual display. status_t setOutputBuffer(int32_t id, const sp& acquireFence, const sp& buf); // Get the retire fence for the last committed frame. This fence will // signal when the h/w composer is completely finished with the frame. // For physical displays, it is no longer being displayed. For virtual // displays, writes to the output buffer are complete. sp getLastRetireFence(int32_t id) const; status_t setCursorPositionAsync(int32_t id, const Rect &pos); /* * Interface to hardware composer's layers functionality. * This abstracts the HAL interface to layers which can evolve in * incompatible ways from one release to another. * The idea is that we could extend this interface as we add * features to h/w composer. */ class HWCLayerInterface { protected: virtual ~HWCLayerInterface() { } public: virtual int32_t getCompositionType() const = 0; virtual uint32_t getHints() const = 0; virtual sp getAndResetReleaseFence() = 0; virtual void setDefaultState() = 0; virtual void setSkip(bool skip) = 0; virtual void setIsCursorLayerHint(bool isCursor = true) = 0; virtual void setBlending(uint32_t blending) = 0; virtual void setTransform(uint32_t transform) = 0; virtual void setFrame(const Rect& frame) = 0; virtual void setCrop(const FloatRect& crop) = 0; virtual void setVisibleRegionScreen(const Region& reg) = 0; virtual void setSurfaceDamage(const Region& reg) = 0; virtual void setSidebandStream(const sp& stream) = 0; virtual void setBuffer(const sp& buffer) = 0; virtual void setAcquireFenceFd(int fenceFd) = 0; virtual void setPlaneAlpha(uint8_t alpha) = 0; virtual void onDisplayed() = 0; }; /* * Interface used to implement an iterator to a list * of HWCLayer. */ class HWCLayer : public HWCLayerInterface { friend class LayerListIterator; // select the layer at the given index virtual status_t setLayer(size_t index) = 0; virtual HWCLayer* dup() = 0; static HWCLayer* copy(HWCLayer *rhs) { return rhs ? rhs->dup() : NULL; } protected: virtual ~HWCLayer() { } }; /* * Iterator through a HWCLayer list. * This behaves more or less like a forward iterator. */ class LayerListIterator { friend class HWComposer; HWCLayer* const mLayerList; size_t mIndex; LayerListIterator() : mLayerList(NULL), mIndex(0) { } LayerListIterator(HWCLayer* layer, size_t index) : mLayerList(layer), mIndex(index) { } // we don't allow assignment, because we don't need it for now LayerListIterator& operator = (const LayerListIterator& rhs); public: // copy operators LayerListIterator(const LayerListIterator& rhs) : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) { } ~LayerListIterator() { delete mLayerList; } // pre-increment LayerListIterator& operator++() { mLayerList->setLayer(++mIndex); return *this; } // dereference HWCLayerInterface& operator * () { return *mLayerList; } HWCLayerInterface* operator -> () { return mLayerList; } // comparison bool operator == (const LayerListIterator& rhs) const { return mIndex == rhs.mIndex; } bool operator != (const LayerListIterator& rhs) const { return !operator==(rhs); } }; // Returns an iterator to the beginning of the layer list LayerListIterator begin(int32_t id); // Returns an iterator to the end of the layer list LayerListIterator end(int32_t id); // Events handling --------------------------------------------------------- enum { EVENT_VSYNC = HWC_EVENT_VSYNC }; void eventControl(int disp, int event, int enabled); struct DisplayConfig { uint32_t width; uint32_t height; float xdpi; float ydpi; nsecs_t refresh; int colorTransform; }; // Query display parameters. Pass in a display index (e.g. // HWC_DISPLAY_PRIMARY). nsecs_t getRefreshTimestamp(int disp) const; sp getDisplayFence(int disp) const; uint32_t getFormat(int disp) const; bool isConnected(int disp) const; // These return the values for the current config of a given display index. // To get the values for all configs, use getConfigs below. uint32_t getWidth(int disp) const; uint32_t getHeight(int disp) const; float getDpiX(int disp) const; float getDpiY(int disp) const; nsecs_t getRefreshPeriod(int disp) const; const Vector& getConfigs(int disp) const; size_t getCurrentConfig(int disp) const; status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h, uint32_t format); // this class is only used to fake the VSync event on systems that don't // have it. class VSyncThread : public Thread { HWComposer& mHwc; mutable Mutex mLock; Condition mCondition; bool mEnabled; mutable nsecs_t mNextFakeVSync; nsecs_t mRefreshPeriod; virtual void onFirstRef(); virtual bool threadLoop(); public: VSyncThread(HWComposer& hwc); void setEnabled(bool enabled); }; friend class VSyncThread; // for debugging ---------------------------------------------------------- void dump(String8& out) const; private: void loadHwcModule(); int loadFbHalModule(); LayerListIterator getLayerIterator(int32_t id, size_t index); struct cb_context; static void hook_invalidate(const struct hwc_procs* procs); static void hook_vsync(const struct hwc_procs* procs, int disp, int64_t timestamp); static void hook_hotplug(const struct hwc_procs* procs, int disp, int connected); inline void invalidate(); inline void vsync(int disp, int64_t timestamp); inline void hotplug(int disp, int connected); status_t queryDisplayProperties(int disp); status_t setFramebufferTarget(int32_t id, const sp& acquireFence, const sp& buf); struct DisplayData { DisplayData(); ~DisplayData(); Vector configs; size_t currentConfig; uint32_t format; // pixel format from FB hal, for pre-hwc-1.1 bool connected; bool hasFbComp; bool hasOvComp; size_t capacity; hwc_display_contents_1* list; hwc_layer_1* framebufferTarget; buffer_handle_t fbTargetHandle; sp lastRetireFence; // signals when the last set op retires sp lastDisplayFence; // signals when the last set op takes // effect on screen buffer_handle_t outbufHandle; sp outbufAcquireFence; // protected by mEventControlLock int32_t events; // We need to hold "copies" of these for memory management purposes. The // actual hwc_layer_1_t holds pointers to the memory within. Vector<> // internally doesn't copy the memory unless one of the copies is // modified. Vector visibleRegions; Vector surfaceDamageRegions; }; sp mFlinger; framebuffer_device_t* mFbDev; struct hwc_composer_device_1* mHwc; // invariant: mLists[0] != NULL iff mHwc != NULL // mLists[i>0] can be NULL. that display is to be ignored struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS]; DisplayData mDisplayData[MAX_HWC_DISPLAYS]; // protect mDisplayData from races between prepare and dump mutable Mutex mDisplayLock; size_t mNumDisplays; cb_context* mCBContext; EventHandler& mEventHandler; size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; sp mVSyncThread; bool mDebugForceFakeVSync; BitSet32 mAllocatedDisplayIDs; // protected by mLock mutable Mutex mLock; mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; // thread-safe mutable Mutex mEventControlLock; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_HWCOMPOSER_H services/surfaceflinger/DisplayHardware/PowerHAL.cpp0100644 0000000 0000000 00000003077 13077405420 021650 0ustar000000000 0000000 /* * Copyright (C) 2012 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 #include #include #include #include #include #include #include "PowerHAL.h" namespace android { // --------------------------------------------------------------------------- status_t PowerHAL::vsyncHint(bool enabled) { Mutex::Autolock _l(mlock); if (mPowerManager == NULL) { const String16 serviceName("power"); sp bs = defaultServiceManager()->checkService(serviceName); if (bs == NULL) { return NAME_NOT_FOUND; } mPowerManager = interface_cast(bs); } status_t status = mPowerManager->powerHint(POWER_HINT_VSYNC, enabled ? 1 : 0); if(status == DEAD_OBJECT) { mPowerManager = NULL; } return status; } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/DisplayHardware/PowerHAL.h0100644 0000000 0000000 00000002246 13077405420 021312 0ustar000000000 0000000 /* * Copyright (C) 2012 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_SF_POWER_HAL_H #define ANDROID_SF_POWER_HAL_H #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class PowerHAL { public: status_t vsyncHint(bool enabled); private: sp mPowerManager; Mutex mlock; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_POWER_HAL_H services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp0100644 0000000 0000000 00000062621 13077405420 024514 0ustar000000000 0000000 /* * Copyright 2013 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. */ // #define LOG_NDEBUG 0 #include "VirtualDisplaySurface.h" #include "HWComposer.h" #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- #if defined(FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS) static const bool sForceHwcCopy = true; #else static const bool sForceHwcCopy = false; #endif #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.string(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ mDisplayName.string(), ##__VA_ARGS__) #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ mDisplayName.string(), ##__VA_ARGS__) static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) { switch (type) { case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN"; case DisplaySurface::COMPOSITION_GLES: return "GLES"; case DisplaySurface::COMPOSITION_HWC: return "HWC"; case DisplaySurface::COMPOSITION_MIXED: return "MIXED"; default: return ""; } } VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const sp& bqProducer, const sp& bqConsumer, const String8& name) : ConsumerBase(bqConsumer), mHwc(hwc), mDisplayId(dispId), mDisplayName(name), mSource{}, mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), mProducerSlotSource(0), mProducerBuffers(), mQueueBufferOutput(), mSinkBufferWidth(0), mSinkBufferHeight(0), mCompositionType(COMPOSITION_UNKNOWN), mFbFence(Fence::NO_FENCE), mOutputFence(Fence::NO_FENCE), mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mDbgState(DBG_STATE_IDLE), mDbgLastCompositionType(COMPOSITION_UNKNOWN), mMustRecompose(false) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; resetPerFrameState(); int sinkWidth, sinkHeight; sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); mSinkBufferWidth = sinkWidth; mSinkBufferHeight = sinkHeight; // Pick the buffer format to request from the sink when not rendering to it // with GLES. If the consumer needs CPU access, use the default format // set by the consumer. Otherwise allow gralloc to decide the format based // on usage bits. int sinkUsage; sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { int sinkFormat; sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); mDefaultOutputFormat = sinkFormat; } else { mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } mOutputFormat = mDefaultOutputFormat; ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); mConsumer->setConsumerName(ConsumerBase::mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); sink->setAsyncMode(true); IGraphicBufferProducer::QueueBufferOutput output; mSource[SOURCE_SCRATCH]->connect(NULL, NATIVE_WINDOW_API_EGL, false, &output); } VirtualDisplaySurface::~VirtualDisplaySurface() { mSource[SOURCE_SCRATCH]->disconnect(NATIVE_WINDOW_API_EGL); } status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { if (mDisplayId < 0) return NO_ERROR; mMustRecompose = mustRecompose; VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, "Unexpected beginFrame() in %s state", dbgStateStr()); mDbgState = DBG_STATE_BEGUN; return refreshOutputBuffer(); } status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { if (mDisplayId < 0) return NO_ERROR; VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, "Unexpected prepareFrame() in %s state", dbgStateStr()); mDbgState = DBG_STATE_PREPARED; mCompositionType = compositionType; if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) { // Some hardware can do RGB->YUV conversion more efficiently in hardware // controlled by HWC than in hardware controlled by the video encoder. // Forcing GLES-composed frames to go through an extra copy by the HWC // allows the format conversion to happen there, rather than passing RGB // directly to the consumer. // // On the other hand, when the consumer prefers RGB or can consume RGB // inexpensively, this forces an unnecessary copy. mCompositionType = COMPOSITION_MIXED; } if (mCompositionType != mDbgLastCompositionType) { VDS_LOGV("prepareFrame: composition type changed to %s", dbgCompositionTypeStr(mCompositionType)); mDbgLastCompositionType = mCompositionType; } if (mCompositionType != COMPOSITION_GLES && (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { // We must have just switched from GLES-only to MIXED or HWC // composition. Stop using the format and usage requested by the GLES // driver; they may be suboptimal when HWC is writing to the output // buffer. For example, if the output is going to a video encoder, and // HWC can write directly to YUV, some hardware can skip a // memory-to-memory RGB-to-YUV conversion step. // // If we just switched *to* GLES-only mode, we'll change the // format/usage and get a new buffer when the GLES driver calls // dequeueBuffer(). mOutputFormat = mDefaultOutputFormat; mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; refreshOutputBuffer(); } return NO_ERROR; } #ifndef USE_HWC2 status_t VirtualDisplaySurface::compositionComplete() { return NO_ERROR; } #endif status_t VirtualDisplaySurface::advanceFrame() { if (mDisplayId < 0) return NO_ERROR; if (mCompositionType == COMPOSITION_HWC) { VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected advanceFrame() in %s state on HWC frame", dbgStateStr()); } else { VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE, "Unexpected advanceFrame() in %s state on GLES/MIXED frame", dbgStateStr()); } mDbgState = DBG_STATE_HWC; if (mOutputProducerSlot < 0 || (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { // Last chance bailout if something bad happened earlier. For example, // in a GLES configuration, if the sink disappears then dequeueBuffer // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. VDS_LOGE("advanceFrame: no buffer, bailing out"); return NO_MEMORY; } sp fbBuffer = mFbProducerSlot >= 0 ? mProducerBuffers[mFbProducerSlot] : sp(NULL); sp outBuffer = mProducerBuffers[mOutputProducerSlot]; VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", mFbProducerSlot, fbBuffer.get(), mOutputProducerSlot, outBuffer.get()); // At this point we know the output buffer acquire fence, // so update HWC state with it. mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer); status_t result = NO_ERROR; if (fbBuffer != NULL) { #ifdef USE_HWC2 // TODO: Correctly propagate the dataspace from GL composition result = mHwc.setClientTarget(mDisplayId, mFbFence, fbBuffer, HAL_DATASPACE_UNKNOWN); #else result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); #endif } return result; } void VirtualDisplaySurface::onFrameCommitted() { if (mDisplayId < 0) return; VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; #ifdef USE_HWC2 sp retireFence = mHwc.getRetireFence(mDisplayId); #else sp fbFence = mHwc.getAndResetReleaseFence(mDisplayId); #endif if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); #ifdef USE_HWC2 addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); #else addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); #endif releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; #ifndef USE_HWC2 sp outFence = mHwc.getLastRetireFence(mDisplayId); #endif VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); if (mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( systemTime(), false /* isAutoTimestamp */, HAL_DATASPACE_UNKNOWN, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, #ifdef USE_HWC2 retireFence), #else outFence), #endif &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); } } else { // If the surface hadn't actually been updated, then we only went // through the motions of updating the display to keep our state // machine happy. We cancel the buffer to avoid triggering another // re-composition and causing an infinite loop. #ifdef USE_HWC2 mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence); #else mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); #endif } } resetPerFrameState(); } void VirtualDisplaySurface::dumpAsString(String8& /* result */) const { } void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) { uint32_t tmpW, tmpH, transformHint, numPendingBuffers; mQueueBufferOutput.deflate(&tmpW, &tmpH, &transformHint, &numPendingBuffers); mQueueBufferOutput.inflate(w, h, transformHint, numPendingBuffers); mSinkBufferWidth = w; mSinkBufferHeight = h; } const sp& VirtualDisplaySurface::getClientTargetAcquireFence() const { return mFbFence; } status_t VirtualDisplaySurface::requestBuffer(int pslot, sp* outBuf) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, "Unexpected requestBuffer pslot=%d in %s state", pslot, dbgStateStr()); *outBuf = mProducerBuffers[pslot]; return NO_ERROR; } status_t VirtualDisplaySurface::setMaxDequeuedBufferCount( int maxDequeuedBuffers) { return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers); } status_t VirtualDisplaySurface::setAsyncMode(bool async) { return mSource[SOURCE_SINK]->setAsyncMode(async); } status_t VirtualDisplaySurface::dequeueBuffer(Source source, PixelFormat format, uint32_t usage, int* sslot, sp* fence) { LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); status_t result = mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight, format, usage); if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d", dbgSourceStr(source), *sslot, pslot, result); uint64_t sourceBit = static_cast(source) << pslot; if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) { // This slot was previously dequeued from the other source; must // re-request the buffer. result |= BUFFER_NEEDS_REALLOCATION; mProducerSlotSource &= ~(1ULL << pslot); mProducerSlotSource |= sourceBit; } if (result & RELEASE_ALL_BUFFERS) { for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { if ((mProducerSlotSource & (1ULL << i)) == sourceBit) mProducerBuffers[i].clear(); } } if (result & BUFFER_NEEDS_REALLOCATION) { result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]); if (result < 0) { mProducerBuffers[pslot].clear(); mSource[source]->cancelBuffer(*sslot, *fence); return result; } VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x", dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), mProducerBuffers[pslot]->getPixelFormat(), mProducerBuffers[pslot]->getUsage()); } return result; } status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage); VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); mDbgState = DBG_STATE_GLES; VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); status_t result = NO_ERROR; Source source = fbSourceForCompositionType(mCompositionType); if (source == SOURCE_SINK) { if (mOutputProducerSlot < 0) { // Last chance bailout if something bad happened earlier. For example, // in a GLES configuration, if the sink disappears then dequeueBuffer // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. VDS_LOGE("dequeueBuffer: no buffer, bailing out"); return NO_MEMORY; } // We already dequeued the output buffer. If the GLES driver wants // something incompatible, we have to cancel and get a new one. This // will mean that HWC will see a different output buffer between // prepare and set, but since we're in GLES-only mode already it // shouldn't matter. usage |= GRALLOC_USAGE_HW_COMPOSER; const sp& buf = mProducerBuffers[mOutputProducerSlot]; if ((usage & ~buf->getUsage()) != 0 || (format != 0 && format != buf->getPixelFormat()) || (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " "want %dx%d fmt=%d use=%#x, " "have %dx%d fmt=%d use=%#x", w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight, buf->getPixelFormat(), buf->getUsage()); mOutputFormat = format; mOutputUsage = usage; result = refreshOutputBuffer(); if (result < 0) return result; } } if (source == SOURCE_SINK) { *pslot = mOutputProducerSlot; *fence = mOutputFence; } else { int sslot; result = dequeueBuffer(source, format, usage, &sslot, fence); if (result >= 0) { *pslot = mapSource2ProducerSlot(source, sslot); } } return result; } status_t VirtualDisplaySurface::detachBuffer(int /* slot */) { VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::detachNextBuffer( sp* /* outBuffer */, sp* /* outFence */) { VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, const sp& /* buffer */) { VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, "Unexpected queueBuffer(pslot=%d) in %s state", pslot, dbgStateStr()); mDbgState = DBG_STATE_GLES_DONE; VDS_LOGV("queueBuffer pslot=%d", pslot); status_t result; if (mCompositionType == COMPOSITION_MIXED) { // Queue the buffer back into the scratch pool QueueBufferOutput scratchQBO; int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO); if (result != NO_ERROR) return result; // Now acquire the buffer from the scratch pool -- should be the same // slot and fence as we just queued. Mutex::Autolock lock(mMutex); BufferItem item; result = acquireBufferLocked(&item, 0); if (result != NO_ERROR) return result; VDS_LOGW_IF(item.mSlot != sslot, "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", item.mSlot, sslot); mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot); mFbFence = mSlots[item.mSlot].mFence; } else { LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES, "Unexpected queueBuffer in state %s for compositionType %s", dbgStateStr(), dbgCompositionTypeStr(mCompositionType)); // Extract the GLES release fence for HWC to acquire int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &mFbFence); mFbProducerSlot = pslot; mOutputFence = mFbFence; } *output = mQueueBufferOutput; return NO_ERROR; } status_t VirtualDisplaySurface::cancelBuffer(int pslot, const sp& fence) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, dbgStateStr()); VDS_LOGV("cancelBuffer pslot=%d", pslot); Source source = fbSourceForCompositionType(mCompositionType); return mSource[source]->cancelBuffer( mapProducer2SourceSlot(source, pslot), fence); } int VirtualDisplaySurface::query(int what, int* value) { switch (what) { case NATIVE_WINDOW_WIDTH: *value = mSinkBufferWidth; break; case NATIVE_WINDOW_HEIGHT: *value = mSinkBufferHeight; break; default: return mSource[SOURCE_SINK]->query(what, value); } return NO_ERROR; } status_t VirtualDisplaySurface::connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) { QueueBufferOutput qbo; status_t result = mSource[SOURCE_SINK]->connect(listener, api, producerControlledByApp, &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); *output = mQueueBufferOutput; } return result; } status_t VirtualDisplaySurface::disconnect(int api) { return mSource[SOURCE_SINK]->disconnect(api); } status_t VirtualDisplaySurface::setSidebandStream(const sp& /*stream*/) { return INVALID_OPERATION; } void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */, uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) { // TODO: Should we actually allocate buffers for a virtual display? } status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { return INVALID_OPERATION; } status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } String8 VirtualDisplaySurface::getConsumerName() const { return String8("VirtualDisplaySurface"); } uint64_t VirtualDisplaySurface::getNextFrameNumber() const { return 0; } status_t VirtualDisplaySurface::setSharedBufferMode(bool /*sharedBufferMode*/) { ALOGE("setSharedBufferMode not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) { ALOGE("setAutoRefresh not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) { ALOGE("setDequeueTimeout not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::getLastQueuedBuffer( sp* /*outBuffer*/, sp* /*outFence*/, float[16] /* outTransformMatrix*/) { ALOGE("getLastQueuedBuffer not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } status_t VirtualDisplaySurface::getUniqueId(uint64_t* /*outId*/) const { ALOGE("getUniqueId not supported on VirtualDisplaySurface"); return INVALID_OPERATION; } void VirtualDisplaySurface::updateQueueBufferOutput( const QueueBufferOutput& qbo) { uint32_t w, h, transformHint, numPendingBuffers; qbo.deflate(&w, &h, &transformHint, &numPendingBuffers); mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers); } void VirtualDisplaySurface::resetPerFrameState() { mCompositionType = COMPOSITION_UNKNOWN; mFbFence = Fence::NO_FENCE; mOutputFence = Fence::NO_FENCE; mOutputProducerSlot = -1; mFbProducerSlot = -1; } status_t VirtualDisplaySurface::refreshOutputBuffer() { if (mOutputProducerSlot >= 0) { mSource[SOURCE_SINK]->cancelBuffer( mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot), mOutputFence); } int sslot; status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage, &sslot, &mOutputFence); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); // On GLES-only frames, we don't have the right output buffer acquire fence // until after GLES calls queueBuffer(). So here we just set the buffer // (for use in HWC prepare) but not the fence; we'll call this again with // the proper fence once we have it. result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE, mProducerBuffers[mOutputProducerSlot]); return result; } // This slot mapping function is its own inverse, so two copies are unnecessary. // Both are kept to make the intent clear where the function is called, and for // the (unlikely) chance that we switch to a different mapping function. int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) { if (source == SOURCE_SCRATCH) { return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1; } else { return sslot; } } int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) { return mapSource2ProducerSlot(source, pslot); } VirtualDisplaySurface::Source VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) { return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK; } const char* VirtualDisplaySurface::dbgStateStr() const { switch (mDbgState) { case DBG_STATE_IDLE: return "IDLE"; case DBG_STATE_PREPARED: return "PREPARED"; case DBG_STATE_GLES: return "GLES"; case DBG_STATE_GLES_DONE: return "GLES_DONE"; case DBG_STATE_HWC: return "HWC"; default: return "INVALID"; } } const char* VirtualDisplaySurface::dbgSourceStr(Source s) { switch (s) { case SOURCE_SINK: return "SINK"; case SOURCE_SCRATCH: return "SCRATCH"; default: return "INVALID"; } } // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h0100644 0000000 0000000 00000026234 13077405420 024161 0ustar000000000 0000000 /* * Copyright 2013 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_SF_VIRTUAL_DISPLAY_SURFACE_H #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H #include #include #include "DisplaySurface.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class HWComposer; class IProducerListener; /* This DisplaySurface implementation supports virtual displays, where GLES * and/or HWC compose into a buffer that is then passed to an arbitrary * consumer (the sink) running in another process. * * The simplest case is when the virtual display will never use the h/w * composer -- either the h/w composer doesn't support writing to buffers, or * there are more virtual displays than it supports simultaneously. In this * case, the GLES driver works directly with the output buffer queue, and * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do * nothing. * * If h/w composer might be used, then each frame will fall into one of three * configurations: GLES-only, HWC-only, and MIXED composition. In all of these, * we must provide a FB target buffer and output buffer for the HWC set() call. * * In GLES-only composition, the GLES driver is given a buffer from the sink to * render into. When the GLES driver queues the buffer to the * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of * immediately queueing it to the sink. The buffer is used as both the FB * target and output buffer for HWC, though on these frames the HWC doesn't * do any work for this display and doesn't write to the output buffer. After * composition is complete, the buffer is queued to the sink. * * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from * the sink and passes it to HWC as both the FB target buffer and output * buffer. The HWC doesn't need to read from the FB target buffer, but does * write to the output buffer. After composition is complete, the buffer is * queued to the sink. * * On MIXED frames, things become more complicated, since some h/w composer * implementations can't read from and write to the same buffer. This class has * an internal BufferQueue that it uses as a scratch buffer pool. The GLES * driver is given a scratch buffer to render into. When it finishes rendering, * the buffer is queued and then immediately acquired by the * VirtualDisplaySurface. The scratch buffer is then used as the FB target * buffer for HWC, and a separate buffer is dequeued from the sink and used as * the HWC output buffer. When HWC composition is complete, the scratch buffer * is released and the output buffer is queued to the sink. */ class VirtualDisplaySurface : public DisplaySurface, public BnGraphicBufferProducer, private ConsumerBase { public: VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const sp& bqProducer, const sp& bqConsumer, const String8& name); // // DisplaySurface interface // virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); #ifndef USE_HWC2 virtual status_t compositionComplete(); #endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const uint32_t w, const uint32_t h); virtual const sp& getClientTargetAcquireFence() const override; private: enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; virtual ~VirtualDisplaySurface(); // // IGraphicBufferProducer interface, used by the GLES driver. // virtual status_t requestBuffer(int pslot, sp* outBuf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* pslot, sp* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence); virtual status_t attachBuffer(int* slot, const sp& buffer); virtual status_t queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output); virtual status_t cancelBuffer(int pslot, const sp& fence); virtual int query(int what, int* value); virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp& stream); virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; virtual uint64_t getNextFrameNumber() const override; virtual status_t setSharedBufferMode(bool sharedBufferMode) override; virtual status_t setAutoRefresh(bool autoRefresh) override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override; virtual status_t getUniqueId(uint64_t* outId) const override; // // Utility methods // static Source fbSourceForCompositionType(CompositionType type); status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage, int* sslot, sp* fence); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); status_t refreshOutputBuffer(); // Both the sink and scratch buffer pools have their own set of slots // ("source slots", or "sslot"). We have to merge these into the single // set of slots used by the GLES producer ("producer slots" or "pslot") and // internally in the VirtualDisplaySurface. To minimize the number of times // a producer slot switches which source it comes from, we map source slot // numbers to producer slot numbers differently for each source. static int mapSource2ProducerSlot(Source source, int sslot); static int mapProducer2SourceSlot(Source source, int pslot); // // Immutable after construction // HWComposer& mHwc; const int32_t mDisplayId; const String8 mDisplayName; sp mSource[2]; // indexed by SOURCE_* uint32_t mDefaultOutputFormat; // // Inter-frame state // // To avoid buffer reallocations, we track the buffer usage and format // we used on the previous frame and use it again on the new frame. If // the composition type changes or the GLES driver starts requesting // different usage/format, we'll get a new buffer. uint32_t mOutputFormat; uint32_t mOutputUsage; // Since we present a single producer interface to the GLES driver, but // are internally muxing between the sink and scratch producers, we have // to keep track of which source last returned each producer slot from // dequeueBuffer. Each bit in mProducerSlotSource corresponds to a producer // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a // "producer slot"; see the mapSlot*() functions. uint64_t mProducerSlotSource; sp mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS]; // The QueueBufferOutput with the latest info from the sink, and with the // transform hint cleared. Since we defer queueBuffer from the GLES driver // to the sink, we have to return the previous version. QueueBufferOutput mQueueBufferOutput; // Details of the current sink buffer. These become valid when a buffer is // dequeued from the sink, and are used when queueing the buffer. uint32_t mSinkBufferWidth, mSinkBufferHeight; // // Intra-frame state // // Composition type and GLES buffer source for the current frame. // Valid after prepareFrame(), cleared in onFrameCommitted. CompositionType mCompositionType; // mFbFence is the fence HWC should wait for before reading the framebuffer // target buffer. sp mFbFence; // mOutputFence is the fence HWC should wait for before writing to the // output buffer. sp mOutputFence; // Producer slot numbers for the buffers to use for HWC framebuffer target // and output. int mFbProducerSlot; int mOutputProducerSlot; // Debug only -- track the sequence of events in each frame so we can make // sure they happen in the order we expect. This class implicitly models // a state machine; this enum/variable makes it explicit. // // +-----------+-------------------+-------------+ // | State | Event || Next State | // +-----------+-------------------+-------------+ // | IDLE | beginFrame || BEGUN | // | BEGUN | prepareFrame || PREPARED | // | PREPARED | dequeueBuffer [1] || GLES | // | PREPARED | advanceFrame [2] || HWC | // | GLES | queueBuffer || GLES_DONE | // | GLES_DONE | advanceFrame || HWC | // | HWC | onFrameCommitted || IDLE | // +-----------+-------------------++------------+ // [1] COMPOSITION_GLES and COMPOSITION_MIXED frames. // [2] COMPOSITION_HWC frames. // enum DbgState { // no buffer dequeued, don't know anything about the next frame DBG_STATE_IDLE, // output buffer dequeued, framebuffer source not yet known DBG_STATE_BEGUN, // output buffer dequeued, framebuffer source known but not provided // to GLES yet. DBG_STATE_PREPARED, // GLES driver has a buffer dequeued DBG_STATE_GLES, // GLES driver has queued the buffer, we haven't sent it to HWC yet DBG_STATE_GLES_DONE, // HWC has the buffer for this frame DBG_STATE_HWC, }; DbgState mDbgState; CompositionType mDbgLastCompositionType; const char* dbgStateStr() const; static const char* dbgSourceStr(Source s); bool mMustRecompose; }; // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H services/surfaceflinger/Effects/0040755 0000000 0000000 00000000000 13077405420 016013 5ustar000000000 0000000 services/surfaceflinger/Effects/Daltonizer.cpp0100644 0000000 0000000 00000014020 13077405420 020624 0ustar000000000 0000000 /* * Copyright 2013 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 "Daltonizer.h" #include namespace android { Daltonizer::Daltonizer() : mType(deuteranomaly), mMode(simulation), mDirty(true) { } Daltonizer::~Daltonizer() { } void Daltonizer::setType(Daltonizer::ColorBlindnessTypes type) { if (type != mType) { mDirty = true; mType = type; } } void Daltonizer::setMode(Daltonizer::Mode mode) { if (mode != mMode) { mDirty = true; mMode = mode; } } const mat4& Daltonizer::operator()() { if (mDirty) { mDirty = false; update(); } return mColorTransform; } void Daltonizer::update() { // converts a linear RGB color to the XYZ space const mat4 rgb2xyz( 0.4124, 0.2126, 0.0193, 0, 0.3576, 0.7152, 0.1192, 0, 0.1805, 0.0722, 0.9505, 0, 0 , 0 , 0 , 1); // converts a XYZ color to the LMS space. const mat4 xyz2lms( 0.7328,-0.7036, 0.0030, 0, 0.4296, 1.6975, 0.0136, 0, -0.1624, 0.0061, 0.9834, 0, 0 , 0 , 0 , 1); // Direct conversion from linear RGB to LMS const mat4 rgb2lms(xyz2lms*rgb2xyz); // And back from LMS to linear RGB const mat4 lms2rgb(inverse(rgb2lms)); // To simulate color blindness we need to "remove" the data lost by the absence of // a cone. This cannot be done by just zeroing out the corresponding LMS component // because it would create a color outside of the RGB gammut. // Instead we project the color along the axis of the missing component onto a plane // within the RGB gammut: // - since the projection happens along the axis of the missing component, a // color blind viewer perceives the projected color the same. // - We use the plane defined by 3 points in LMS space: black, white and // blue and red for protanopia/deuteranopia and tritanopia respectively. // LMS space red const vec3& lms_r(rgb2lms[0].rgb); // LMS space blue const vec3& lms_b(rgb2lms[2].rgb); // LMS space white const vec3 lms_w((rgb2lms * vec4(1)).rgb); // To find the planes we solve the a*L + b*M + c*S = 0 equation for the LMS values // of the three known points. This equation is trivially solved, and has for // solution the following cross-products: const vec3 p0 = cross(lms_w, lms_b); // protanopia/deuteranopia const vec3 p1 = cross(lms_w, lms_r); // tritanopia // The following 3 matrices perform the projection of a LMS color onto the given plane // along the selected axis // projection for protanopia (L = 0) const mat4 lms2lmsp( 0.0000, 0.0000, 0.0000, 0, -p0.y / p0.x, 1.0000, 0.0000, 0, -p0.z / p0.x, 0.0000, 1.0000, 0, 0 , 0 , 0 , 1); // projection for deuteranopia (M = 0) const mat4 lms2lmsd( 1.0000, -p0.x / p0.y, 0.0000, 0, 0.0000, 0.0000, 0.0000, 0, 0.0000, -p0.z / p0.y, 1.0000, 0, 0 , 0 , 0 , 1); // projection for tritanopia (S = 0) const mat4 lms2lmst( 1.0000, 0.0000, -p1.x / p1.z, 0, 0.0000, 1.0000, -p1.y / p1.z, 0, 0.0000, 0.0000, 0.0000, 0, 0 , 0 , 0 , 1); // We will calculate the error between the color and the color viewed by // a color blind user and "spread" this error onto the healthy cones. // The matrices below perform this last step and have been chosen arbitrarily. // The amount of correction can be adjusted here. // error spread for protanopia const mat4 errp( 1.0, 0.7, 0.7, 0, 0.0, 1.0, 0.0, 0, 0.0, 0.0, 1.0, 0, 0, 0, 0, 1); // error spread for deuteranopia const mat4 errd( 1.0, 0.0, 0.0, 0, 0.7, 1.0, 0.7, 0, 0.0, 0.0, 1.0, 0, 0, 0, 0, 1); // error spread for tritanopia const mat4 errt( 1.0, 0.0, 0.0, 0, 0.0, 1.0, 0.0, 0, 0.7, 0.7, 1.0, 0, 0, 0, 0, 1); const mat4 identity; // And the magic happens here... // We construct the matrix that will perform the whole correction. // simulation: type of color blindness to simulate: // set to either lms2lmsp, lms2lmsd, lms2lmst mat4 simulation; // correction: type of color blindness correction (should match the simulation above): // set to identity, errp, errd, errt ([0] for simulation only) mat4 correction(0); switch (mType) { case protanopia: case protanomaly: simulation = lms2lmsp; if (mMode == Daltonizer::correction) correction = errp; break; case deuteranopia: case deuteranomaly: simulation = lms2lmsd; if (mMode == Daltonizer::correction) correction = errd; break; case tritanopia: case tritanomaly: simulation = lms2lmst; if (mMode == Daltonizer::correction) correction = errt; break; } mColorTransform = lms2rgb * (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms)); } } /* namespace android */ services/surfaceflinger/Effects/Daltonizer.h0100644 0000000 0000000 00000003056 13077405420 020300 0ustar000000000 0000000 /* * Copyright 2013 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 SF_EFFECTS_DALTONIZER_H_ #define SF_EFFECTS_DALTONIZER_H_ #include namespace android { class Daltonizer { public: enum ColorBlindnessTypes { protanopia, // L (red) cone missing deuteranopia, // M (green) cone missing tritanopia, // S (blue) cone missing protanomaly, // L (red) cone deficient deuteranomaly, // M (green) cone deficient (most common) tritanomaly // S (blue) cone deficient }; enum Mode { simulation, correction }; Daltonizer(); ~Daltonizer(); void setType(ColorBlindnessTypes type); void setMode(Mode mode); // returns the color transform to apply in the shader const mat4& operator()(); private: void update(); ColorBlindnessTypes mType; Mode mMode; bool mDirty; mat4 mColorTransform; }; } /* namespace android */ #endif /* SF_EFFECTS_DALTONIZER_H_ */ services/surfaceflinger/EventControlThread.cpp0100644 0000000 0000000 00000003553 13077405420 020715 0ustar000000000 0000000 /* * Copyright (C) 2013 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 "EventControlThread.h" #include "SurfaceFlinger.h" namespace android { EventControlThread::EventControlThread(const sp& flinger): mFlinger(flinger), mVsyncEnabled(false) { } void EventControlThread::setVsyncEnabled(bool enabled) { Mutex::Autolock lock(mMutex); mVsyncEnabled = enabled; mCond.signal(); } bool EventControlThread::threadLoop() { Mutex::Autolock lock(mMutex); bool vsyncEnabled = mVsyncEnabled; #ifdef USE_HWC2 mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); #else mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); #endif while (true) { status_t err = mCond.wait(mMutex); if (err != NO_ERROR) { ALOGE("error waiting for new events: %s (%d)", strerror(-err), err); return false; } if (vsyncEnabled != mVsyncEnabled) { #ifdef USE_HWC2 mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); #else mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); #endif vsyncEnabled = mVsyncEnabled; } } return false; } } // namespace android services/surfaceflinger/EventControlThread.h0100644 0000000 0000000 00000002227 13077405420 020357 0ustar000000000 0000000 /* * Copyright (C) 2013 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_EVENTCONTROLTHREAD_H #define ANDROID_EVENTCONTROLTHREAD_H #include #include #include namespace android { class SurfaceFlinger; class EventControlThread: public Thread { public: EventControlThread(const sp& flinger); virtual ~EventControlThread() {} void setVsyncEnabled(bool enabled); virtual bool threadLoop(); private: sp mFlinger; bool mVsyncEnabled; Mutex mMutex; Condition mCond; }; } #endif // ANDROID_DISPSYNC_H services/surfaceflinger/EventLog/0040755 0000000 0000000 00000000000 13077405420 016157 5ustar000000000 0000000 services/surfaceflinger/EventLog/EventLog.cpp0100644 0000000 0000000 00000007547 13077405420 020420 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include #include "EventLog.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(EventLog) EventLog::EventLog() { } void EventLog::doLogFrameDurations(const String8& window, const int32_t* durations, size_t numDurations) { EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR); buffer.startList(1 + numDurations); buffer.writeString8(window); for (size_t i = 0; i < numDurations; i++) { buffer.writeInt32(durations[i]); } buffer.endList(); buffer.log(); } void EventLog::logFrameDurations(const String8& window, const int32_t* durations, size_t numDurations) { EventLog::getInstance().doLogFrameDurations(window, durations, numDurations); } // --------------------------------------------------------------------------- EventLog::TagBuffer::TagBuffer(int32_t tag) : mPos(0), mTag(tag), mOverflow(false) { } void EventLog::TagBuffer::log() { if (mOverflow) { ALOGW("couldn't log to binary event log: overflow."); } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) { ALOGE("couldn't log to EventLog: %s", strerror(errno)); } // purge the buffer mPos = 0; mOverflow = false; } void EventLog::TagBuffer::startList(int8_t count) { if (mOverflow) return; const size_t needed = 1 + sizeof(count); if (mPos + needed > STORAGE_MAX_SIZE) { mOverflow = true; return; } mStorage[mPos + 0] = EVENT_TYPE_LIST; mStorage[mPos + 1] = count; mPos += needed; } void EventLog::TagBuffer::endList() { if (mOverflow) return; const size_t needed = 1; if (mPos + needed > STORAGE_MAX_SIZE) { mOverflow = true; return; } mStorage[mPos + 0] = '\n'; mPos += needed; } void EventLog::TagBuffer::writeInt32(int32_t value) { if (mOverflow) return; const size_t needed = 1 + sizeof(value); if (mPos + needed > STORAGE_MAX_SIZE) { mOverflow = true; return; } mStorage[mPos + 0] = EVENT_TYPE_INT; memcpy(&mStorage[mPos + 1], &value, sizeof(value)); mPos += needed; } void EventLog::TagBuffer::writeInt64(int64_t value) { if (mOverflow) return; const size_t needed = 1 + sizeof(value); if (mPos + needed > STORAGE_MAX_SIZE) { mOverflow = true; return; } mStorage[mPos + 0] = EVENT_TYPE_LONG; memcpy(&mStorage[mPos + 1], &value, sizeof(value)); mPos += needed; } void EventLog::TagBuffer::writeString8(const String8& value) { if (mOverflow) return; const int32_t stringLen = value.length(); const size_t needed = 1 + sizeof(int32_t) + stringLen; if (mPos + needed > STORAGE_MAX_SIZE) { mOverflow = true; return; } mStorage[mPos + 0] = EVENT_TYPE_STRING; memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t)); memcpy(&mStorage[mPos + 5], value.string(), stringLen); mPos += needed; } // --------------------------------------------------------------------------- }// namespace android // --------------------------------------------------------------------------- services/surfaceflinger/EventLog/EventLog.h0100644 0000000 0000000 00000005061 13077405420 020052 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #ifndef ANDROID_SF_EVENTLOG_H #define ANDROID_SF_EVENTLOG_H // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class String8; class EventLog : public Singleton { public: static void logFrameDurations(const String8& window, const int32_t* durations, size_t numDurations); protected: EventLog(); private: /* * EventLogBuffer is a helper class to construct an in-memory event log * tag. In this version the buffer is not dynamic, so write operation can * fail if there is not enough space in the temporary buffer. * Once constructed, the buffer can be logger by calling the log() * method. */ class TagBuffer { enum { STORAGE_MAX_SIZE = 128 }; int32_t mPos; int32_t mTag; bool mOverflow; char mStorage[STORAGE_MAX_SIZE]; public: TagBuffer(int32_t tag); // starts list of items void startList(int8_t count); // terminates the list void endList(); // write a 32-bit integer void writeInt32(int32_t value); // write a 64-bit integer void writeInt64(int64_t value); // write a C string void writeString8(const String8& value); // outputs the the buffer to the log void log(); }; friend class Singleton; EventLog(const EventLog&); EventLog& operator =(const EventLog&); enum { LOGTAG_SF_FRAME_DUR = 60100 }; void doLogFrameDurations(const String8& window, const int32_t* durations, size_t numDurations); }; // --------------------------------------------------------------------------- }// namespace android // --------------------------------------------------------------------------- #endif /* ANDROID_SF_EVENTLOG_H */ services/surfaceflinger/EventLog/EventLogTags.logtags0100644 0000000 0000000 00000002772 13077405420 022110 0ustar000000000 0000000 # The entries in this file map a sparse set of log tag numbers to tag names. # This is installed on the device, in /system/etc, and parsed by logcat. # # Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the # negative values alone for now.) # # Tag names are one or more ASCII letters and numbers or underscores, i.e. # "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former # impacts log readability, the latter makes regex searches more annoying). # # Tag numbers and names are separated by whitespace. Blank lines and lines # starting with '#' are ignored. # # Optionally, after the tag names can be put a description for the value(s) # of the tag. Description are in the format # (|data type[|data unit]) # Multiple values are separated by commas. # # The data type is a number from the following values: # 1: int # 2: long # 3: string # 4: list # # The data unit is a number taken from the following list: # 1: Number of objects # 2: Number of bytes # 3: Number of milliseconds # 4: Number of allocations # 5: Id # 6: Percent # Default value for data of type int/long is 2 (bytes). # # See system/core/logcat/event.logtags for the master copy of the tags. # 60100 - 60199 reserved for surfaceflinger 60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1) 60110 sf_stop_bootanim (time|2|3) # NOTE - the range 1000000-2000000 is reserved for partners and others who # want to define their own log tags without conflicting with the core platform. services/surfaceflinger/EventThread.cpp0100644 0000000 0000000 00000036210 13077405420 017350 0ustar000000000 0000000 /* * 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include "EventThread.h" #include "SurfaceFlinger.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- // time to wait between VSYNC requests before sending a VSYNC OFF power hint: 40msec. const long vsyncHintOffDelay = 40000000; static void vsyncOffCallback(union sigval val) { EventThread *ev = (EventThread *)val.sival_ptr; ev->sendVsyncHintOff(); return; } EventThread::EventThread(const sp& src, SurfaceFlinger& flinger) : mVSyncSource(src), mFlinger(flinger), mUseSoftwareVSync(false), mVsyncEnabled(false), mDebugVsyncEnabled(false), mVsyncHintSent(false) { for (int32_t i=0 ; isetPhaseOffset(phaseOffset); } void EventThread::sendVsyncHintOnLocked() { struct itimerspec ts; if(!mVsyncHintSent) { mPowerHAL.vsyncHint(true); mVsyncHintSent = true; } ts.it_value.tv_sec = 0; ts.it_value.tv_nsec = vsyncHintOffDelay; ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 0; timer_settime(mTimerId, 0, &ts, NULL); } void EventThread::onFirstRef() { run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } sp EventThread::createEventConnection() const { return new Connection(const_cast(this)); } status_t EventThread::registerDisplayEventConnection( const sp& connection) { Mutex::Autolock _l(mLock); mDisplayEventConnections.add(connection); mCondition.broadcast(); return NO_ERROR; } void EventThread::removeDisplayEventConnection( const wp& connection) { Mutex::Autolock _l(mLock); mDisplayEventConnections.remove(connection); } void EventThread::setVsyncRate(uint32_t count, const sp& connection) { if (int32_t(count) >= 0) { // server must protect against bad params Mutex::Autolock _l(mLock); const int32_t new_count = (count == 0) ? -1 : count; if (connection->count != new_count) { connection->count = new_count; mCondition.broadcast(); } } } void EventThread::requestNextVsync( const sp& connection) { Mutex::Autolock _l(mLock); mFlinger.resyncWithRateLimit(); if (connection->count < 0) { connection->count = 0; mCondition.broadcast(); } } void EventThread::onScreenReleased() { Mutex::Autolock _l(mLock); if (!mUseSoftwareVSync) { // disable reliance on h/w vsync mUseSoftwareVSync = true; mCondition.broadcast(); } } void EventThread::onScreenAcquired() { Mutex::Autolock _l(mLock); if (mUseSoftwareVSync) { // resume use of h/w vsync mUseSoftwareVSync = false; mCondition.broadcast(); } } void EventThread::onVSyncEvent(nsecs_t timestamp) { Mutex::Autolock _l(mLock); mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; mVSyncEvent[0].header.id = 0; mVSyncEvent[0].header.timestamp = timestamp; mVSyncEvent[0].vsync.count++; mCondition.broadcast(); } void EventThread::onHotplugReceived(int type, bool connected) { ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES, "received hotplug event for an invalid display (id=%d)", type); Mutex::Autolock _l(mLock); if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { DisplayEventReceiver::Event event; event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG; event.header.id = type; event.header.timestamp = systemTime(); event.hotplug.connected = connected; mPendingEvents.add(event); mCondition.broadcast(); } } bool EventThread::threadLoop() { DisplayEventReceiver::Event event; Vector< sp > signalConnections; signalConnections = waitForEvent(&event); // dispatch events to listeners... const size_t count = signalConnections.size(); for (size_t i=0 ; i& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); if (err == -EAGAIN || err == -EWOULDBLOCK) { // The destination doesn't accept events anymore, it's probably // full. For now, we just drop the events on the floor. // FIXME: Note that some events cannot be dropped and would have // to be re-sent later. // Right-now we don't have the ability to do this. ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type, conn.get()); } else if (err < 0) { // handle any other error on the pipe as fatal. the only // reasonable thing to do is to clean-up this connection. // The most common error we'll get here is -EPIPE. removeDisplayEventConnection(signalConnections[i]); } } return true; } // This will return when (1) a vsync event has been received, and (2) there was // at least one connection interested in receiving it when we started waiting. Vector< sp > EventThread::waitForEvent( DisplayEventReceiver::Event* event) { Mutex::Autolock _l(mLock); Vector< sp > signalConnections; do { bool eventPending = false; bool waitForVSync = false; size_t vsyncCount = 0; nsecs_t timestamp = 0; for (int32_t i=0 ; i connection(mDisplayEventConnections[i].promote()); if (connection != NULL) { bool added = false; if (connection->count >= 0) { // we need vsync events because at least // one connection is waiting for it waitForVSync = true; if (timestamp) { // we consume the event only if it's time // (ie: we received a vsync event) if (connection->count == 0) { // fired this time around connection->count = -1; signalConnections.add(connection); added = true; } else if (connection->count == 1 || (vsyncCount % connection->count) == 0) { // continuous event, and time to report it signalConnections.add(connection); added = true; } } } if (eventPending && !timestamp && !added) { // we don't have a vsync event to process // (timestamp==0), but we have some pending // messages. signalConnections.add(connection); } } else { // we couldn't promote this reference, the connection has // died, so clean-up! mDisplayEventConnections.removeAt(i); --i; --count; } } // Here we figure out if we need to enable or disable vsyncs if (timestamp && !waitForVSync) { // we received a VSYNC but we have no clients // don't report it, and disable VSYNC events disableVSyncLocked(); } else if (!timestamp && waitForVSync) { // we have at least one client, so we want vsync enabled // (TODO: this function is called right after we finish // notifying clients of a vsync, so this call will be made // at the vsync rate, e.g. 60fps. If we can accurately // track the current state we could avoid making this call // so often.) enableVSyncLocked(); } // note: !timestamp implies signalConnections.isEmpty(), because we // don't populate signalConnections if there's no vsync pending if (!timestamp && !eventPending) { // wait for something to happen if (waitForVSync) { // This is where we spend most of our time, waiting // for vsync events and new client registrations. // // If the screen is off, we can't use h/w vsync, so we // use a 16ms timeout instead. It doesn't need to be // precise, we just need to keep feeding our clients. // // We don't want to stall if there's a driver bug, so we // use a (long) timeout when waiting for h/w vsync, and // generate fake events when necessary. bool softwareSync = mUseSoftwareVSync; nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000); if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) { if (!softwareSync) { ALOGW("Timed out waiting for hw vsync; faking it"); } // FIXME: how do we decide which display id the fake // vsync came from ? mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY; mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); mVSyncEvent[0].vsync.count++; } } else { // Nobody is interested in vsync, so we just want to sleep. // h/w vsync should be disabled, so this will wait until we // get a new connection, or an existing connection becomes // interested in receiving vsync again. mCondition.wait(mLock); } } } while (signalConnections.isEmpty()); // here we're guaranteed to have a timestamp and some connections to signal // (The connections might have dropped out of mDisplayEventConnections // while we were asleep, but we'll still have strong references to them.) return signalConnections; } void EventThread::enableVSyncLocked() { if (!mUseSoftwareVSync) { // never enable h/w VSYNC when screen is off if (!mVsyncEnabled) { mVsyncEnabled = true; mVSyncSource->setCallback(static_cast(this)); mVSyncSource->setVSyncEnabled(true); } } mDebugVsyncEnabled = true; sendVsyncHintOnLocked(); } void EventThread::disableVSyncLocked() { if (mVsyncEnabled) { mVsyncEnabled = false; mVSyncSource->setVSyncEnabled(false); mDebugVsyncEnabled = false; } } void EventThread::dump(String8& result) const { Mutex::Autolock _l(mLock); result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled?"enabled":"disabled"); result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync?"enabled":"disabled"); result.appendFormat(" numListeners=%zu,\n events-delivered: %u\n", mDisplayEventConnections.size(), mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count); for (size_t i=0 ; i connection = mDisplayEventConnections.itemAt(i).promote(); result.appendFormat(" %p: count=%d\n", connection.get(), connection!=NULL ? connection->count : 0); } } // --------------------------------------------------------------------------- EventThread::Connection::Connection( const sp& eventThread) : count(-1), mEventThread(eventThread), mChannel(new BitTube()) { } EventThread::Connection::~Connection() { // do nothing here -- clean-up will happen automatically // when the main thread wakes up } void EventThread::Connection::onFirstRef() { // NOTE: mEventThread doesn't hold a strong reference on us mEventThread->registerDisplayEventConnection(this); } sp EventThread::Connection::getDataChannel() const { return mChannel; } void EventThread::Connection::setVsyncRate(uint32_t count) { mEventThread->setVsyncRate(count, this); } void EventThread::Connection::requestNextVsync() { mEventThread->requestNextVsync(this); } status_t EventThread::Connection::postEvent( const DisplayEventReceiver::Event& event) { ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1); return size < 0 ? status_t(size) : status_t(NO_ERROR); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/EventThread.h0100644 0000000 0000000 00000010552 13077405420 017016 0ustar000000000 0000000 /* * 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_SURFACE_FLINGER_EVENT_THREAD_H #define ANDROID_SURFACE_FLINGER_EVENT_THREAD_H #include #include #include #include #include #include #include #include "DisplayDevice.h" #include "DisplayHardware/PowerHAL.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class SurfaceFlinger; class String8; // --------------------------------------------------------------------------- class VSyncSource : public virtual RefBase { public: class Callback: public virtual RefBase { public: virtual ~Callback() {} virtual void onVSyncEvent(nsecs_t when) = 0; }; virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp& callback) = 0; virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; }; class EventThread : public Thread, private VSyncSource::Callback { class Connection : public BnDisplayEventConnection { public: Connection(const sp& eventThread); status_t postEvent(const DisplayEventReceiver::Event& event); // count >= 1 : continuous event. count is the vsync rate // count == 0 : one-shot event that has not fired // count ==-1 : one-shot event that fired this round / disabled int32_t count; private: virtual ~Connection(); virtual void onFirstRef(); virtual sp getDataChannel() const; virtual void setVsyncRate(uint32_t count); virtual void requestNextVsync(); // asynchronous sp const mEventThread; sp const mChannel; }; public: EventThread(const sp& src, SurfaceFlinger& flinger); sp createEventConnection() const; status_t registerDisplayEventConnection(const sp& connection); void setVsyncRate(uint32_t count, const sp& connection); void requestNextVsync(const sp& connection); // called before the screen is turned off from main thread void onScreenReleased(); // called after the screen is turned on from main thread void onScreenAcquired(); // called when receiving a hotplug event void onHotplugReceived(int type, bool connected); Vector< sp > waitForEvent( DisplayEventReceiver::Event* event); void dump(String8& result) const; void sendVsyncHintOff(); void setPhaseOffset(nsecs_t phaseOffset); private: virtual bool threadLoop(); virtual void onFirstRef(); virtual void onVSyncEvent(nsecs_t timestamp); void removeDisplayEventConnection(const wp& connection); void enableVSyncLocked(); void disableVSyncLocked(); void sendVsyncHintOnLocked(); // constants sp mVSyncSource; PowerHAL mPowerHAL; SurfaceFlinger& mFlinger; mutable Mutex mLock; mutable Condition mCondition; // protected by mLock SortedVector< wp > mDisplayEventConnections; Vector< DisplayEventReceiver::Event > mPendingEvents; DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; bool mUseSoftwareVSync; bool mVsyncEnabled; // for debugging bool mDebugVsyncEnabled; bool mVsyncHintSent; timer_t mTimerId; }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif /* ANDROID_SURFACE_FLINGER_EVENT_THREAD_H */ services/surfaceflinger/FenceTracker.cpp0100644 0000000 0000000 00000015745 13077405420 017505 0ustar000000000 0000000 /* * Copyright 2016 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include "FenceTracker.h" #include "Layer.h" #include namespace android { FenceTracker::FenceTracker() : mFrameCounter(0), mOffset(0), mFrames() {} void FenceTracker::dump(String8* outString) { Mutex::Autolock lock(mMutex); checkFencesForCompletion(); for (size_t i = 0; i < MAX_FRAME_HISTORY; i++) { int index = (mOffset + i) % MAX_FRAME_HISTORY; const FrameRecord& frame = mFrames[index]; outString->appendFormat("Frame %" PRIu64 "\n", frame.frameId); outString->appendFormat("- Refresh start\t%" PRId64 "\n", frame.refreshStartTime); if (frame.glesCompositionDoneTime) { outString->appendFormat("- GLES done\t%" PRId64 "\n", frame.glesCompositionDoneTime); } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) { outString->append("- GLES done\tNot signaled\n"); } if (frame.retireTime) { outString->appendFormat("- Retire\t%" PRId64 "\n", frame.retireTime); } else { outString->append("- Retire\tNot signaled\n"); } for (const auto& kv : frame.layers) { const LayerRecord& layer = kv.second; outString->appendFormat("-- %s\n", layer.name.string()); outString->appendFormat("---- Frame # %" PRIu64 " (%s)\n", layer.frameNumber, layer.isGlesComposition ? "GLES" : "HWC"); outString->appendFormat("---- Posted\t%" PRId64 "\n", layer.postedTime); if (layer.acquireTime) { outString->appendFormat("---- Acquire\t%" PRId64 "\n", layer.acquireTime); } else { outString->append("---- Acquire\tNot signaled\n"); } if (layer.releaseTime) { outString->appendFormat("---- Release\t%" PRId64 "\n", layer.releaseTime); } else { outString->append("---- Release\tNot signaled\n"); } } } } static inline bool isValidTimestamp(nsecs_t time) { return time > 0 && time < INT64_MAX; } void FenceTracker::checkFencesForCompletion() { ATRACE_CALL(); for (auto& frame : mFrames) { if (frame.retireFence != Fence::NO_FENCE) { nsecs_t time = frame.retireFence->getSignalTime(); if (isValidTimestamp(time)) { frame.retireTime = time; frame.retireFence = Fence::NO_FENCE; } } if (frame.glesCompositionDoneFence != Fence::NO_FENCE) { nsecs_t time = frame.glesCompositionDoneFence->getSignalTime(); if (isValidTimestamp(time)) { frame.glesCompositionDoneTime = time; frame.glesCompositionDoneFence = Fence::NO_FENCE; } } for (auto& kv : frame.layers) { LayerRecord& layer = kv.second; if (layer.acquireFence != Fence::NO_FENCE) { nsecs_t time = layer.acquireFence->getSignalTime(); if (isValidTimestamp(time)) { layer.acquireTime = time; layer.acquireFence = Fence::NO_FENCE; } } if (layer.releaseFence != Fence::NO_FENCE) { nsecs_t time = layer.releaseFence->getSignalTime(); if (isValidTimestamp(time)) { layer.releaseTime = time; layer.releaseFence = Fence::NO_FENCE; } } } } } void FenceTracker::addFrame(nsecs_t refreshStartTime, sp retireFence, const Vector>& layers, sp glDoneFence) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); FrameRecord& frame = mFrames[mOffset]; FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) % MAX_FRAME_HISTORY]; frame.layers.clear(); bool wasGlesCompositionDone = false; const size_t count = layers.size(); for (size_t i = 0; i < count; i++) { String8 name; uint64_t frameNumber; bool glesComposition; nsecs_t postedTime; sp acquireFence; sp prevReleaseFence; int32_t key = layers[i]->getSequence(); layers[i]->getFenceData(&name, &frameNumber, &glesComposition, &postedTime, &acquireFence, &prevReleaseFence); #ifdef USE_HWC2 if (glesComposition) { frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(name, frameNumber, glesComposition, postedTime, 0, 0, acquireFence, prevReleaseFence)); wasGlesCompositionDone = true; } else { frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(name, frameNumber, glesComposition, postedTime, 0, 0, acquireFence, Fence::NO_FENCE)); auto prevLayer = prevFrame.layers.find(key); if (prevLayer != prevFrame.layers.end()) { prevLayer->second.releaseFence = prevReleaseFence; } } #else frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(name, frameNumber, glesComposition, postedTime, 0, 0, acquireFence, glesComposition ? Fence::NO_FENCE : prevReleaseFence)); if (glesComposition) { wasGlesCompositionDone = true; } #endif frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(name, frameNumber, glesComposition, postedTime, 0, 0, acquireFence, prevReleaseFence)); } frame.frameId = mFrameCounter; frame.refreshStartTime = refreshStartTime; frame.retireTime = 0; frame.glesCompositionDoneTime = 0; prevFrame.retireFence = retireFence; frame.retireFence = Fence::NO_FENCE; frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence : Fence::NO_FENCE; mOffset = (mOffset + 1) % MAX_FRAME_HISTORY; mFrameCounter++; checkFencesForCompletion(); } } // namespace android services/surfaceflinger/FenceTracker.h0100644 0000000 0000000 00000007270 13077405420 017144 0ustar000000000 0000000 /* * Copyright 2016 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_FENCETRACKER_H #define ANDROID_FENCETRACKER_H #include #include #include #include #include #include #include namespace android { class Layer; /* * Keeps a circular buffer of fence/timestamp data for the last N frames in * SurfaceFlinger. Gets timestamps for fences after they have signaled. */ class FenceTracker { public: FenceTracker(); void dump(String8* outString); void addFrame(nsecs_t refreshStartTime, sp retireFence, const Vector>& layers, sp glDoneFence); protected: static constexpr size_t MAX_FRAME_HISTORY = 128; struct LayerRecord { String8 name; // layer name uint64_t frameNumber; // frame number for this layer bool isGlesComposition; // was GLES composition used for this layer? nsecs_t postedTime; // time when buffer was queued nsecs_t acquireTime; // timestamp from the acquire fence nsecs_t releaseTime; // timestamp from the release fence sp acquireFence; // acquire fence sp releaseFence; // release fence LayerRecord(const String8& name, uint64_t frameNumber, bool isGlesComposition, nsecs_t postedTime, nsecs_t acquireTime, nsecs_t releaseTime, sp acquireFence, sp releaseFence) : name(name), frameNumber(frameNumber), isGlesComposition(isGlesComposition), postedTime(postedTime), acquireTime(acquireTime), releaseTime(releaseTime), acquireFence(acquireFence), releaseFence(releaseFence) {}; LayerRecord() : name("uninitialized"), frameNumber(0), isGlesComposition(false), postedTime(0), acquireTime(0), releaseTime(0), acquireFence(Fence::NO_FENCE), releaseFence(Fence::NO_FENCE) {}; }; struct FrameRecord { // global SurfaceFlinger frame counter uint64_t frameId; // layer data for this frame std::unordered_map layers; // timestamp for when SurfaceFlinger::handleMessageRefresh() was called nsecs_t refreshStartTime; // timestamp from the retire fence nsecs_t retireTime; // timestamp from the GLES composition completion fence nsecs_t glesCompositionDoneTime; // primary display retire fence for this frame sp retireFence; // if GLES composition was done, the fence for its completion sp glesCompositionDoneFence; FrameRecord() : frameId(0), layers(), refreshStartTime(0), retireTime(0), glesCompositionDoneTime(0), retireFence(Fence::NO_FENCE), glesCompositionDoneFence(Fence::NO_FENCE) {} }; uint64_t mFrameCounter; uint32_t mOffset; FrameRecord mFrames[MAX_FRAME_HISTORY]; Mutex mMutex; void checkFencesForCompletion(); }; } #endif // ANDROID_FRAMETRACKER_H services/surfaceflinger/FrameTracker.cpp0100644 0000000 0000000 00000017643 13077405420 017516 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ // This is needed for stdint.h to define INT64_MAX in C++ #define __STDC_LIMIT_MACROS #include #include #include #include #include #include "FrameTracker.h" #include "EventLog/EventLog.h" namespace android { FrameTracker::FrameTracker() : mOffset(0), mNumFences(0), mDisplayPeriod(0) { resetFrameCountersLocked(); } void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) { Mutex::Autolock lock(mMutex); mFrameRecords[mOffset].desiredPresentTime = presentTime; } void FrameTracker::setFrameReadyTime(nsecs_t readyTime) { Mutex::Autolock lock(mMutex); mFrameRecords[mOffset].frameReadyTime = readyTime; } void FrameTracker::setFrameReadyFence(const sp& readyFence) { Mutex::Autolock lock(mMutex); mFrameRecords[mOffset].frameReadyFence = readyFence; mNumFences++; } void FrameTracker::setActualPresentTime(nsecs_t presentTime) { Mutex::Autolock lock(mMutex); mFrameRecords[mOffset].actualPresentTime = presentTime; } void FrameTracker::setActualPresentFence(const sp& readyFence) { Mutex::Autolock lock(mMutex); mFrameRecords[mOffset].actualPresentFence = readyFence; mNumFences++; } void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) { Mutex::Autolock lock(mMutex); mDisplayPeriod = displayPeriod; } void FrameTracker::advanceFrame() { Mutex::Autolock lock(mMutex); // Update the statistic to include the frame we just finished. updateStatsLocked(mOffset); // Advance to the next frame. mOffset = (mOffset+1) % NUM_FRAME_RECORDS; mFrameRecords[mOffset].desiredPresentTime = INT64_MAX; mFrameRecords[mOffset].frameReadyTime = INT64_MAX; mFrameRecords[mOffset].actualPresentTime = INT64_MAX; if (mFrameRecords[mOffset].frameReadyFence != NULL) { // We're clobbering an unsignaled fence, so we need to decrement the // fence count. mFrameRecords[mOffset].frameReadyFence = NULL; mNumFences--; } if (mFrameRecords[mOffset].actualPresentFence != NULL) { // We're clobbering an unsignaled fence, so we need to decrement the // fence count. mFrameRecords[mOffset].actualPresentFence = NULL; mNumFences--; } // Clean up the signaled fences to keep the number of open fence FDs in // this process reasonable. processFencesLocked(); } void FrameTracker::clearStats() { Mutex::Autolock lock(mMutex); for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) { mFrameRecords[i].desiredPresentTime = 0; mFrameRecords[i].frameReadyTime = 0; mFrameRecords[i].actualPresentTime = 0; mFrameRecords[i].frameReadyFence.clear(); mFrameRecords[i].actualPresentFence.clear(); } mNumFences = 0; mFrameRecords[mOffset].desiredPresentTime = INT64_MAX; mFrameRecords[mOffset].frameReadyTime = INT64_MAX; mFrameRecords[mOffset].actualPresentTime = INT64_MAX; } void FrameTracker::getStats(FrameStats* outStats) const { Mutex::Autolock lock(mMutex); processFencesLocked(); outStats->refreshPeriodNano = mDisplayPeriod; const size_t offset = mOffset; for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) { const size_t index = (offset + i) % NUM_FRAME_RECORDS; // Skip frame records with no data (if buffer not yet full). if (mFrameRecords[index].desiredPresentTime == 0) { continue; } nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime; outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano); nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime; outStats->actualPresentTimesNano.push_back(actualPresentTimeNano); nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime; outStats->frameReadyTimesNano.push_back(frameReadyTimeNano); } } void FrameTracker::logAndResetStats(const String8& name) { Mutex::Autolock lock(mMutex); logStatsLocked(name); resetFrameCountersLocked(); } void FrameTracker::processFencesLocked() const { FrameRecord* records = const_cast(mFrameRecords); int& numFences = const_cast(mNumFences); for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) { size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS; bool updated = false; const sp& rfence = records[idx].frameReadyFence; if (rfence != NULL) { records[idx].frameReadyTime = rfence->getSignalTime(); if (records[idx].frameReadyTime < INT64_MAX) { records[idx].frameReadyFence = NULL; numFences--; updated = true; } } const sp& pfence = records[idx].actualPresentFence; if (pfence != NULL) { records[idx].actualPresentTime = pfence->getSignalTime(); if (records[idx].actualPresentTime < INT64_MAX) { records[idx].actualPresentFence = NULL; numFences--; updated = true; } } if (updated) { updateStatsLocked(idx); } } } void FrameTracker::updateStatsLocked(size_t newFrameIdx) const { int* numFrames = const_cast(mNumFrames); if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) { size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) % NUM_FRAME_RECORDS; if (isFrameValidLocked(prevFrameIdx)) { nsecs_t newPresentTime = mFrameRecords[newFrameIdx].actualPresentTime; nsecs_t prevPresentTime = mFrameRecords[prevFrameIdx].actualPresentTime; nsecs_t duration = newPresentTime - prevPresentTime; int numPeriods = int((duration + mDisplayPeriod/2) / mDisplayPeriod); for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) { int nextBucket = 1 << (i+1); if (numPeriods < nextBucket) { numFrames[i]++; return; } } // The last duration bucket is a catch-all. numFrames[NUM_FRAME_BUCKETS-1]++; } } } void FrameTracker::resetFrameCountersLocked() { for (int i = 0; i < NUM_FRAME_BUCKETS; i++) { mNumFrames[i] = 0; } } void FrameTracker::logStatsLocked(const String8& name) const { for (int i = 0; i < NUM_FRAME_BUCKETS; i++) { if (mNumFrames[i] > 0) { EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS); return; } } } bool FrameTracker::isFrameValidLocked(size_t idx) const { return mFrameRecords[idx].actualPresentTime > 0 && mFrameRecords[idx].actualPresentTime < INT64_MAX; } void FrameTracker::dumpStats(String8& result) const { Mutex::Autolock lock(mMutex); processFencesLocked(); const size_t o = mOffset; for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) { const size_t index = (o+i) % NUM_FRAME_RECORDS; result.appendFormat("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n", mFrameRecords[index].desiredPresentTime, mFrameRecords[index].actualPresentTime, mFrameRecords[index].frameReadyTime); } result.append("\n"); } } // namespace android services/surfaceflinger/FrameTracker.h0100644 0000000 0000000 00000014147 13077405420 017157 0ustar000000000 0000000 /* * Copyright (C) 2012 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_FRAMETRACKER_H #define ANDROID_FRAMETRACKER_H #include #include #include #include namespace android { class String8; class Fence; // FrameTracker tracks information about the most recently rendered frames. It // uses a circular buffer of frame records, and is *NOT* thread-safe - // mutexing must be done at a higher level if multi-threaded access is // possible. // // Some of the time values tracked may be set either as a specific timestamp // or a fence. When a non-NULL fence is set for a given time value, the // signal time of that fence is used instead of the timestamp. class FrameTracker { public: // NUM_FRAME_RECORDS is the size of the circular buffer used to track the // frame time history. enum { NUM_FRAME_RECORDS = 128 }; enum { NUM_FRAME_BUCKETS = 7 }; FrameTracker(); // setDesiredPresentTime sets the time at which the current frame // should be presented to the user under ideal (i.e. zero latency) // conditions. void setDesiredPresentTime(nsecs_t desiredPresentTime); // setFrameReadyTime sets the time at which the current frame became ready // to be presented to the user. For example, if the frame contents is // being written to memory by some asynchronous hardware, this would be // the time at which those writes completed. void setFrameReadyTime(nsecs_t readyTime); // setFrameReadyFence sets the fence that is used to get the time at which // the current frame became ready to be presented to the user. void setFrameReadyFence(const sp& readyFence); // setActualPresentTime sets the timestamp at which the current frame became // visible to the user. void setActualPresentTime(nsecs_t displayTime); // setActualPresentFence sets the fence that is used to get the time // at which the current frame became visible to the user. void setActualPresentFence(const sp& fence); // setDisplayRefreshPeriod sets the display refresh period in nanoseconds. // This is used to compute frame presentation duration statistics relative // to this period. void setDisplayRefreshPeriod(nsecs_t displayPeriod); // advanceFrame advances the frame tracker to the next frame. void advanceFrame(); // clearStats clears the tracked frame stats. void clearStats(); // getStats gets the tracked frame stats. void getStats(FrameStats* outStats) const; // logAndResetStats dumps the current statistics to the binary event log // and then resets the accumulated statistics to their initial values. void logAndResetStats(const String8& name); // dumpStats dump appends the current frame display time history to the result string. void dumpStats(String8& result) const; private: struct FrameRecord { FrameRecord() : desiredPresentTime(0), frameReadyTime(0), actualPresentTime(0) {} nsecs_t desiredPresentTime; nsecs_t frameReadyTime; nsecs_t actualPresentTime; sp frameReadyFence; sp actualPresentFence; }; // processFences iterates over all the frame records that have a fence set // and replaces that fence with a timestamp if the fence has signaled. If // the fence is not signaled the record's displayTime is set to INT64_MAX. // // This method is const because although it modifies the frame records it // does so in such a way that the information represented should not // change. This allows it to be called from the dump method. void processFencesLocked() const; // updateStatsLocked updates the running statistics that are gathered // about the frame times. void updateStatsLocked(size_t newFrameIdx) const; // resetFrameCounteresLocked sets all elements of the mNumFrames array to // 0. void resetFrameCountersLocked(); // logStatsLocked dumps the current statistics to the binary event log. void logStatsLocked(const String8& name) const; // isFrameValidLocked returns true if the data for the given frame index is // valid and has all arrived (i.e. there are no oustanding fences). bool isFrameValidLocked(size_t idx) const; // mFrameRecords is the circular buffer storing the tracked data for each // frame. FrameRecord mFrameRecords[NUM_FRAME_RECORDS]; // mOffset is the offset into mFrameRecords of the current frame. size_t mOffset; // mNumFences is the total number of fences set in the frame records. It // is incremented each time a fence is added and decremented each time a // signaled fence is removed in processFences or if advanceFrame clobbers // a fence. // // The number of fences is tracked so that the run time of processFences // doesn't grow with NUM_FRAME_RECORDS. int mNumFences; // mNumFrames keeps a count of the number of frames with a duration in a // particular range of vsync periods. Element n of the array stores the // number of frames with duration in the half-inclusive range // [2^n, 2^(n+1)). The last element of the array contains the count for // all frames with duration greater than 2^(NUM_FRAME_BUCKETS-1). int32_t mNumFrames[NUM_FRAME_BUCKETS]; // mDisplayPeriod is the display refresh period of the display for which // this FrameTracker is gathering information. nsecs_t mDisplayPeriod; // mMutex is used to protect access to all member variables. mutable Mutex mMutex; }; } #endif // ANDROID_FRAMETRACKER_H services/surfaceflinger/GpuService.cpp0100644 0000000 0000000 00000011765 13077405420 017223 0ustar000000000 0000000 /* * Copyright 2016 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 "GpuService.h" #include #include #include namespace android { // ---------------------------------------------------------------------------- class BpGpuService : public BpInterface { public: BpGpuService(const sp& impl) : BpInterface(impl) {} }; IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService"); status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case SHELL_COMMAND_TRANSACTION: { int in = data.readFileDescriptor(); int out = data.readFileDescriptor(); int err = data.readFileDescriptor(); int argc = data.readInt32(); Vector args; for (int i = 0; i < argc && data.dataAvail() > 0; i++) { args.add(data.readString16()); } return shellCommand(in, out, err, args); } default: return BBinder::onTransact(code, data, reply, flags); } } // ---------------------------------------------------------------------------- namespace { status_t cmd_help(int out); status_t cmd_vkjson(int out, int err); } const char* const GpuService::SERVICE_NAME = "gpu"; GpuService::GpuService() {} status_t GpuService::shellCommand(int /*in*/, int out, int err, Vector& args) { ALOGV("GpuService::shellCommand"); for (size_t i = 0, n = args.size(); i < n; i++) ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string()); if (args[0] == String16("vkjson")) return cmd_vkjson(out, err); else if (args[0] == String16("help")) return cmd_help(out); return NO_ERROR; } // ---------------------------------------------------------------------------- namespace { status_t cmd_help(int out) { FILE* outs = fdopen(out, "w"); if (!outs) { ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno), errno); return BAD_VALUE; } fprintf(outs, "GPU Service commands:\n" " vkjson dump Vulkan device capabilities as JSON\n"); fclose(outs); return NO_ERROR; } VkResult vkjsonPrint(FILE* out, FILE* err) { VkResult result; const VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "vkjson", 1, /* app name, version */ "", 0, /* engine name, version */ VK_API_VERSION_1_0 }; const VkInstanceCreateInfo instance_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr, 0, /* flags */ &app_info, 0, nullptr, /* layers */ 0, nullptr, /* extensions */ }; VkInstance instance; result = vkCreateInstance(&instance_info, nullptr, &instance); if (result != VK_SUCCESS) { fprintf(err, "vkCreateInstance failed: %d\n", result); return result; } uint32_t ngpu = 0; result = vkEnumeratePhysicalDevices(instance, &ngpu, nullptr); if (result != VK_SUCCESS) { fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result); return result; } std::vector gpus(ngpu, VK_NULL_HANDLE); result = vkEnumeratePhysicalDevices(instance, &ngpu, gpus.data()); if (result != VK_SUCCESS) { fprintf(err, "vkEnumeratePhysicalDevices failed: %d\n", result); return result; } for (size_t i = 0, n = gpus.size(); i < n; i++) { auto props = VkJsonGetAllProperties(gpus[i]); std::string json = VkJsonAllPropertiesToJson(props); fwrite(json.data(), 1, json.size(), out); if (i < n - 1) fputc(',', out); fputc('\n', out); } vkDestroyInstance(instance, nullptr); return VK_SUCCESS; } status_t cmd_vkjson(int out, int err) { int errnum; FILE* outs = fdopen(out, "w"); if (!outs) { errnum = errno; ALOGE("vkjson: failed to create output stream: %s", strerror(errnum)); return -errnum; } FILE* errs = fdopen(err, "w"); if (!errs) { errnum = errno; ALOGE("vkjson: failed to create error stream: %s", strerror(errnum)); fclose(outs); return -errnum; } fprintf(outs, "[\n"); VkResult result = vkjsonPrint(outs, errs); fprintf(outs, "]\n"); fclose(errs); fclose(outs); return result >= 0 ? NO_ERROR : UNKNOWN_ERROR; } } // anonymous namespace } // namespace android services/surfaceflinger/GpuService.h0100644 0000000 0000000 00000003007 13077405420 016656 0ustar000000000 0000000 /* * Copyright 2016 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_GPUSERVICE_H #define ANDROID_GPUSERVICE_H #include #include namespace android { /* * This class defines the Binder IPC interface for GPU-related queries and * control. */ class IGpuService : public IInterface { public: DECLARE_META_INTERFACE(GpuService); }; class BnGpuService: public BnInterface { protected: virtual status_t shellCommand(int in, int out, int err, Vector& args) = 0; virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override; }; class GpuService : public BnGpuService { public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; protected: virtual status_t shellCommand(int in, int out, int err, Vector& args) override; }; } // namespace android #endif // ANDROID_GPUSERVICE_H services/surfaceflinger/Layer.cpp0100644 0000000 0000000 00000233736 13077405420 016227 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "Layer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "clz.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "Layer.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" #include "DisplayHardware/HWComposer.h" #include "RenderEngine/RenderEngine.h" #define DEBUG_RESIZE 0 namespace android { // --------------------------------------------------------------------------- int32_t Layer::sSequence = 1; Layer::Layer(SurfaceFlinger* flinger, const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags) : contentDirty(false), sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), mTextureName(-1U), mPremultipliedAlpha(true), mName("unnamed"), mFormat(PIXEL_FORMAT_NONE), mTransactionFlags(0), mPendingStateMutex(), mPendingStates(), mQueuedFrames(0), mSidebandStreamChanged(false), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mOverrideScalingMode(-1), mCurrentOpacity(true), mCurrentFrameNumber(0), mRefreshPending(false), mFrameLatencyNeeded(false), mFiltering(false), mNeedsFiltering(false), mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), #ifndef USE_HWC2 mIsGlesComposition(false), #endif mProtectedByApp(false), mHasSurface(false), mClientRef(client), mPotentialCursor(false), mQueueItemLock(), mQueueItemCondition(), mQueueItems(), mLastFrameNumberReceived(0), mUpdateTexImageFailed(false), mAutoRefresh(false), mFreezePositionUpdates(false) { #ifdef USE_HWC2 ALOGV("Creating Layer %s", name.string()); #endif mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName); uint32_t layerFlags = 0; if (flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; if (flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure; if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; mName = name; mCurrentState.active.w = w; mCurrentState.active.h = h; mCurrentState.active.transform.set(0, 0); mCurrentState.crop.makeInvalid(); mCurrentState.finalCrop.makeInvalid(); mCurrentState.z = 0; #ifdef USE_HWC2 mCurrentState.alpha = 1.0f; #else mCurrentState.alpha = 0xFF; #endif mCurrentState.layerStack = 0; mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; mCurrentState.requested = mCurrentState.active; // drawing state & current state are identical mDrawingState = mCurrentState; #ifdef USE_HWC2 const auto& hwc = flinger->getHwComposer(); const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY); nsecs_t displayPeriod = activeConfig->getVsyncPeriod(); #else nsecs_t displayPeriod = flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); #endif mFrameTracker.setDisplayRefreshPeriod(displayPeriod); } void Layer::onFirstRef() { // Creates a custom BufferQueue for SurfaceFlingerConsumer to use sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); mProducer = new MonitoredProducer(producer, mFlinger); mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mSurfaceFlingerConsumer->setContentsChangedListener(this); mSurfaceFlingerConsumer->setName(mName); #ifdef TARGET_DISABLE_TRIPLE_BUFFERING #warning "disabling triple buffering" #else mProducer->setMaxDequeuedBufferCount(2); #endif const sp hw(mFlinger->getDefaultDisplayDevice()); updateTransformHint(hw); } Layer::~Layer() { sp c(mClientRef.promote()); if (c != 0) { c->detachLayer(this); } for (auto& point : mRemoteSyncPoints) { point->setTransactionApplied(); } for (auto& point : mLocalSyncPoints) { point->setFrameAvailable(); } mFlinger->deleteTextureAsync(mTextureName); mFrameTracker.logAndResetStats(mName); } // --------------------------------------------------------------------------- // callbacks // --------------------------------------------------------------------------- #ifdef USE_HWC2 void Layer::onLayerDisplayed(const sp& releaseFence) { if (mHwcLayers.empty()) { return; } mSurfaceFlingerConsumer->setReleaseFence(releaseFence); } #else void Layer::onLayerDisplayed(const sp& /* hw */, HWComposer::HWCLayerInterface* layer) { if (layer) { layer->onDisplayed(); mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence()); } } #endif void Layer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after // a frame number reset if (item.mFrameNumber == 1) { mLastFrameNumberReceived = 0; } // Ensure that callbacks are handled in order while (item.mFrameNumber != mLastFrameNumberReceived + 1) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", mName.string()); } } mQueueItems.push_back(item); android_atomic_inc(&mQueuedFrames); // Wake up any pending callbacks mLastFrameNumberReceived = item.mFrameNumber; mQueueItemCondition.broadcast(); } mFlinger->signalLayerUpdate(); } void Layer::onFrameReplaced(const BufferItem& item) { { // Autolock scope Mutex::Autolock lock(mQueueItemLock); // Ensure that callbacks are handled in order while (item.mFrameNumber != mLastFrameNumberReceived + 1) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", mName.string()); } } if (mQueueItems.empty()) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(mQueueItems.size() - 1) = item; // Wake up any pending callbacks mLastFrameNumberReceived = item.mFrameNumber; mQueueItemCondition.broadcast(); } } void Layer::onSidebandStreamChanged() { if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was false mFlinger->signalLayerUpdate(); } } // called with SurfaceFlinger::mStateLock from the drawing thread after // the layer has been remove from the current state list (and just before // it's removed from the drawing state list) void Layer::onRemoved() { mSurfaceFlingerConsumer->abandon(); } // --------------------------------------------------------------------------- // set-up // --------------------------------------------------------------------------- const String8& Layer::getName() const { return mName; } status_t Layer::setBuffers( uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { uint32_t const maxSurfaceDims = min( mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims()); // never allow a surface larger than what our underlying GL implementation // can handle. if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) { ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h)); return BAD_VALUE; } mFormat = format; mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; mCurrentOpacity = getOpacityForFormat(format); mSurfaceFlingerConsumer->setDefaultBufferSize(w, h); mSurfaceFlingerConsumer->setDefaultBufferFormat(format); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); return NO_ERROR; } /* * The layer handle is just a BBinder object passed to the client * (remote process) -- we don't keep any reference on our side such that * the dtor is called when the remote side let go of its reference. * * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for * this layer when the handle is destroyed. */ class Layer::Handle : public BBinder, public LayerCleaner { public: Handle(const sp& flinger, const sp& layer) : LayerCleaner(flinger, layer), owner(layer) {} wp owner; }; sp Layer::getHandle() { Mutex::Autolock _l(mLock); LOG_ALWAYS_FATAL_IF(mHasSurface, "Layer::getHandle() has already been called"); mHasSurface = true; return new Handle(mFlinger, this); } sp Layer::getProducer() const { return mProducer; } // --------------------------------------------------------------------------- // h/w composer set-up // --------------------------------------------------------------------------- Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) Rect crop; if (!mCurrentCrop.isEmpty()) { // if the buffer crop is defined, we use that crop = mCurrentCrop; } else if (mActiveBuffer != NULL) { // otherwise we use the whole buffer crop = mActiveBuffer->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop crop.makeInvalid(); } return crop; } static Rect reduce(const Rect& win, const Region& exclude) { if (CC_LIKELY(exclude.isEmpty())) { return win; } if (exclude.isRect()) { return win.reduce(exclude.getBounds()); } return Region(win).subtract(exclude).getBounds(); } Rect Layer::computeBounds() const { const Layer::State& s(getDrawingState()); return computeBounds(s.activeTransparentRegion); } Rect Layer::computeBounds(const Region& activeTransparentRegion) const { const Layer::State& s(getDrawingState()); Rect win(s.active.w, s.active.h); if (!s.crop.isEmpty()) { win.intersect(s.crop, &win); } // subtract the transparent region and snap to the bounds return reduce(win, activeTransparentRegion); } FloatRect Layer::computeCrop(const sp& hw) const { // the content crop is the area of the content that gets scaled to the // layer's size. FloatRect crop(getContentCrop()); // the crop is the area of the window that gets cropped, but not // scaled in any ways. const State& s(getDrawingState()); // apply the projection's clipping to the window crop in // layerstack space, and convert-back to layer space. // if there are no window scaling involved, this operation will map to full // pixels in the buffer. // FIXME: the 3 lines below can produce slightly incorrect clipping when we have // a viewport clipping and a window transform. we should use floating point to fix this. Rect activeCrop(s.active.w, s.active.h); if (!s.crop.isEmpty()) { activeCrop = s.crop; } activeCrop = s.active.transform.transform(activeCrop); if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) { activeCrop.clear(); } if (!s.finalCrop.isEmpty()) { if(!activeCrop.intersect(s.finalCrop, &activeCrop)) { activeCrop.clear(); } } activeCrop = s.active.transform.inverse().transform(activeCrop); // This needs to be here as transform.transform(Rect) computes the // transformed rect and then takes the bounding box of the result before // returning. This means // transform.inverse().transform(transform.transform(Rect)) != Rect // in which case we need to make sure the final rect is clipped to the // display bounds. if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) { activeCrop.clear(); } // subtract the transparent region and snap to the bounds activeCrop = reduce(activeCrop, s.activeTransparentRegion); // Transform the window crop to match the buffer coordinate system, // which means using the inverse of the current transform set on the // SurfaceFlingerConsumer. uint32_t invTransform = mCurrentTransform; if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to the * buffer */ uint32_t invTransformOrient = DisplayDevice::getPrimaryDisplayOrientationTransform(); // calculate the inverse transform if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) { invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } // and apply to the current transform invTransform = (Transform(invTransformOrient) * Transform(invTransform)) .getOrientation(); } int winWidth = s.active.w; int winHeight = s.active.h; if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { // If the activeCrop has been rotate the ends are rotated but not // the space itself so when transforming ends back we can't rely on // a modification of the axes of rotation. To account for this we // need to reorient the inverse rotation in terms of the current // axes of rotation. bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0; bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0; if (is_h_flipped == is_v_flipped) { invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } winWidth = s.active.h; winHeight = s.active.w; } const Rect winCrop = activeCrop.transform( invTransform, s.active.w, s.active.h); // below, crop is intersected with winCrop expressed in crop's coordinate space float xScale = crop.getWidth() / float(winWidth); float yScale = crop.getHeight() / float(winHeight); float insetL = winCrop.left * xScale; float insetT = winCrop.top * yScale; float insetR = (winWidth - winCrop.right ) * xScale; float insetB = (winHeight - winCrop.bottom) * yScale; crop.left += insetL; crop.top += insetT; crop.right -= insetR; crop.bottom -= insetB; return crop; } #ifdef USE_HWC2 void Layer::setGeometry(const sp& displayDevice) #else void Layer::setGeometry( const sp& hw, HWComposer::HWCLayerInterface& layer) #endif { #ifdef USE_HWC2 const auto hwcId = displayDevice->getHwcDisplayId(); auto& hwcInfo = mHwcLayers[hwcId]; #else layer.setDefaultState(); #endif // enable this layer #ifdef USE_HWC2 hwcInfo.forceClientComposition = false; if (isSecure() && !displayDevice->isSecure()) { hwcInfo.forceClientComposition = true; } auto& hwcLayer = hwcInfo.layer; #else layer.setSkip(false); if (isSecure() && !hw->isSecure()) { layer.setSkip(true); } #endif // this gives us only the "orientation" component of the transform const State& s(getDrawingState()); #ifdef USE_HWC2 if (!isOpaque(s) || s.alpha != 1.0f) { auto blendMode = mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage; auto error = hwcLayer->setBlendMode(blendMode); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:" " %s (%d)", mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(), static_cast(error)); } #else if (!isOpaque(s) || s.alpha != 0xFF) { layer.setBlending(mPremultipliedAlpha ? HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE); } #endif // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects Region activeTransparentRegion(s.activeTransparentRegion); if (!s.crop.isEmpty()) { Rect activeCrop(s.crop); activeCrop = s.active.transform.transform(activeCrop); #ifdef USE_HWC2 if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) { #else if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) { #endif activeCrop.clear(); } activeCrop = s.active.transform.inverse().transform(activeCrop); // This needs to be here as transform.transform(Rect) computes the // transformed rect and then takes the bounding box of the result before // returning. This means // transform.inverse().transform(transform.transform(Rect)) != Rect // in which case we need to make sure the final rect is clipped to the // display bounds. if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) { activeCrop.clear(); } // mark regions outside the crop as transparent activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top)); activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h)); activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom)); activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom)); } Rect frame(s.active.transform.transform(computeBounds(activeTransparentRegion))); if (!s.finalCrop.isEmpty()) { if(!frame.intersect(s.finalCrop, &frame)) { frame.clear(); } } #ifdef USE_HWC2 if (!frame.intersect(displayDevice->getViewport(), &frame)) { frame.clear(); } const Transform& tr(displayDevice->getTransform()); Rect transformedFrame = tr.transform(frame); auto error = hwcLayer->setDisplayFrame(transformedFrame); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set display frame " "[%d, %d, %d, %d]: %s (%d)", mName.string(), transformedFrame.left, transformedFrame.top, transformedFrame.right, transformedFrame.bottom, to_string(error).c_str(), static_cast(error)); FloatRect sourceCrop = computeCrop(displayDevice); error = hwcLayer->setSourceCrop(sourceCrop); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set source crop " "[%.3f, %.3f, %.3f, %.3f]: %s (%d)", mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(), static_cast(error)); error = hwcLayer->setPlaneAlpha(s.alpha); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: " "%s (%d)", mName.string(), s.alpha, to_string(error).c_str(), static_cast(error)); error = hwcLayer->setZOrder(s.z); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), s.z, to_string(error).c_str(), static_cast(error)); #else if (!frame.intersect(hw->getViewport(), &frame)) { frame.clear(); } const Transform& tr(hw->getTransform()); layer.setFrame(tr.transform(frame)); layer.setCrop(computeCrop(hw)); layer.setPlaneAlpha(s.alpha); #endif /* * Transformations are applied in this order: * 1) buffer orientation/flip/mirror * 2) state transformation (window manager) * 3) layer orientation (screen orientation) * (NOTE: the matrices are multiplied in reverse order) */ const Transform bufferOrientation(mCurrentTransform); Transform transform(tr * s.active.transform * bufferOrientation); if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to the * buffer */ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform(); // calculate the inverse transform if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H; } // and apply to the current transform transform = Transform(invTransform) * transform; } // this gives us only the "orientation" component of the transform const uint32_t orientation = transform.getOrientation(); #ifdef USE_HWC2 if (orientation & Transform::ROT_INVALID) { // we can only handle simple transformation hwcInfo.forceClientComposition = true; } else { auto transform = static_cast(orientation); auto error = hwcLayer->setTransform(transform); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: " "%s (%d)", mName.string(), to_string(transform).c_str(), to_string(error).c_str(), static_cast(error)); } #else if (orientation & Transform::ROT_INVALID) { // we can only handle simple transformation layer.setSkip(true); } else { layer.setTransform(orientation); } #endif } #ifdef USE_HWC2 void Layer::forceClientComposition(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId); return; } mHwcLayers[hwcId].forceClientComposition = true; } #endif #ifdef USE_HWC2 void Layer::setPerFrameData(const sp& displayDevice) { // Apply this display's projection's viewport to the visible region // before giving it to the HWC HAL. const Transform& tr = displayDevice->getTransform(); const auto& viewport = displayDevice->getViewport(); Region visible = tr.transform(visibleRegion.intersect(viewport)); auto hwcId = displayDevice->getHwcDisplayId(); auto& hwcLayer = mHwcLayers[hwcId].layer; auto error = hwcLayer->setVisibleRegion(visible); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(), to_string(error).c_str(), static_cast(error)); visible.dump(LOG_TAG); } error = hwcLayer->setSurfaceDamage(surfaceDamageRegion); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(), to_string(error).c_str(), static_cast(error)); surfaceDamageRegion.dump(LOG_TAG); } // Sideband layers if (mSidebandStream.get()) { setCompositionType(hwcId, HWC2::Composition::Sideband); ALOGV("[%s] Requesting Sideband composition", mName.string()); error = hwcLayer->setSidebandStream(mSidebandStream->handle()); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(), mSidebandStream->handle(), to_string(error).c_str(), static_cast(error)); } return; } // Client or SolidColor layers if (mActiveBuffer == nullptr || mActiveBuffer->handle == nullptr || mHwcLayers[hwcId].forceClientComposition) { // TODO: This also includes solid color layers, but no API exists to // setup a solid color layer yet ALOGV("[%s] Requesting Client composition", mName.string()); setCompositionType(hwcId, HWC2::Composition::Client); error = hwcLayer->setBuffer(nullptr, Fence::NO_FENCE); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set null buffer: %s (%d)", mName.string(), to_string(error).c_str(), static_cast(error)); } return; } // Device or Cursor layers if (mPotentialCursor) { ALOGV("[%s] Requesting Cursor composition", mName.string()); setCompositionType(hwcId, HWC2::Composition::Cursor); } else { ALOGV("[%s] Requesting Device composition", mName.string()); setCompositionType(hwcId, HWC2::Composition::Device); } auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence(); error = hwcLayer->setBuffer(mActiveBuffer->handle, acquireFence); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle, to_string(error).c_str(), static_cast(error)); } } #else void Layer::setPerFrameData(const sp& hw, HWComposer::HWCLayerInterface& layer) { // we have to set the visible region on every frame because // we currently free it during onLayerDisplayed(), which is called // after HWComposer::commit() -- every frame. // Apply this display's projection's viewport to the visible region // before giving it to the HWC HAL. const Transform& tr = hw->getTransform(); Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); layer.setVisibleRegionScreen(visible); layer.setSurfaceDamage(surfaceDamageRegion); mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER); if (mSidebandStream.get()) { layer.setSidebandStream(mSidebandStream); } else { // NOTE: buffer can be NULL if the client never drew into this // layer yet, or if we ran out of memory layer.setBuffer(mActiveBuffer); } } #endif #ifdef USE_HWC2 void Layer::updateCursorPosition(const sp& displayDevice) { auto hwcId = displayDevice->getHwcDisplayId(); if (mHwcLayers.count(hwcId) == 0 || getCompositionType(hwcId) != HWC2::Composition::Cursor) { return; } // This gives us only the "orientation" component of the transform const State& s(getCurrentState()); // Apply the layer's transform, followed by the display's global transform // Here we're guaranteed that the layer's transform preserves rects Rect win(s.active.w, s.active.h); if (!s.crop.isEmpty()) { win.intersect(s.crop, &win); } // Subtract the transparent region and snap to the bounds Rect bounds = reduce(win, s.activeTransparentRegion); Rect frame(s.active.transform.transform(bounds)); frame.intersect(displayDevice->getViewport(), &frame); if (!s.finalCrop.isEmpty()) { frame.intersect(s.finalCrop, &frame); } auto& displayTransform(displayDevice->getTransform()); auto position = displayTransform.transform(frame); auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left, position.top); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set cursor position " "to (%d, %d): %s (%d)", mName.string(), position.left, position.top, to_string(error).c_str(), static_cast(error)); } #else void Layer::setAcquireFence(const sp& /* hw */, HWComposer::HWCLayerInterface& layer) { int fenceFd = -1; // TODO: there is a possible optimization here: we only need to set the // acquire fence the first time a new buffer is acquired on EACH display. if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) { sp fence = mSurfaceFlingerConsumer->getCurrentFence(); if (fence->isValid()) { fenceFd = fence->dup(); if (fenceFd == -1) { ALOGW("failed to dup layer fence, skipping sync: %d", errno); } } } layer.setAcquireFenceFd(fenceFd); } Rect Layer::getPosition( const sp& hw) { // this gives us only the "orientation" component of the transform const State& s(getCurrentState()); // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects Rect win(s.active.w, s.active.h); if (!s.crop.isEmpty()) { win.intersect(s.crop, &win); } // subtract the transparent region and snap to the bounds Rect bounds = reduce(win, s.activeTransparentRegion); Rect frame(s.active.transform.transform(bounds)); frame.intersect(hw->getViewport(), &frame); if (!s.finalCrop.isEmpty()) { frame.intersect(s.finalCrop, &frame); } const Transform& tr(hw->getTransform()); return Rect(tr.transform(frame)); } #endif // --------------------------------------------------------------------------- // drawing... // --------------------------------------------------------------------------- void Layer::draw(const sp& hw, const Region& clip) const { onDraw(hw, clip, false); } void Layer::draw(const sp& hw, bool useIdentityTransform) const { onDraw(hw, Region(hw->bounds()), useIdentityTransform); } void Layer::draw(const sp& hw) const { onDraw(hw, Region(hw->bounds()), false); } void Layer::onDraw(const sp& hw, const Region& clip, bool useIdentityTransform) const { ATRACE_CALL(); if (CC_UNLIKELY(mActiveBuffer == 0)) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with // SurfaceView because the WindowManager can't know when the client // has drawn the first time. // If there is nothing under us, we paint the screen in black, otherwise // we just skip this update. // figure out if there is something below us Region under; const SurfaceFlinger::LayerVector& drawingLayers( mFlinger->mDrawingState.layersSortedByZ); const size_t count = drawingLayers.size(); for (size_t i=0 ; i& layer(drawingLayers[i]); if (layer.get() == static_cast(this)) break; under.orSelf( hw->getTransform().transform(layer->visibleRegion) ); } // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); if (!holes.isEmpty()) { clearWithOpenGL(hw, holes, 0, 0, 0, 1); } return; } // Bind the current buffer to the GL texture, and wait for it to be // ready for us to draw into. status_t err = mSurfaceFlingerConsumer->bindTextureImage(); if (err != NO_ERROR) { ALOGW("onDraw: bindTextureImage failed (err=%d)", err); // Go ahead and draw the buffer anyway; no matter what we do the screen // is probably going to have something visibly wrong. } bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); RenderEngine& engine(mFlinger->getRenderEngine()); if (!blackOutLayer) { // TODO: we could be more subtle with isFixedSize() const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); // Query the texture matrix given our current filtering mode. float textureMatrix[16]; mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering); mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { /* * the code below applies the primary display's inverse transform to * the texture transform */ // create a 4x4 transform matrix from the display transform flags const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1); const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1); const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1); mat4 tr; uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform(); if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) tr = tr * rot90; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) tr = tr * flipH; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) tr = tr * flipV; // calculate the inverse tr = inverse(tr); // and finally apply it to the original texture matrix const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); } // Set things up for texturing. mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); mTexture.setFiltering(useFiltering); mTexture.setMatrix(textureMatrix); engine.setupLayerTexturing(mTexture); } else { engine.setupLayerBlackedOut(); } drawWithOpenGL(hw, clip, useIdentityTransform); engine.disableTexturing(); } void Layer::clearWithOpenGL(const sp& hw, const Region& /* clip */, float red, float green, float blue, float alpha) const { RenderEngine& engine(mFlinger->getRenderEngine()); computeGeometry(hw, mMesh, false); engine.setupFillWithColor(red, green, blue, alpha); engine.drawMesh(mMesh); } void Layer::clearWithOpenGL( const sp& hw, const Region& clip) const { clearWithOpenGL(hw, clip, 0,0,0,0); } void Layer::drawWithOpenGL(const sp& hw, const Region& /* clip */, bool useIdentityTransform) const { const State& s(getDrawingState()); computeGeometry(hw, mMesh, useIdentityTransform); /* * NOTE: the way we compute the texture coordinates here produces * different results than when we take the HWC path -- in the later case * the "source crop" is rounded to texel boundaries. * This can produce significantly different results when the texture * is scaled by a large amount. * * The GL code below is more logical (imho), and the difference with * HWC is due to a limitation of the HWC API to integers -- a question * is suspend is whether we should ignore this problem or revert to * GL composition when a buffer scaling is applied (maybe with some * minimal value)? Or, we could make GL behave like HWC -- but this feel * like more of a hack. */ Rect win(computeBounds()); if (!s.finalCrop.isEmpty()) { win = s.active.transform.transform(win); if (!win.intersect(s.finalCrop, &win)) { win.clear(); } win = s.active.transform.inverse().transform(win); if (!win.intersect(computeBounds(), &win)) { win.clear(); } } float left = float(win.left) / float(s.active.w); float top = float(win.top) / float(s.active.h); float right = float(win.right) / float(s.active.w); float bottom = float(win.bottom) / float(s.active.h); // TODO: we probably want to generate the texture coords with the mesh // here we assume that we only have 4 vertices Mesh::VertexArray texCoords(mMesh.getTexCoordArray()); texCoords[0] = vec2(left, 1.0f - top); texCoords[1] = vec2(left, 1.0f - bottom); texCoords[2] = vec2(right, 1.0f - bottom); texCoords[3] = vec2(right, 1.0f - top); RenderEngine& engine(mFlinger->getRenderEngine()); engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha); engine.drawMesh(mMesh); engine.disableBlending(); } #ifdef USE_HWC2 void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) { if (mHwcLayers.count(hwcId) == 0) { ALOGE("setCompositionType called without a valid HWC layer"); return; } auto& hwcInfo = mHwcLayers[hwcId]; auto& hwcLayer = hwcInfo.layer; ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(), static_cast(callIntoHwc)); if (hwcInfo.compositionType != type) { ALOGV(" actually setting"); hwcInfo.compositionType = type; if (callIntoHwc) { auto error = hwcLayer->setCompositionType(type); ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set " "composition type %s: %s (%d)", mName.string(), to_string(type).c_str(), to_string(error).c_str(), static_cast(error)); } } } HWC2::Composition Layer::getCompositionType(int32_t hwcId) const { if (mHwcLayers.count(hwcId) == 0) { ALOGE("getCompositionType called without a valid HWC layer"); return HWC2::Composition::Invalid; } return mHwcLayers.at(hwcId).compositionType; } void Layer::setClearClientTarget(int32_t hwcId, bool clear) { if (mHwcLayers.count(hwcId) == 0) { ALOGE("setClearClientTarget called without a valid HWC layer"); return; } mHwcLayers[hwcId].clearClientTarget = clear; } bool Layer::getClearClientTarget(int32_t hwcId) const { if (mHwcLayers.count(hwcId) == 0) { ALOGE("getClearClientTarget called without a valid HWC layer"); return false; } return mHwcLayers.at(hwcId).clearClientTarget; } #endif uint32_t Layer::getProducerStickyTransform() const { int producerStickyTransform = 0; int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); if (ret != OK) { ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, strerror(-ret), ret); return 0; } return static_cast(producerStickyTransform); } uint64_t Layer::getHeadFrameNumber() const { Mutex::Autolock lock(mQueueItemLock); if (!mQueueItems.empty()) { return mQueueItems[0].mFrameNumber; } else { return mCurrentFrameNumber; } } bool Layer::addSyncPoint(const std::shared_ptr& point) { if (point->getFrameNumber() <= mCurrentFrameNumber) { // Don't bother with a SyncPoint, since we've already latched the // relevant frame return false; } Mutex::Autolock lock(mLocalSyncPointMutex); mLocalSyncPoints.push_back(point); return true; } void Layer::setFiltering(bool filtering) { mFiltering = filtering; } bool Layer::getFiltering() const { return mFiltering; } // As documented in libhardware header, formats in the range // 0x100 - 0x1FF are specific to the HAL implementation, and // are known to have no alpha channel // TODO: move definition for device-specific range into // hardware.h, instead of using hard-coded values here. #define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) bool Layer::getOpacityForFormat(uint32_t format) { if (HARDWARE_IS_DEVICE_FORMAT(format)) { return true; } switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_BGRA_8888: return false; } // in all other case, we have no blending (also for unknown formats) return true; } // ---------------------------------------------------------------------------- // local state // ---------------------------------------------------------------------------- static void boundPoint(vec2* point, const Rect& crop) { if (point->x < crop.left) { point->x = crop.left; } if (point->x > crop.right) { point->x = crop.right; } if (point->y < crop.top) { point->y = crop.top; } if (point->y > crop.bottom) { point->y = crop.bottom; } } void Layer::computeGeometry(const sp& hw, Mesh& mesh, bool useIdentityTransform) const { const Layer::State& s(getDrawingState()); const Transform tr(hw->getTransform()); const uint32_t hw_h = hw->getHeight(); Rect win(s.active.w, s.active.h); if (!s.crop.isEmpty()) { win.intersect(s.crop, &win); } // subtract the transparent region and snap to the bounds win = reduce(win, s.activeTransparentRegion); vec2 lt = vec2(win.left, win.top); vec2 lb = vec2(win.left, win.bottom); vec2 rb = vec2(win.right, win.bottom); vec2 rt = vec2(win.right, win.top); if (!useIdentityTransform) { lt = s.active.transform.transform(lt); lb = s.active.transform.transform(lb); rb = s.active.transform.transform(rb); rt = s.active.transform.transform(rt); } if (!s.finalCrop.isEmpty()) { boundPoint(<, s.finalCrop); boundPoint(&lb, s.finalCrop); boundPoint(&rb, s.finalCrop); boundPoint(&rt, s.finalCrop); } Mesh::VertexArray position(mesh.getPositionArray()); position[0] = tr.transform(lt); position[1] = tr.transform(lb); position[2] = tr.transform(rb); position[3] = tr.transform(rt); for (size_t i=0 ; i<4 ; i++) { position[i].y = hw_h - position[i].y; } } bool Layer::isOpaque(const Layer::State& s) const { // if we don't have a buffer yet, we're translucent regardless of the // layer's opaque flag. if (mActiveBuffer == 0) { return false; } // if the layer has the opaque flag, then we're always opaque, // otherwise we use the current buffer's format. return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; } bool Layer::isSecure() const { const Layer::State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); } bool Layer::isProtected() const { const sp& activeBuffer(mActiveBuffer); return (activeBuffer != 0) && (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); } bool Layer::isFixedSize() const { return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE; } bool Layer::isCropped() const { return !mCurrentCrop.isEmpty(); } bool Layer::needsFiltering(const sp& hw) const { return mNeedsFiltering || hw->needsFiltering(); } void Layer::setVisibleRegion(const Region& visibleRegion) { // always called from main thread this->visibleRegion = visibleRegion; } void Layer::setCoveredRegion(const Region& coveredRegion) { // always called from main thread this->coveredRegion = coveredRegion; } void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) { // always called from main thread this->visibleNonTransparentRegion = setVisibleNonTransparentRegion; } // ---------------------------------------------------------------------------- // transaction // ---------------------------------------------------------------------------- void Layer::pushPendingState() { if (!mCurrentState.modified) { return; } // If this transaction is waiting on the receipt of a frame, generate a sync // point and send it to the remote layer. if (mCurrentState.handle != nullptr) { sp handle = static_cast(mCurrentState.handle.get()); sp handleLayer = handle->owner.promote(); if (handleLayer == nullptr) { ALOGE("[%s] Unable to promote Layer handle", mName.string()); // If we can't promote the layer we are intended to wait on, // then it is expired or otherwise invalid. Allow this transaction // to be applied as per normal (no synchronization). mCurrentState.handle = nullptr; } else { auto syncPoint = std::make_shared( mCurrentState.frameNumber); if (handleLayer->addSyncPoint(syncPoint)) { mRemoteSyncPoints.push_back(std::move(syncPoint)); } else { // We already missed the frame we're supposed to synchronize // on, so go ahead and apply the state update mCurrentState.handle = nullptr; } } // Wake us up to check if the frame has been received setTransactionFlags(eTransactionNeeded); } mPendingStates.push_back(mCurrentState); } void Layer::popPendingState(State* stateToCommit) { auto oldFlags = stateToCommit->flags; *stateToCommit = mPendingStates[0]; stateToCommit->flags = (oldFlags & ~stateToCommit->mask) | (stateToCommit->flags & stateToCommit->mask); mPendingStates.removeAt(0); } bool Layer::applyPendingStates(State* stateToCommit) { bool stateUpdateAvailable = false; while (!mPendingStates.empty()) { if (mPendingStates[0].handle != nullptr) { if (mRemoteSyncPoints.empty()) { // If we don't have a sync point for this, apply it anyway. It // will be visually wrong, but it should keep us from getting // into too much trouble. ALOGE("[%s] No local sync point found", mName.string()); popPendingState(stateToCommit); stateUpdateAvailable = true; continue; } if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) { ALOGE("[%s] Unexpected sync point frame number found", mName.string()); // Signal our end of the sync point and then dispose of it mRemoteSyncPoints.front()->setTransactionApplied(); mRemoteSyncPoints.pop_front(); continue; } if (mRemoteSyncPoints.front()->frameIsAvailable()) { // Apply the state update popPendingState(stateToCommit); stateUpdateAvailable = true; // Signal our end of the sync point and then dispose of it mRemoteSyncPoints.front()->setTransactionApplied(); mRemoteSyncPoints.pop_front(); } else { break; } } else { popPendingState(stateToCommit); stateUpdateAvailable = true; } } // If we still have pending updates, wake SurfaceFlinger back up and point // it at this layer so we can process them if (!mPendingStates.empty()) { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); } mCurrentState.modified = false; return stateUpdateAvailable; } void Layer::notifyAvailableFrames() { auto headFrameNumber = getHeadFrameNumber(); Mutex::Autolock lock(mLocalSyncPointMutex); for (auto& point : mLocalSyncPoints) { if (headFrameNumber >= point->getFrameNumber()) { point->setFrameAvailable(); } } } uint32_t Layer::doTransaction(uint32_t flags) { ATRACE_CALL(); pushPendingState(); Layer::State c = getCurrentState(); if (!applyPendingStates(&c)) { return 0; } const Layer::State& s(getDrawingState()); const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h); if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer ALOGD_IF(DEBUG_RESIZE, "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n" " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} }}\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} }}\n", this, getName().string(), mCurrentTransform, getEffectiveScalingMode(), c.active.w, c.active.h, c.crop.left, c.crop.top, c.crop.right, c.crop.bottom, c.crop.getWidth(), c.crop.getHeight(), c.requested.w, c.requested.h, s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right, s.crop.bottom, s.crop.getWidth(), s.crop.getHeight(), s.requested.w, s.requested.h); // record the new size, form this point on, when the client request // a buffer, it'll get the new size. mSurfaceFlingerConsumer->setDefaultBufferSize( c.requested.w, c.requested.h); } const bool resizePending = (c.requested.w != c.active.w) || (c.requested.h != c.active.h); if (!isFixedSize()) { if (resizePending && mSidebandStream == NULL) { // don't let Layer::doTransaction update the drawing state // if we have a pending resize, unless we are in fixed-size mode. // the drawing state will be updated only once we receive a buffer // with the correct size. // // in particular, we want to make sure the clip (which is part // of the geometry state) is latched together with the size but is // latched immediately when no resizing is involved. // // If a sideband stream is attached, however, we want to skip this // optimization so that transactions aren't missed when a buffer // never arrives flags |= eDontUpdateGeometryState; } } // always set active to requested, unless we're asked not to // this is used by Layer, which special cases resizes. if (flags & eDontUpdateGeometryState) { } else { Layer::State& editCurrentState(getCurrentState()); if (mFreezePositionUpdates) { float tx = c.active.transform.tx(); float ty = c.active.transform.ty(); c.active = c.requested; c.active.transform.set(tx, ty); editCurrentState.active = c.active; } else { editCurrentState.active = editCurrentState.requested; c.active = c.requested; } } if (s.active != c.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; } if (c.sequence != s.sequence) { // invalidate and recompute the visible regions if needed flags |= eVisibleRegion; this->contentDirty = true; // we may use linear filtering, if the matrix scales us const uint8_t type = c.active.transform.getType(); mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE)); } // If the layer is hidden, signal and clear out all local sync points so // that transactions for layers depending on this layer's frames becoming // visible are not blocked if (c.flags & layer_state_t::eLayerHidden) { Mutex::Autolock lock(mLocalSyncPointMutex); for (auto& point : mLocalSyncPoints) { point->setFrameAvailable(); } mLocalSyncPoints.clear(); } // Commit the transaction commitTransaction(c); return flags; } void Layer::commitTransaction(const State& stateToCommit) { mDrawingState = stateToCommit; } uint32_t Layer::getTransactionFlags(uint32_t flags) { return android_atomic_and(~flags, &mTransactionFlags) & flags; } uint32_t Layer::setTransactionFlags(uint32_t flags) { return android_atomic_or(flags, &mTransactionFlags); } bool Layer::setPosition(float x, float y, bool immediate) { if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y) return false; mCurrentState.sequence++; // We update the requested and active position simultaneously because // we want to apply the position portion of the transform matrix immediately, // but still delay scaling when resizing a SCALING_MODE_FREEZE layer. mCurrentState.requested.transform.set(x, y); if (immediate && !mFreezePositionUpdates) { mCurrentState.active.transform.set(x, y); } mFreezePositionUpdates = mFreezePositionUpdates || !immediate; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setLayer(uint32_t z) { if (mCurrentState.z == z) return false; mCurrentState.sequence++; mCurrentState.z = z; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setSize(uint32_t w, uint32_t h) { if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false; mCurrentState.requested.w = w; mCurrentState.requested.h = h; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } #ifdef USE_HWC2 bool Layer::setAlpha(float alpha) { #else bool Layer::setAlpha(uint8_t alpha) { #endif if (mCurrentState.alpha == alpha) return false; mCurrentState.sequence++; mCurrentState.alpha = alpha; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { mCurrentState.sequence++; mCurrentState.requested.transform.set( matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy); mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setTransparentRegionHint(const Region& transparent) { mCurrentState.requestedTransparentRegion = transparent; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setFlags(uint8_t flags, uint8_t mask) { const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); if (mCurrentState.flags == newFlags) return false; mCurrentState.sequence++; mCurrentState.flags = newFlags; mCurrentState.mask = mask; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setCrop(const Rect& crop) { if (mCurrentState.crop == crop) return false; mCurrentState.sequence++; mCurrentState.crop = crop; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setFinalCrop(const Rect& crop) { if (mCurrentState.finalCrop == crop) return false; mCurrentState.sequence++; mCurrentState.finalCrop = crop; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } bool Layer::setOverrideScalingMode(int32_t scalingMode) { if (scalingMode == mOverrideScalingMode) return false; mOverrideScalingMode = scalingMode; setTransactionFlags(eTransactionNeeded); return true; } uint32_t Layer::getEffectiveScalingMode() const { if (mOverrideScalingMode >= 0) { return mOverrideScalingMode; } return mCurrentScalingMode; } bool Layer::setLayerStack(uint32_t layerStack) { if (mCurrentState.layerStack == layerStack) return false; mCurrentState.sequence++; mCurrentState.layerStack = layerStack; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } void Layer::deferTransactionUntil(const sp& handle, uint64_t frameNumber) { mCurrentState.handle = handle; mCurrentState.frameNumber = frameNumber; // We don't set eTransactionNeeded, because just receiving a deferral // request without any other state updates shouldn't actually induce a delay mCurrentState.modified = true; pushPendingState(); mCurrentState.handle = nullptr; mCurrentState.frameNumber = 0; mCurrentState.modified = false; } void Layer::useSurfaceDamage() { if (mFlinger->mForceFullDamage) { surfaceDamageRegion = Region::INVALID_REGION; } else { surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage(); } } void Layer::useEmptyDamage() { surfaceDamageRegion.clear(); } // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- bool Layer::shouldPresentNow(const DispSync& dispSync) const { if (mSidebandStreamChanged || mAutoRefresh) { return true; } Mutex::Autolock lock(mQueueItemLock); if (mQueueItems.empty()) { return false; } auto timestamp = mQueueItems[0].mTimestamp; nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); // Ignore timestamps more than a second in the future bool isPlausible = timestamp < (expectedPresent + s2ns(1)); ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible " "relative to expectedPresent %" PRId64, mName.string(), timestamp, expectedPresent); bool isDue = timestamp < expectedPresent; return isDue || !isPlausible; } bool Layer::onPreComposition() { mRefreshPending = false; return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } void Layer::onPostComposition() { if (mFrameLatencyNeeded) { nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp(); mFrameTracker.setDesiredPresentTime(desiredPresentTime); sp frameReadyFence = mSurfaceFlingerConsumer->getCurrentFence(); if (frameReadyFence->isValid()) { mFrameTracker.setFrameReadyFence(frameReadyFence); } else { // There was no fence for this frame, so assume that it was ready // to be presented at the desired present time. mFrameTracker.setFrameReadyTime(desiredPresentTime); } const HWComposer& hwc = mFlinger->getHwComposer(); #ifdef USE_HWC2 sp presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY); #else sp presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); #endif if (presentFence->isValid()) { mFrameTracker.setActualPresentFence(presentFence); } else { // The HWC doesn't support present fences, so use the refresh // timestamp instead. nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); mFrameTracker.setActualPresentTime(presentTime); } mFrameTracker.advanceFrame(); mFrameLatencyNeeded = false; } } #ifdef USE_HWC2 void Layer::releasePendingBuffer() { mSurfaceFlingerConsumer->releasePendingBuffer(); } #endif bool Layer::isVisible() const { const Layer::State& s(mDrawingState); #ifdef USE_HWC2 return !(s.flags & layer_state_t::eLayerHidden) && s.alpha > 0.0f && (mActiveBuffer != NULL || mSidebandStream != NULL); #else return !(s.flags & layer_state_t::eLayerHidden) && s.alpha && (mActiveBuffer != NULL || mSidebandStream != NULL); #endif } Region Layer::latchBuffer(bool& recomputeVisibleRegions) { ATRACE_CALL(); if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was true mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream(); if (mSidebandStream != NULL) { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); } recomputeVisibleRegions = true; const State& s(getDrawingState()); return s.active.transform.transform(Region(Rect(s.active.w, s.active.h))); } Region outDirtyRegion; if (mQueuedFrames > 0 || mAutoRefresh) { // if we've already called updateTexImage() without going through // a composition step, we have to skip this layer at this point // because we cannot call updateTeximage() without a corresponding // compositionComplete() call. // we'll trigger an update in onPreComposition(). if (mRefreshPending) { return outDirtyRegion; } // Capture the old state of the layer for comparisons later const State& s(getDrawingState()); const bool oldOpacity = isOpaque(s); sp oldActiveBuffer = mActiveBuffer; struct Reject : public SurfaceFlingerConsumer::BufferRejecter { Layer::State& front; Layer::State& current; bool& recomputeVisibleRegions; bool stickyTransformSet; const char* name; int32_t overrideScalingMode; Reject(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions, bool stickySet, const char* name, int32_t overrideScalingMode) : front(front), current(current), recomputeVisibleRegions(recomputeVisibleRegions), stickyTransformSet(stickySet), name(name), overrideScalingMode(overrideScalingMode) { } virtual bool reject(const sp& buf, const BufferItem& item) { if (buf == NULL) { return false; } uint32_t bufWidth = buf->getWidth(); uint32_t bufHeight = buf->getHeight(); // check that we received a buffer of the right size // (Take the buffer's orientation into account) if (item.mTransform & Transform::ROT_90) { swap(bufWidth, bufHeight); } int actualScalingMode = overrideScalingMode >= 0 ? overrideScalingMode : item.mScalingMode; bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; if (front.active != front.requested) { if (isFixedSize || (bufWidth == front.requested.w && bufHeight == front.requested.h)) { // Here we pretend the transaction happened by updating the // current and drawing states. Drawing state is only accessed // in this thread, no need to have it locked front.active = front.requested; // We also need to update the current state so that // we don't end-up overwriting the drawing state with // this stale current state during the next transaction // // NOTE: We don't need to hold the transaction lock here // because State::active is only accessed from this thread. current.active = front.active; current.modified = true; // recompute visible region recomputeVisibleRegions = true; } ALOGD_IF(DEBUG_RESIZE, "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} }}\n", name, bufWidth, bufHeight, item.mTransform, item.mScalingMode, front.active.w, front.active.h, front.crop.left, front.crop.top, front.crop.right, front.crop.bottom, front.crop.getWidth(), front.crop.getHeight(), front.requested.w, front.requested.h); } if (!isFixedSize && !stickyTransformSet) { if (front.active.w != bufWidth || front.active.h != bufHeight) { // reject this buffer ALOGE("[%s] rejecting buffer: " "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}", name, bufWidth, bufHeight, front.active.w, front.active.h); return true; } } // if the transparent region has changed (this test is // conservative, but that's fine, worst case we're doing // a bit of extra work), we latch the new one and we // trigger a visible-region recompute. if (!front.activeTransparentRegion.isTriviallyEqual( front.requestedTransparentRegion)) { front.activeTransparentRegion = front.requestedTransparentRegion; // We also need to update the current state so that // we don't end-up overwriting the drawing state with // this stale current state during the next transaction // // NOTE: We don't need to hold the transaction lock here // because State::active is only accessed from this thread. current.activeTransparentRegion = front.activeTransparentRegion; // recompute visible region recomputeVisibleRegions = true; } return false; } }; Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode); // Check all of our local sync points to ensure that all transactions // which need to have been applied prior to the frame which is about to // be latched have signaled auto headFrameNumber = getHeadFrameNumber(); bool matchingFramesFound = false; bool allTransactionsApplied = true; { Mutex::Autolock lock(mLocalSyncPointMutex); for (auto& point : mLocalSyncPoints) { if (point->getFrameNumber() > headFrameNumber) { break; } matchingFramesFound = true; if (!point->frameIsAvailable()) { // We haven't notified the remote layer that the frame for // this point is available yet. Notify it now, and then // abort this attempt to latch. point->setFrameAvailable(); allTransactionsApplied = false; break; } allTransactionsApplied &= point->transactionIsApplied(); } } if (matchingFramesFound && !allTransactionsApplied) { mFlinger->signalLayerUpdate(); return outDirtyRegion; } // This boolean is used to make sure that SurfaceFlinger's shadow copy // of the buffer queue isn't modified when the buffer queue is returning // BufferItem's that weren't actually queued. This can happen in shared // buffer mode. bool queuedBuffer = false; status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer, mLastFrameNumberReceived); if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. mFlinger->signalLayerUpdate(); return outDirtyRegion; } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) { // If the buffer has been rejected, remove it from the shadow queue // and return early if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); mQueueItems.removeAt(0); android_atomic_dec(&mQueuedFrames); } return outDirtyRegion; } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { // This can occur if something goes wrong when trying to create the // EGLImage for this buffer. If this happens, the buffer has already // been released, so we need to clean up the queue and bug out // early. if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); mQueueItems.clear(); android_atomic_and(0, &mQueuedFrames); } // Once we have hit this state, the shadow queue may no longer // correctly reflect the incoming BufferQueue's contents, so even if // updateTexImage starts working, the only safe course of action is // to continue to ignore updates. mUpdateTexImageFailed = true; return outDirtyRegion; } if (queuedBuffer) { // Autolock scope auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); Mutex::Autolock lock(mQueueItemLock); // Remove any stale buffers that have been dropped during // updateTexImage while (mQueueItems[0].mFrameNumber != currentFrameNumber) { mQueueItems.removeAt(0); android_atomic_dec(&mQueuedFrames); } mQueueItems.removeAt(0); } // Decrement the queued-frames count. Signal another event if we // have more frames pending. if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) { mFlinger->signalLayerUpdate(); } if (updateResult != NO_ERROR) { // something happened! recomputeVisibleRegions = true; return outDirtyRegion; } // update the active buffer mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. return outDirtyRegion; } mRefreshPending = true; mFrameLatencyNeeded = true; if (oldActiveBuffer == NULL) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. recomputeVisibleRegions = true; } Rect crop(mSurfaceFlingerConsumer->getCurrentCrop()); const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform()); const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode()); if ((crop != mCurrentCrop) || (transform != mCurrentTransform) || (scalingMode != mCurrentScalingMode)) { mCurrentCrop = crop; mCurrentTransform = transform; mCurrentScalingMode = scalingMode; recomputeVisibleRegions = true; } if (oldActiveBuffer != NULL) { uint32_t bufWidth = mActiveBuffer->getWidth(); uint32_t bufHeight = mActiveBuffer->getHeight(); if (bufWidth != uint32_t(oldActiveBuffer->width) || bufHeight != uint32_t(oldActiveBuffer->height)) { recomputeVisibleRegions = true; mFreezePositionUpdates = false; } } mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format); if (oldOpacity != isOpaque(s)) { recomputeVisibleRegions = true; } mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); // Remove any sync points corresponding to the buffer which was just // latched { Mutex::Autolock lock(mLocalSyncPointMutex); auto point = mLocalSyncPoints.begin(); while (point != mLocalSyncPoints.end()) { if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) { // This sync point must have been added since we started // latching. Don't drop it yet. ++point; continue; } if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { point = mLocalSyncPoints.erase(point); } else { ++point; } } } // FIXME: postedRegion should be dirty & bounds Region dirtyRegion(Rect(s.active.w, s.active.h)); // transform the dirty region to window-manager space outDirtyRegion = (s.active.transform.transform(dirtyRegion)); } return outDirtyRegion; } uint32_t Layer::getEffectiveUsage(uint32_t usage) const { // TODO: should we do something special if mSecure is set? if (mProtectedByApp) { // need a hardware-protected path to external video sink usage |= GraphicBuffer::USAGE_PROTECTED; } if (mPotentialCursor) { usage |= GraphicBuffer::USAGE_CURSOR; } usage |= GraphicBuffer::USAGE_HW_COMPOSER; return usage; } void Layer::updateTransformHint(const sp& hw) const { uint32_t orientation = 0; if (!mFlinger->mDebugDisableTransformHint) { // The transform hint is used to improve performance, but we can // only have a single transform hint, it cannot // apply to all displays. const Transform& planeTransform(hw->getTransform()); orientation = planeTransform.getOrientation(); if (orientation & Transform::ROT_INVALID) { orientation = 0; } } mSurfaceFlingerConsumer->setTransformHint(orientation); } // ---------------------------------------------------------------------------- // debugging // ---------------------------------------------------------------------------- void Layer::dump(String8& result, Colorizer& colorizer) const { const Layer::State& s(getDrawingState()); colorizer.colorize(result, Colorizer::GREEN); result.appendFormat( "+ %s %p (%s)\n", getTypeId(), this, getName().string()); colorizer.reset(result); s.activeTransparentRegion.dump(result, "transparentRegion"); visibleRegion.dump(result, "visibleRegion"); surfaceDamageRegion.dump(result, "surfaceDamageRegion"); sp client(mClientRef.promote()); result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " #ifdef USE_HWC2 "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" #else "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" #endif " client=%p\n", s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right, s.crop.bottom, s.finalCrop.left, s.finalCrop.top, s.finalCrop.right, s.finalCrop.bottom, isOpaque(s), contentDirty, s.alpha, s.flags, s.active.transform[0][0], s.active.transform[0][1], s.active.transform[1][0], s.active.transform[1][1], client.get()); sp buf0(mActiveBuffer); uint32_t w0=0, h0=0, s0=0, f0=0; if (buf0 != 0) { w0 = buf0->getWidth(); h0 = buf0->getHeight(); s0 = buf0->getStride(); f0 = buf0->format; } result.appendFormat( " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," " queued-frames=%d, mRefreshPending=%d\n", mFormat, w0, h0, s0,f0, mQueuedFrames, mRefreshPending); if (mSurfaceFlingerConsumer != 0) { mSurfaceFlingerConsumer->dump(result, " "); } } void Layer::dumpFrameStats(String8& result) const { mFrameTracker.dumpStats(result); } void Layer::clearFrameStats() { mFrameTracker.clearStats(); } void Layer::logFrameStats() { mFrameTracker.logAndResetStats(mName); } void Layer::getFrameStats(FrameStats* outStats) const { mFrameTracker.getStats(outStats); } void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber, bool* outIsGlesComposition, nsecs_t* outPostedTime, sp* outAcquireFence, sp* outPrevReleaseFence) const { *outName = mName; *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); #ifdef USE_HWC2 *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ? mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType == HWC2::Composition::Client : true; #else *outIsGlesComposition = mIsGlesComposition; #endif *outPostedTime = mSurfaceFlingerConsumer->getTimestamp(); *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence(); *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence(); } // --------------------------------------------------------------------------- Layer::LayerCleaner::LayerCleaner(const sp& flinger, const sp& layer) : mFlinger(flinger), mLayer(layer) { } Layer::LayerCleaner::~LayerCleaner() { // destroy client resources mFlinger->onLayerDestroyed(mLayer); } // --------------------------------------------------------------------------- }; // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" #endif #if defined(__gl2_h_) #error "don't include gl2/gl2.h in this file" #endif services/surfaceflinger/Layer.h0100644 0000000 0000000 00000045075 13077405420 015671 0ustar000000000 0000000 /* * Copyright (C) 2007 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_LAYER_H #define ANDROID_LAYER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FrameTracker.h" #include "Client.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerConsumer.h" #include "Transform.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/FloatRect.h" #include "RenderEngine/Mesh.h" #include "RenderEngine/Texture.h" namespace android { // --------------------------------------------------------------------------- class Client; class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; // --------------------------------------------------------------------------- /* * A new BufferQueue and a new SurfaceFlingerConsumer are created when the * Layer is first referenced. * * This also implements onFrameAvailable(), which notifies SurfaceFlinger * that new data has arrived. */ class Layer : public SurfaceFlingerConsumer::ContentsChangedListener { static int32_t sSequence; public: mutable bool contentDirty; // regions below are in window-manager space Region visibleRegion; Region coveredRegion; Region visibleNonTransparentRegion; Region surfaceDamageRegion; // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are // the same. int32_t sequence; enum { // flags for doTransaction() eDontUpdateGeometryState = 0x00000001, eVisibleRegion = 0x00000002, }; struct Geometry { uint32_t w; uint32_t h; Transform transform; inline bool operator ==(const Geometry& rhs) const { return (w == rhs.w && h == rhs.h); } inline bool operator !=(const Geometry& rhs) const { return !operator ==(rhs); } }; struct State { Geometry active; Geometry requested; uint32_t z; uint32_t layerStack; #ifdef USE_HWC2 float alpha; #else uint8_t alpha; #endif uint8_t flags; uint8_t mask; uint8_t reserved[2]; int32_t sequence; // changes when visible regions can change bool modified; Rect crop; Rect finalCrop; // If set, defers this state update until the Layer identified by handle // receives a frame with the given frameNumber sp handle; uint64_t frameNumber; // the transparentRegion hint is a bit special, it's latched only // when we receive a buffer -- this is because it's "content" // dependent. Region activeTransparentRegion; Region requestedTransparentRegion; }; // ----------------------------------------------------------------------- Layer(SurfaceFlinger* flinger, const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~Layer(); // the this layer's size and format status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); // modify current state bool setPosition(float x, float y, bool immediate); bool setLayer(uint32_t z); bool setSize(uint32_t w, uint32_t h); #ifdef USE_HWC2 bool setAlpha(float alpha); #else bool setAlpha(uint8_t alpha); #endif bool setMatrix(const layer_state_t::matrix22_t& matrix); bool setTransparentRegionHint(const Region& transparent); bool setFlags(uint8_t flags, uint8_t mask); bool setCrop(const Rect& crop); bool setFinalCrop(const Rect& crop); bool setLayerStack(uint32_t layerStack); void deferTransactionUntil(const sp& handle, uint64_t frameNumber); bool setOverrideScalingMode(int32_t overrideScalingMode); // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with // one empty rect. void useSurfaceDamage(); void useEmptyDamage(); uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); void computeGeometry(const sp& hw, Mesh& mesh, bool useIdentityTransform) const; Rect computeBounds(const Region& activeTransparentRegion) const; Rect computeBounds() const; class Handle; sp getHandle(); sp getProducer() const; const String8& getName() const; int32_t getSequence() const { return sequence; } // ----------------------------------------------------------------------- // Virtuals virtual const char* getTypeId() const { return "Layer"; } /* * isOpaque - true if this surface is opaque * * This takes into account the buffer format (i.e. whether or not the * pixel format includes an alpha channel) and the "opaque" flag set * on the layer. It does not examine the current plane alpha value. */ virtual bool isOpaque(const Layer::State& s) const; /* * isSecure - true if this surface is secure, that is if it prevents * screenshots or VNC servers. */ virtual bool isSecure() const; /* * isProtected - true if the layer may contain protected content in the * GRALLOC_USAGE_PROTECTED sense. */ virtual bool isProtected() const; /* * isVisible - true if this layer is visible, false otherwise */ virtual bool isVisible() const; /* * isFixedSize - true if content has a fixed size */ virtual bool isFixedSize() const; protected: /* * onDraw - draws the surface. */ virtual void onDraw(const sp& hw, const Region& clip, bool useIdentityTransform) const; public: // ----------------------------------------------------------------------- #ifdef USE_HWC2 void setGeometry(const sp& displayDevice); void forceClientComposition(int32_t hwcId); void setPerFrameData(const sp& displayDevice); // callIntoHwc exists so we can update our local state and call // acceptDisplayChanges without unnecessarily updating the device's state void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true); HWC2::Composition getCompositionType(int32_t hwcId) const; void setClearClientTarget(int32_t hwcId, bool clear); bool getClearClientTarget(int32_t hwcId) const; void updateCursorPosition(const sp& hw); #else void setGeometry(const sp& hw, HWComposer::HWCLayerInterface& layer); void setPerFrameData(const sp& hw, HWComposer::HWCLayerInterface& layer); void setAcquireFence(const sp& hw, HWComposer::HWCLayerInterface& layer); Rect getPosition(const sp& hw); #endif /* * called after page-flip */ #ifdef USE_HWC2 void onLayerDisplayed(const sp& releaseFence); #else void onLayerDisplayed(const sp& hw, HWComposer::HWCLayerInterface* layer); #endif bool shouldPresentNow(const DispSync& dispSync) const; /* * called before composition. * returns true if the layer has pending updates. */ bool onPreComposition(); /* * called after composition. */ void onPostComposition(); #ifdef USE_HWC2 // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(); #endif /* * draw - performs some global clipping optimizations * and calls onDraw(). */ void draw(const sp& hw, const Region& clip) const; void draw(const sp& hw, bool useIdentityTransform) const; void draw(const sp& hw) const; /* * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. */ uint32_t doTransaction(uint32_t transactionFlags); /* * setVisibleRegion - called to set the new visible region. This gives * a chance to update the new visible region or record the fact it changed. */ void setVisibleRegion(const Region& visibleRegion); /* * setCoveredRegion - called when the covered region changes. The covered * region corresponds to any area of the surface that is covered * (transparently or not) by another surface. */ void setCoveredRegion(const Region& coveredRegion); /* * setVisibleNonTransparentRegion - called when the visible and * non-transparent region changes. */ void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion); /* * latchBuffer - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ Region latchBuffer(bool& recomputeVisibleRegions); bool isPotentialCursor() const { return mPotentialCursor;} /* * called with the state lock when the surface is removed from the * current list */ void onRemoved(); // Updates the transform hint in our SurfaceFlingerConsumer to match // the current orientation of the display device. void updateTransformHint(const sp& hw) const; /* * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ Rect getContentCrop() const; /* * Returns if a frame is queued. */ bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } #ifdef USE_HWC2 // ----------------------------------------------------------------------- bool hasHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return false; } if (mHwcLayers[hwcId].layer->isAbandoned()) { ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId); mHwcLayers.erase(hwcId); return false; } return true; } std::shared_ptr getHwcLayer(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { return nullptr; } return mHwcLayers[hwcId].layer; } void setHwcLayer(int32_t hwcId, std::shared_ptr&& layer) { if (layer) { mHwcLayers[hwcId].layer = layer; } else { mHwcLayers.erase(hwcId); } } #endif // ----------------------------------------------------------------------- void clearWithOpenGL(const sp& hw, const Region& clip) const; void setFiltering(bool filtering); bool getFiltering() const; // only for debugging inline const sp& getActiveBuffer() const { return mActiveBuffer; } inline const State& getDrawingState() const { return mDrawingState; } inline const State& getCurrentState() const { return mCurrentState; } inline State& getCurrentState() { return mCurrentState; } /* always call base class first */ void dump(String8& result, Colorizer& colorizer) const; void dumpFrameStats(String8& result) const; void clearFrameStats(); void logFrameStats(); void getFrameStats(FrameStats* outStats) const; void getFenceData(String8* outName, uint64_t* outFrameNumber, bool* outIsGlesComposition, nsecs_t* outPostedTime, sp* outAcquireFence, sp* outPrevReleaseFence) const; protected: // constant sp mFlinger; virtual void onFirstRef(); /* * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer) * is called. */ class LayerCleaner { sp mFlinger; wp mLayer; protected: ~LayerCleaner(); public: LayerCleaner(const sp& flinger, const sp& layer); }; private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener virtual void onFrameAvailable(const BufferItem& item) override; virtual void onFrameReplaced(const BufferItem& item) override; virtual void onSidebandStreamChanged() override; void commitTransaction(const State& stateToCommit); // needsLinearFiltering - true if this surface's state requires filtering bool needsFiltering(const sp& hw) const; uint32_t getEffectiveUsage(uint32_t usage) const; FloatRect computeCrop(const sp& hw) const; bool isCropped() const; static bool getOpacityForFormat(uint32_t format); // drawing void clearWithOpenGL(const sp& hw, const Region& clip, float r, float g, float b, float alpha) const; void drawWithOpenGL(const sp& hw, const Region& clip, bool useIdentityTransform) const; // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; // ----------------------------------------------------------------------- class SyncPoint { public: SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber), mFrameIsAvailable(false), mTransactionIsApplied(false) {} uint64_t getFrameNumber() const { return mFrameNumber; } bool frameIsAvailable() const { return mFrameIsAvailable; } void setFrameAvailable() { mFrameIsAvailable = true; } bool transactionIsApplied() const { return mTransactionIsApplied; } void setTransactionApplied() { mTransactionIsApplied = true; } private: const uint64_t mFrameNumber; std::atomic mFrameIsAvailable; std::atomic mTransactionIsApplied; }; // SyncPoints which will be signaled when the correct frame is at the head // of the queue and dropped after the frame has been latched. Protected by // mLocalSyncPointMutex. Mutex mLocalSyncPointMutex; std::list> mLocalSyncPoints; // SyncPoints which will be signaled and then dropped when the transaction // is applied std::list> mRemoteSyncPoints; uint64_t getHeadFrameNumber() const; // Returns false if the relevant frame has already been latched bool addSyncPoint(const std::shared_ptr& point); void pushPendingState(); void popPendingState(State* stateToCommit); bool applyPendingStates(State* stateToCommit); // Returns mCurrentScaling mode (originating from the // Client) or mOverrideScalingMode mode (originating from // the Surface Controller) if set. uint32_t getEffectiveScalingMode() const; public: void notifyAvailableFrames(); private: // ----------------------------------------------------------------------- // constants sp mSurfaceFlingerConsumer; sp mProducer; uint32_t mTextureName; // from GLES bool mPremultipliedAlpha; String8 mName; PixelFormat mFormat; // these are protected by an external lock State mCurrentState; State mDrawingState; volatile int32_t mTransactionFlags; // Accessed from main thread and binder threads Mutex mPendingStateMutex; Vector mPendingStates; // thread-safe volatile int32_t mQueuedFrames; volatile int32_t mSidebandStreamChanged; // used like an atomic boolean FrameTracker mFrameTracker; // main thread sp mActiveBuffer; sp mSidebandStream; Rect mCurrentCrop; uint32_t mCurrentTransform; uint32_t mCurrentScalingMode; // We encode unset as -1. int32_t mOverrideScalingMode; bool mCurrentOpacity; std::atomic mCurrentFrameNumber; bool mRefreshPending; bool mFrameLatencyNeeded; // Whether filtering is forced on or not bool mFiltering; // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering; // The mesh used to draw the layer in GLES composition mode mutable Mesh mMesh; // The texture used to draw the layer in GLES composition mode mutable Texture mTexture; #ifdef USE_HWC2 // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() : layer(), forceClientComposition(false), compositionType(HWC2::Composition::Invalid), clearClientTarget(false) {} std::shared_ptr layer; bool forceClientComposition; HWC2::Composition compositionType; bool clearClientTarget; }; std::unordered_map mHwcLayers; #else bool mIsGlesComposition; #endif // page-flip thread (currently main thread) bool mProtectedByApp; // application requires protected path to external sink // protected by mLock mutable Mutex mLock; // Set to true once we've returned this surface's handle mutable bool mHasSurface; const wp mClientRef; // This layer can be a cursor on some displays. bool mPotentialCursor; // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; Condition mQueueItemCondition; Vector mQueueItems; std::atomic mLastFrameNumberReceived; bool mUpdateTexImageFailed; // This is only modified from the main thread bool mAutoRefresh; bool mFreezePositionUpdates; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_LAYER_H services/surfaceflinger/LayerDim.cpp0100644 0000000 0000000 00000003706 13077405420 016651 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "LayerDim" #include #include #include #include #include #include #include "LayerDim.h" #include "SurfaceFlinger.h" #include "DisplayDevice.h" #include "RenderEngine/RenderEngine.h" namespace android { // --------------------------------------------------------------------------- LayerDim::LayerDim(SurfaceFlinger* flinger, const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags) : Layer(flinger, client, name, w, h, flags) { } LayerDim::~LayerDim() { } void LayerDim::onDraw(const sp& hw, const Region& /* clip */, bool useIdentityTransform) const { const State& s(getDrawingState()); if (s.alpha>0) { Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2); computeGeometry(hw, mesh, useIdentityTransform); RenderEngine& engine(mFlinger->getRenderEngine()); engine.setupDimLayerBlending(s.alpha); engine.drawMesh(mesh); engine.disableBlending(); } } bool LayerDim::isVisible() const { const Layer::State& s(getDrawingState()); return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/LayerDim.h0100644 0000000 0000000 00000003136 13077405420 016313 0ustar000000000 0000000 /* * Copyright (C) 2007 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_LAYER_DIM_H #define ANDROID_LAYER_DIM_H #include #include #include "Layer.h" // --------------------------------------------------------------------------- namespace android { class LayerDim : public Layer { public: LayerDim(SurfaceFlinger* flinger, const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~LayerDim(); virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp& hw, const Region& clip, bool useIdentityTransform) const; virtual bool isOpaque(const Layer::State&) const { return false; } virtual bool isSecure() const { return false; } virtual bool isFixedSize() const { return true; } virtual bool isVisible() const; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_LAYER_DIM_H services/surfaceflinger/MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13077405420 017554 0ustar000000000 0000000 services/surfaceflinger/MessageQueue.cpp0100644 0000000 0000000 00000012256 13077405420 017534 0ustar000000000 0000000 /* * Copyright (C) 2009 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 #include #include #include #include #include #include #include #include #include "MessageQueue.h" #include "EventThread.h" #include "SurfaceFlinger.h" namespace android { // --------------------------------------------------------------------------- MessageBase::MessageBase() : MessageHandler() { } MessageBase::~MessageBase() { } void MessageBase::handleMessage(const Message&) { this->handler(); barrier.open(); }; // --------------------------------------------------------------------------- void MessageQueue::Handler::dispatchRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); } } void MessageQueue::Handler::dispatchInvalidate() { if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } } void MessageQueue::Handler::handleMessage(const Message& message) { switch (message.what) { case INVALIDATE: android_atomic_and(~eventMaskInvalidate, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); break; case REFRESH: android_atomic_and(~eventMaskRefresh, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); break; } } // --------------------------------------------------------------------------- MessageQueue::MessageQueue() { } MessageQueue::~MessageQueue() { } void MessageQueue::init(const sp& flinger) { mFlinger = flinger; mLooper = new Looper(true); mHandler = new Handler(*this); } void MessageQueue::setEventThread(const sp& eventThread) { mEventThread = eventThread; mEvents = eventThread->createEventConnection(); mEventTube = mEvents->getDataChannel(); mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver, this); } void MessageQueue::waitMessage() { do { IPCThreadState::self()->flushCommands(); int32_t ret = mLooper->pollOnce(-1); switch (ret) { case Looper::POLL_WAKE: case Looper::POLL_CALLBACK: continue; case Looper::POLL_ERROR: ALOGE("Looper::POLL_ERROR"); continue; case Looper::POLL_TIMEOUT: // timeout (should not happen) continue; default: // should not happen ALOGE("Looper::pollOnce() returned unknown status %d", ret); continue; } } while (true); } status_t MessageQueue::postMessage( const sp& messageHandler, nsecs_t relTime) { const Message dummyMessage; if (relTime > 0) { mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage); } else { mLooper->sendMessage(messageHandler, dummyMessage); } return NO_ERROR; } /* when INVALIDATE_ON_VSYNC is set SF only processes * buffer updates on VSYNC and performs a refresh immediately * after. * * when INVALIDATE_ON_VSYNC is set to false, SF will instead * perform the buffer updates immediately, but the refresh only * at the next VSYNC. * THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS */ #define INVALIDATE_ON_VSYNC 1 void MessageQueue::invalidate() { #if INVALIDATE_ON_VSYNC mEvents->requestNextVsync(); #else mHandler->dispatchInvalidate(); #endif } void MessageQueue::refresh() { #if INVALIDATE_ON_VSYNC mHandler->dispatchRefresh(); #else mEvents->requestNextVsync(); #endif } int MessageQueue::cb_eventReceiver(int fd, int events, void* data) { MessageQueue* queue = reinterpret_cast(data); return queue->eventReceiver(fd, events); } int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) { ssize_t n; DisplayEventReceiver::Event buffer[8]; while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) { for (int i=0 ; idispatchInvalidate(); #else mHandler->dispatchRefresh(); #endif break; } } } return 1; } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/MessageQueue.h0100644 0000000 0000000 00000005605 13077405420 017201 0ustar000000000 0000000 /* * Copyright (C) 2009 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_MESSAGE_QUEUE_H #define ANDROID_MESSAGE_QUEUE_H #include #include #include #include #include #include #include #include "Barrier.h" namespace android { class IDisplayEventConnection; class EventThread; class SurfaceFlinger; // --------------------------------------------------------------------------- class MessageBase : public MessageHandler { public: MessageBase(); // return true if message has a handler virtual bool handler() = 0; // waits for the handler to be processed void wait() const { barrier.wait(); } protected: virtual ~MessageBase(); private: virtual void handleMessage(const Message& message); mutable Barrier barrier; }; // --------------------------------------------------------------------------- class MessageQueue { class Handler : public MessageHandler { enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 }; MessageQueue& mQueue; int32_t mEventMask; public: Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { } virtual void handleMessage(const Message& message); void dispatchRefresh(); void dispatchInvalidate(); }; friend class Handler; sp mFlinger; sp mLooper; sp mEventThread; sp mEvents; sp mEventTube; sp mHandler; static int cb_eventReceiver(int fd, int events, void* data); int eventReceiver(int fd, int events); public: enum { INVALIDATE = 0, REFRESH = 1, }; MessageQueue(); ~MessageQueue(); void init(const sp& flinger); void setEventThread(const sp& events); void waitMessage(); status_t postMessage(const sp& message, nsecs_t reltime=0); // sends INVALIDATE message at next VSYNC void invalidate(); // sends REFRESH message at next VSYNC void refresh(); }; // --------------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_MESSAGE_QUEUE_H */ services/surfaceflinger/MonitoredProducer.cpp0100644 0000000 0000000 00000012225 13077405420 020603 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MessageQueue.h" #include "MonitoredProducer.h" #include "SurfaceFlinger.h" namespace android { MonitoredProducer::MonitoredProducer(const sp& producer, const sp& flinger) : mProducer(producer), mFlinger(flinger) {} MonitoredProducer::~MonitoredProducer() { // Remove ourselves from SurfaceFlinger's list. We do this asynchronously // because we don't know where this destructor is called from. It could be // called with the mStateLock held, leading to a dead-lock (it actually // happens). class MessageCleanUpList : public MessageBase { public: MessageCleanUpList(const sp& flinger, const wp& producer) : mFlinger(flinger), mProducer(producer) {} virtual ~MessageCleanUpList() {} virtual bool handler() { Mutex::Autolock _l(mFlinger->mStateLock); mFlinger->mGraphicBufferProducerList.remove(mProducer); return true; } private: sp mFlinger; wp mProducer; }; mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(this))); } status_t MonitoredProducer::requestBuffer(int slot, sp* buf) { return mProducer->requestBuffer(slot, buf); } status_t MonitoredProducer::setMaxDequeuedBufferCount( int maxDequeuedBuffers) { return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers); } status_t MonitoredProducer::setAsyncMode(bool async) { return mProducer->setAsyncMode(async); } status_t MonitoredProducer::dequeueBuffer(int* slot, sp* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { return mProducer->dequeueBuffer(slot, fence, w, h, format, usage); } status_t MonitoredProducer::detachBuffer(int slot) { return mProducer->detachBuffer(slot); } status_t MonitoredProducer::detachNextBuffer(sp* outBuffer, sp* outFence) { return mProducer->detachNextBuffer(outBuffer, outFence); } status_t MonitoredProducer::attachBuffer(int* outSlot, const sp& buffer) { return mProducer->attachBuffer(outSlot, buffer); } status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output) { return mProducer->queueBuffer(slot, input, output); } status_t MonitoredProducer::cancelBuffer(int slot, const sp& fence) { return mProducer->cancelBuffer(slot, fence); } int MonitoredProducer::query(int what, int* value) { return mProducer->query(what, value); } status_t MonitoredProducer::connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) { return mProducer->connect(listener, api, producerControlledByApp, output); } status_t MonitoredProducer::disconnect(int api) { return mProducer->disconnect(api); } status_t MonitoredProducer::setSidebandStream(const sp& stream) { return mProducer->setSidebandStream(stream); } void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { mProducer->allocateBuffers(width, height, format, usage); } status_t MonitoredProducer::allowAllocation(bool allow) { return mProducer->allowAllocation(allow); } status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { return mProducer->setGenerationNumber(generationNumber); } String8 MonitoredProducer::getConsumerName() const { return mProducer->getConsumerName(); } uint64_t MonitoredProducer::getNextFrameNumber() const { return mProducer->getNextFrameNumber(); } status_t MonitoredProducer::setSharedBufferMode(bool sharedBufferMode) { return mProducer->setSharedBufferMode(sharedBufferMode); } status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) { return mProducer->setAutoRefresh(autoRefresh); } status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) { return mProducer->setDequeueTimeout(timeout); } status_t MonitoredProducer::getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) { return mProducer->getLastQueuedBuffer(outBuffer, outFence, outTransformMatrix); } status_t MonitoredProducer::getUniqueId(uint64_t* outId) const { return mProducer->getUniqueId(outId); } IBinder* MonitoredProducer::onAsBinder() { return IInterface::asBinder(mProducer).get(); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/MonitoredProducer.h0100644 0000000 0000000 00000006166 13077405420 020257 0ustar000000000 0000000 /* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_MONITORED_PRODUCER_H #define ANDROID_MONITORED_PRODUCER_H #include namespace android { class IProducerListener; class NativeHandle; class SurfaceFlinger; // MonitoredProducer wraps an IGraphicBufferProducer so that SurfaceFlinger will // be notified upon its destruction class MonitoredProducer : public IGraphicBufferProducer { public: MonitoredProducer(const sp& producer, const sp& flinger); virtual ~MonitoredProducer(); // From IGraphicBufferProducer virtual status_t requestBuffer(int slot, sp* buf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* slot, sp* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence); virtual status_t attachBuffer(int* outSlot, const sp& buffer); virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output); virtual status_t cancelBuffer(int slot, const sp& fence); virtual int query(int what, int* value); virtual status_t connect(const sp& token, int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp& stream); virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; virtual uint64_t getNextFrameNumber() const override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override; virtual IBinder* onAsBinder(); virtual status_t setSharedBufferMode(bool sharedBufferMode) override; virtual status_t setAutoRefresh(bool autoRefresh) override; virtual status_t getUniqueId(uint64_t* outId) const override; private: sp mProducer; sp mFlinger; }; }; // namespace android #endif // ANDROID_MONITORED_PRODUCER_H services/surfaceflinger/RenderEngine/0040755 0000000 0000000 00000000000 13077405420 017001 5ustar000000000 0000000 services/surfaceflinger/RenderEngine/Description.cpp0100644 0000000 0000000 00000004367 13077405420 021777 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include #include #include "Description.h" namespace android { Description::Description() : mUniformsDirty(true) { mPlaneAlpha = 1.0f; mPremultipliedAlpha = false; mOpaque = true; mTextureEnabled = false; mColorMatrixEnabled = false; memset(mColor, 0, sizeof(mColor)); } Description::~Description() { } void Description::setPlaneAlpha(GLclampf planeAlpha) { if (planeAlpha != mPlaneAlpha) { mUniformsDirty = true; mPlaneAlpha = planeAlpha; } } void Description::setPremultipliedAlpha(bool premultipliedAlpha) { if (premultipliedAlpha != mPremultipliedAlpha) { mPremultipliedAlpha = premultipliedAlpha; } } void Description::setOpaque(bool opaque) { if (opaque != mOpaque) { mOpaque = opaque; } } void Description::setTexture(const Texture& texture) { mTexture = texture; mTextureEnabled = true; mUniformsDirty = true; } void Description::disableTexture() { mTextureEnabled = false; } void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { mColor[0] = red; mColor[1] = green; mColor[2] = blue; mColor[3] = alpha; mUniformsDirty = true; } void Description::setProjectionMatrix(const mat4& mtx) { mProjectionMatrix = mtx; mUniformsDirty = true; } void Description::setColorMatrix(const mat4& mtx) { const mat4 identity; mColorMatrix = mtx; mColorMatrixEnabled = (mtx != identity); } const mat4& Description::getColorMatrix() const { return mColorMatrix; } } /* namespace android */ services/surfaceflinger/RenderEngine/Description.h0100644 0000000 0000000 00000004122 13077405420 021431 0ustar000000000 0000000 /* * Copyright 2013 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 #include "Texture.h" #ifndef SF_RENDER_ENGINE_DESCRIPTION_H_ #define SF_RENDER_ENGINE_DESCRIPTION_H_ namespace android { class Program; /* * This holds the state of the rendering engine. This class is used * to generate a corresponding GLSL program and set the appropriate * uniform. * * Program and ProgramCache are friends and access the state directly */ class Description { friend class Program; friend class ProgramCache; // value of the plane-alpha, between 0 and 1 GLclampf mPlaneAlpha; // whether textures are premultiplied bool mPremultipliedAlpha; // whether this layer is marked as opaque bool mOpaque; // Texture this layer uses Texture mTexture; bool mTextureEnabled; // color used when texturing is disabled GLclampf mColor[4]; // projection matrix mat4 mProjectionMatrix; bool mColorMatrixEnabled; mat4 mColorMatrix; public: Description(); ~Description(); void setPlaneAlpha(GLclampf planeAlpha); void setPremultipliedAlpha(bool premultipliedAlpha); void setOpaque(bool opaque); void setTexture(const Texture& texture); void disableTexture(); void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); const mat4& getColorMatrix() const; private: bool mUniformsDirty; }; } /* namespace android */ #endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */ services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp0100644 0000000 0000000 00000005073 13077405420 022670 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include "GLES10RenderEngine.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- GLES10RenderEngine::~GLES10RenderEngine() { } void GLES10RenderEngine::setupLayerBlending( #ifdef USE_HWC2 bool premultipliedAlpha, bool opaque, float alpha) { #else bool premultipliedAlpha, bool opaque, int alpha) { #endif // OpenGL ES 1.0 doesn't support texture combiners. // This path doesn't properly handle opaque layers that have non-opaque // alpha values. The alpha channel will be copied into the framebuffer or // screenshot, so if the framebuffer or screenshot is blended on top of // something else, whatever is below the window will incorrectly show // through. #ifdef USE_HWC2 if (CC_UNLIKELY(alpha < 1.0f)) { if (premultipliedAlpha) { glColor4f(alpha, alpha, alpha, alpha); } else { glColor4f(1.0f, 1.0f, 1.0f, alpha); } #else if (CC_UNLIKELY(alpha < 0xFF)) { GLfloat floatAlpha = alpha * (1.0f / 255.0f); if (premultipliedAlpha) { glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); } else { glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); } #endif glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } else { glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } #ifdef USE_HWC2 if (alpha < 1.0f || !opaque) { #else if (alpha < 0xFF || !opaque) { #endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } } // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- services/surfaceflinger/RenderEngine/GLES10RenderEngine.h0100644 0000000 0000000 00000002723 13077405420 022334 0ustar000000000 0000000 /* * Copyright 2013 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 SF_GLES10RENDERENGINE_H_ #define SF_GLES10RENDERENGINE_H_ #include #include #include "GLES11RenderEngine.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class GLES10RenderEngine : public GLES11RenderEngine { virtual ~GLES10RenderEngine(); protected: #ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; #else virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); #endif }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif /* SF_GLES10RENDERENGINE_H_ */ services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp0100644 0000000 0000000 00000022150 13077405420 022664 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include #include #include #include "GLES11RenderEngine.h" #include "Mesh.h" #include "Texture.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- GLES11RenderEngine::GLES11RenderEngine() { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); glEnableClientState(GL_VERTEX_ARRAY); glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_CULL_FACE); const uint16_t protTexData[] = { 0 }; glGenTextures(1, &mProtectedTexName); glBindTexture(GL_TEXTURE_2D, mProtectedTexName); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); } GLES11RenderEngine::~GLES11RenderEngine() { } size_t GLES11RenderEngine::getMaxTextureSize() const { return mMaxTextureSize; } size_t GLES11RenderEngine::getMaxViewportDims() const { return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1]; } void GLES11RenderEngine::setViewportAndProjection( size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) { glViewport(0, 0, vpw, vph); glMatrixMode(GL_PROJECTION); glLoadIdentity(); size_t l = sourceCrop.left; size_t r = sourceCrop.right; // In GL, (0, 0) is the bottom-left corner, so flip y coordinates size_t t = hwh - sourceCrop.top; size_t b = hwh - sourceCrop.bottom; if (yswap) { glOrthof(l, r, t, b, 0, 1); } else { glOrthof(l, r, b, t, 0, 1); } switch (rotation) { case Transform::ROT_0: break; case Transform::ROT_90: glRotatef(90, 0, 0, 1); break; case Transform::ROT_180: glRotatef(180, 0, 0, 1); break; case Transform::ROT_270: glRotatef(270, 0, 0, 1); break; default: break; } glMatrixMode(GL_MODELVIEW); } #ifdef USE_HWC2 void GLES11RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) { #else void GLES11RenderEngine::setupLayerBlending( bool premultipliedAlpha, bool opaque, int alpha) { #endif GLenum combineRGB; GLenum combineAlpha; GLenum src0Alpha; GLfloat envColor[4]; #ifdef USE_HWC2 if (CC_UNLIKELY(alpha < 1.0f)) { #else if (CC_UNLIKELY(alpha < 0xFF)) { #endif // Cv = premultiplied ? Cs*alpha : Cs // Av = !opaque ? As*alpha : As combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; src0Alpha = GL_CONSTANT; #ifdef USE_HWC2 envColor[0] = alpha; #else envColor[0] = alpha * (1.0f / 255.0f); #endif } else { // Cv = Cs // Av = opaque ? 1.0 : As combineRGB = GL_REPLACE; combineAlpha = GL_REPLACE; src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE; envColor[0] = 1.0f; } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB); glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); if (combineRGB == GL_MODULATE) { glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); } glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha); glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); if (combineAlpha == GL_MODULATE) { glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); } if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) { envColor[1] = envColor[0]; envColor[2] = envColor[0]; envColor[3] = envColor[0]; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); } #ifdef USE_HWC2 if (alpha < 1.0f || !opaque) { #else if (alpha < 0xFF || !opaque) { #endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } } #ifdef USE_HWC2 void GLES11RenderEngine::setupDimLayerBlending(float alpha) { #else void GLES11RenderEngine::setupDimLayerBlending(int alpha) { #endif glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); #ifdef USE_HWC2 if (alpha == 1.0f) { #else if (alpha == 0xFF) { #endif glDisable(GL_BLEND); } else { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } #ifdef USE_HWC2 glColor4f(0, 0, 0, alpha); #else glColor4f(0, 0, 0, alpha/255.0f); #endif } void GLES11RenderEngine::setupLayerTexturing(const Texture& texture) { GLuint target = texture.getTextureTarget(); glBindTexture(target, texture.getTextureName()); GLenum filter = GL_NEAREST; if (texture.getFiltering()) { filter = GL_LINEAR; } glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterx(target, GL_TEXTURE_MAG_FILTER, filter); glTexParameterx(target, GL_TEXTURE_MIN_FILTER, filter); glMatrixMode(GL_TEXTURE); glLoadMatrixf(texture.getMatrix().asArray()); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_EXTERNAL_OES); } void GLES11RenderEngine::setupLayerBlackedOut() { glBindTexture(GL_TEXTURE_2D, mProtectedTexName); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_EXTERNAL_OES); glEnable(GL_TEXTURE_2D); } void GLES11RenderEngine::disableTexturing() { glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); } void GLES11RenderEngine::disableBlending() { glDisable(GL_BLEND); } void GLES11RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) { GLuint tname, name; // turn our EGLImage into a texture glGenTextures(1, &tname); glBindTexture(GL_TEXTURE_2D, tname); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); // create a Framebuffer Object to render into glGenFramebuffersOES(1, &name); glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); *status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); *texName = tname; *fbName = name; } void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteFramebuffersOES(1, &fbName); glDeleteTextures(1, &texName); } void GLES11RenderEngine::setupFillWithColor(float r, float g, float b, float a) { glColor4f(r, g, b, a); glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } void GLES11RenderEngine::drawMesh(const Mesh& mesh) { if (mesh.getTexCoordsSize()) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(mesh.getTexCoordsSize(), GL_FLOAT, mesh.getByteStride(), mesh.getTexCoords()); } glVertexPointer(mesh.getVertexSize(), GL_FLOAT, mesh.getByteStride(), mesh.getPositions()); glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); if (mesh.getTexCoordsSize()) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } } void GLES11RenderEngine::dump(String8& result) { RenderEngine::dump(result); } // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #if defined(__gl2_h_) #error "don't include gl2/gl2.h in this file" #endif services/surfaceflinger/RenderEngine/GLES11RenderEngine.h0100644 0000000 0000000 00000005071 13077405420 022334 0ustar000000000 0000000 /* * Copyright 2013 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 SF_GLES11RENDERENGINE_H_ #define SF_GLES11RENDERENGINE_H_ #include #include #include #include #include "RenderEngine.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class String8; class Mesh; class Texture; class GLES11RenderEngine : public RenderEngine { GLuint mProtectedTexName; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status); virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); public: GLES11RenderEngine(); protected: virtual ~GLES11RenderEngine(); virtual void dump(String8& result); virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation); #ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; virtual void setupDimLayerBlending(float alpha) override; #else virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); virtual void setupDimLayerBlending(int alpha); #endif virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a) ; virtual void disableTexturing(); virtual void disableBlending(); virtual void drawMesh(const Mesh& mesh); virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif /* SF_GLES11RENDERENGINE_H_ */ services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp0100644 0000000 0000000 00000020061 13077405420 022663 0ustar000000000 0000000 /* * Copyright 2013 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include "GLES20RenderEngine.h" #include "Program.h" #include "ProgramCache.h" #include "Description.h" #include "Mesh.h" #include "Texture.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- GLES20RenderEngine::GLES20RenderEngine() : mVpWidth(0), mVpHeight(0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); const uint16_t protTexData[] = { 0 }; glGenTextures(1, &mProtectedTexName); glBindTexture(GL_TEXTURE_2D, mProtectedTexName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); //mColorBlindnessCorrection = M; } GLES20RenderEngine::~GLES20RenderEngine() { } size_t GLES20RenderEngine::getMaxTextureSize() const { return mMaxTextureSize; } size_t GLES20RenderEngine::getMaxViewportDims() const { return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1]; } void GLES20RenderEngine::setViewportAndProjection( size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) { size_t l = sourceCrop.left; size_t r = sourceCrop.right; // In GL, (0, 0) is the bottom-left corner, so flip y coordinates size_t t = hwh - sourceCrop.top; size_t b = hwh - sourceCrop.bottom; mat4 m; if (yswap) { m = mat4::ortho(l, r, t, b, 0, 1); } else { m = mat4::ortho(l, r, b, t, 0, 1); } // Apply custom rotation to the projection. float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; switch (rotation) { case Transform::ROT_0: break; case Transform::ROT_90: m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m; break; case Transform::ROT_180: m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m; break; case Transform::ROT_270: m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m; break; default: break; } glViewport(0, 0, vpw, vph); mState.setProjectionMatrix(m); mVpWidth = vpw; mVpHeight = vph; } #ifdef USE_HWC2 void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) { #else void GLES20RenderEngine::setupLayerBlending( bool premultipliedAlpha, bool opaque, int alpha) { #endif mState.setPremultipliedAlpha(premultipliedAlpha); mState.setOpaque(opaque); #ifdef USE_HWC2 mState.setPlaneAlpha(alpha); if (alpha < 1.0f || !opaque) { #else mState.setPlaneAlpha(alpha / 255.0f); if (alpha < 0xFF || !opaque) { #endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } } #ifdef USE_HWC2 void GLES20RenderEngine::setupDimLayerBlending(float alpha) { #else void GLES20RenderEngine::setupDimLayerBlending(int alpha) { #endif mState.setPlaneAlpha(1.0f); mState.setPremultipliedAlpha(true); mState.setOpaque(false); #ifdef USE_HWC2 mState.setColor(0, 0, 0, alpha); #else mState.setColor(0, 0, 0, alpha/255.0f); #endif mState.disableTexture(); #ifdef USE_HWC2 if (alpha == 1.0f) { #else if (alpha == 0xFF) { #endif glDisable(GL_BLEND); } else { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } } void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) { GLuint target = texture.getTextureTarget(); glBindTexture(target, texture.getTextureName()); GLenum filter = GL_NEAREST; if (texture.getFiltering()) { filter = GL_LINEAR; } glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); mState.setTexture(texture); } void GLES20RenderEngine::setupLayerBlackedOut() { glBindTexture(GL_TEXTURE_2D, mProtectedTexName); Texture texture(Texture::TEXTURE_2D, mProtectedTexName); texture.setDimensions(1, 1); // FIXME: we should get that from somewhere mState.setTexture(texture); } mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { mat4 oldTransform = mState.getColorMatrix(); mState.setColorMatrix(colorTransform); return oldTransform; } void GLES20RenderEngine::disableTexturing() { mState.disableTexture(); } void GLES20RenderEngine::disableBlending() { glDisable(GL_BLEND); } void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) { GLuint tname, name; // turn our EGLImage into a texture glGenTextures(1, &tname); glBindTexture(GL_TEXTURE_2D, tname); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); // create a Framebuffer Object to render into glGenFramebuffers(1, &name); glBindFramebuffer(GL_FRAMEBUFFER, name); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); *status = glCheckFramebufferStatus(GL_FRAMEBUFFER); *texName = tname; *fbName = name; } void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbName); glDeleteTextures(1, &texName); } void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) { mState.setPlaneAlpha(1.0f); mState.setPremultipliedAlpha(true); mState.setOpaque(false); mState.setColor(r, g, b, a); mState.disableTexture(); glDisable(GL_BLEND); } void GLES20RenderEngine::drawMesh(const Mesh& mesh) { ProgramCache::getInstance().useProgram(mState); if (mesh.getTexCoordsSize()) { glEnableVertexAttribArray(Program::texCoords); glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE, mesh.getByteStride(), mesh.getTexCoords()); } glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, mesh.getByteStride(), mesh.getPositions()); glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); if (mesh.getTexCoordsSize()) { glDisableVertexAttribArray(Program::texCoords); } } void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #if defined(__gl_h_) #error "don't include gl/gl.h in this file" #endif services/surfaceflinger/RenderEngine/GLES20RenderEngine.h0100644 0000000 0000000 00000005643 13077405420 022341 0ustar000000000 0000000 /* * Copyright 2013 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 SF_GLES20RENDERENGINE_H_ #define SF_GLES20RENDERENGINE_H_ #include #include #include #include #include "RenderEngine.h" #include "ProgramCache.h" #include "Description.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class String8; class Mesh; class Texture; class GLES20RenderEngine : public RenderEngine { GLuint mProtectedTexName; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; GLuint mVpWidth; GLuint mVpHeight; struct Group { GLuint texture; GLuint fbo; GLuint width; GLuint height; mat4 colorTransform; }; Description mState; Vector mGroupStack; virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status); virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); public: GLES20RenderEngine(); protected: virtual ~GLES20RenderEngine(); virtual void dump(String8& result); virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation); #ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; virtual void setupDimLayerBlending(float alpha) override; #else virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); virtual void setupDimLayerBlending(int alpha); #endif virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); virtual mat4 setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); virtual void drawMesh(const Mesh& mesh); virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif /* SF_GLES20RENDERENGINE_H_ */ services/surfaceflinger/RenderEngine/GLExtensions.cpp0100644 0000000 0000000 00000004263 13077405420 022071 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include "GLExtensions.h" namespace android { // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions ) GLExtensions::GLExtensions() : mHaveFramebufferObject(false) { } void GLExtensions::initWithGLStrings( GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version, GLubyte const* extensions) { mVendor = (char const*)vendor; mRenderer = (char const*)renderer; mVersion = (char const*)version; mExtensions = (char const*)extensions; char const* curr = (char const*)extensions; char const* head = curr; do { head = strchr(curr, ' '); String8 s(curr, head ? head-curr : strlen(curr)); if (s.length()) { mExtensionList.add(s); } curr = head+1; } while (head); if (hasExtension("GL_OES_framebuffer_object")) { mHaveFramebufferObject = true; } } bool GLExtensions::hasExtension(char const* extension) const { const String8 s(extension); return mExtensionList.indexOf(s) >= 0; } char const* GLExtensions::getVendor() const { return mVendor.string(); } char const* GLExtensions::getRenderer() const { return mRenderer.string(); } char const* GLExtensions::getVersion() const { return mVersion.string(); } char const* GLExtensions::getExtension() const { return mExtensions.string(); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/RenderEngine/GLExtensions.h0100644 0000000 0000000 00000003754 13077405420 021542 0ustar000000000 0000000 /* * Copyright (C) 2010 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_SF_GLEXTENSION_H #define ANDROID_SF_GLEXTENSION_H #include #include #include #include #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- class GLExtensions : public Singleton { friend class Singleton; bool mHaveFramebufferObject : 1; String8 mVendor; String8 mRenderer; String8 mVersion; String8 mExtensions; SortedVector mExtensionList; GLExtensions(const GLExtensions&); GLExtensions& operator = (const GLExtensions&); protected: GLExtensions(); public: inline bool haveFramebufferObject() const { return mHaveFramebufferObject; } void initWithGLStrings( GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version, GLubyte const* extensions); char const* getVendor() const; char const* getRenderer() const; char const* getVersion() const; char const* getExtension() const; bool hasExtension(char const* extension) const; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_GLEXTENSION_H services/surfaceflinger/RenderEngine/Mesh.cpp0100644 0000000 0000000 00000004755 13077405420 020411 0ustar000000000 0000000 /* * Copyright 2013 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 "Mesh.h" #include namespace android { Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize), mPrimitive(primitive) { if (vertexCount == 0) { mVertices = new float[1]; mVertices[0] = 0.0f; mStride = 0; return; } size_t stride = vertexSize + texCoordSize; size_t remainder = (stride * vertexCount) / vertexCount; // Since all of the input parameters are unsigned, if stride is less than // either vertexSize or texCoordSize, it must have overflowed. remainder // will be equal to stride as long as stride * vertexCount doesn't overflow. if ((stride < vertexSize) || (remainder != stride)) { ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize); mVertices = new float[1]; mVertices[0] = 0.0f; mVertexCount = 0; mVertexSize = 0; mTexCoordsSize = 0; mStride = 0; return; } mVertices = new float[stride * vertexCount]; mStride = stride; } Mesh::~Mesh() { delete [] mVertices; } Mesh::Primitive Mesh::getPrimitive() const { return mPrimitive; } float const* Mesh::getPositions() const { return mVertices; } float* Mesh::getPositions() { return mVertices; } float const* Mesh::getTexCoords() const { return mVertices + mVertexSize; } float* Mesh::getTexCoords() { return mVertices + mVertexSize; } size_t Mesh::getVertexCount() const { return mVertexCount; } size_t Mesh::getVertexSize() const { return mVertexSize; } size_t Mesh::getTexCoordsSize() const { return mTexCoordsSize; } size_t Mesh::getByteStride() const { return mStride*sizeof(float); } size_t Mesh::getStride() const { return mStride; } } /* namespace android */ services/surfaceflinger/RenderEngine/Mesh.h0100644 0000000 0000000 00000005406 13077405420 020050 0ustar000000000 0000000 /* * Copyright 2013 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 SF_RENDER_ENGINE_MESH_H #define SF_RENDER_ENGINE_MESH_H #include namespace android { class Mesh { public: enum Primitive { TRIANGLES = 0x0004, // GL_TRIANGLES TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN }; Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0); ~Mesh(); /* * VertexArray handles the stride automatically. */ template class VertexArray { friend class Mesh; float* mData; size_t mStride; VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { } public: TYPE& operator[](size_t index) { return *reinterpret_cast(&mData[index*mStride]); } TYPE const& operator[](size_t index) const { return *reinterpret_cast(&mData[index*mStride]); } }; template VertexArray getPositionArray() { return VertexArray(getPositions(), mStride); } template VertexArray getTexCoordArray() { return VertexArray(getTexCoords(), mStride); } Primitive getPrimitive() const; // returns a pointer to the vertices positions float const* getPositions() const; // returns a pointer to the vertices texture coordinates float const* getTexCoords() const; // number of vertices in this mesh size_t getVertexCount() const; // dimension of vertices size_t getVertexSize() const; // dimension of texture coordinates size_t getTexCoordsSize() const; // return stride in bytes size_t getByteStride() const; // return stride in floats size_t getStride() const; private: Mesh(const Mesh&); Mesh& operator = (const Mesh&); Mesh const& operator = (const Mesh&) const; float* getPositions(); float* getTexCoords(); float* mVertices; size_t mVertexCount; size_t mVertexSize; size_t mTexCoordsSize; size_t mStride; Primitive mPrimitive; }; } /* namespace android */ #endif /* SF_RENDER_ENGINE_MESH_H */ services/surfaceflinger/RenderEngine/Program.cpp0100644 0000000 0000000 00000011517 13077405420 021116 0ustar000000000 0000000 /*Gluint * Copyright 2013 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 #include #include "Program.h" #include "ProgramCache.h" #include "Description.h" #include namespace android { Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment) : mInitialized(false) { GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER); GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER); GLuint programId = glCreateProgram(); glAttachShader(programId, vertexId); glAttachShader(programId, fragmentId); glBindAttribLocation(programId, position, "position"); glBindAttribLocation(programId, texCoords, "texCoords"); glLinkProgram(programId); GLint status; glGetProgramiv(programId, GL_LINK_STATUS, &status); if (status != GL_TRUE) { ALOGE("Error while linking shaders:"); GLint infoLen = 0; glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen > 1) { GLchar log[infoLen]; glGetProgramInfoLog(programId, infoLen, 0, &log[0]); ALOGE("%s", log); } glDetachShader(programId, vertexId); glDetachShader(programId, fragmentId); glDeleteShader(vertexId); glDeleteShader(fragmentId); glDeleteProgram(programId); } else { mProgram = programId; mVertexShader = vertexId; mFragmentShader = fragmentId; mInitialized = true; mColorMatrixLoc = glGetUniformLocation(programId, "colorMatrix"); mProjectionMatrixLoc = glGetUniformLocation(programId, "projection"); mTextureMatrixLoc = glGetUniformLocation(programId, "texture"); mSamplerLoc = glGetUniformLocation(programId, "sampler"); mColorLoc = glGetUniformLocation(programId, "color"); mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane"); // set-up the default values for our uniforms glUseProgram(programId); const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m); glEnableVertexAttribArray(0); } } Program::~Program() { } bool Program::isValid() const { return mInitialized; } void Program::use() { glUseProgram(mProgram); } GLuint Program::getAttrib(const char* name) const { // TODO: maybe use a local cache return glGetAttribLocation(mProgram, name); } GLint Program::getUniform(const char* name) const { // TODO: maybe use a local cache return glGetUniformLocation(mProgram, name); } GLuint Program::buildShader(const char* source, GLenum type) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, 0); glCompileShader(shader); GLint status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { // Some drivers return wrong values for GL_INFO_LOG_LENGTH // use a fixed size instead GLchar log[512]; glGetShaderInfoLog(shader, sizeof(log), 0, log); ALOGE("Error while compiling shader: \n%s\n%s", source, log); glDeleteShader(shader); return 0; } return shader; } String8& Program::dumpShader(String8& result, GLenum /*type*/) { GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader; GLint l; glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l); char* src = new char[l]; glGetShaderSource(shader, l, NULL, src); result.append(src); delete [] src; return result; } void Program::setUniforms(const Description& desc) { // TODO: we should have a mechanism here to not always reset uniforms that // didn't change for this program. if (mSamplerLoc >= 0) { glUniform1i(mSamplerLoc, 0); glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray()); } if (mAlphaPlaneLoc >= 0) { glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha); } if (mColorLoc >= 0) { glUniform4fv(mColorLoc, 1, desc.mColor); } if (mColorMatrixLoc >= 0) { glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray()); } // these uniforms are always present glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray()); } } /* namespace android */ services/surfaceflinger/RenderEngine/Program.h0100644 0000000 0000000 00000004520 13077405420 020557 0ustar000000000 0000000 /* * Copyright 2013 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 SF_RENDER_ENGINE_PROGRAM_H #define SF_RENDER_ENGINE_PROGRAM_H #include #include #include "Description.h" #include "ProgramCache.h" namespace android { class String8; /* * Abstracts a GLSL program comprising a vertex and fragment shader */ class Program { public: // known locations for position and texture coordinates enum { position=0, texCoords=1 }; Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment); ~Program(); /* whether this object is usable */ bool isValid() const; /* Binds this program to the GLES context */ void use(); /* Returns the location of the specified attribute */ GLuint getAttrib(const char* name) const; /* Returns the location of the specified uniform */ GLint getUniform(const char* name) const; /* set-up uniforms from the description */ void setUniforms(const Description& desc); private: GLuint buildShader(const char* source, GLenum type); String8& dumpShader(String8& result, GLenum type); // whether the initialization succeeded bool mInitialized; // Name of the OpenGL program and shaders GLuint mProgram; GLuint mVertexShader; GLuint mFragmentShader; /* location of the projection matrix uniform */ GLint mProjectionMatrixLoc; /* location of the color matrix uniform */ GLint mColorMatrixLoc; /* location of the texture matrix uniform */ GLint mTextureMatrixLoc; /* location of the sampler uniform */ GLint mSamplerLoc; /* location of the alpha plane uniform */ GLint mAlphaPlaneLoc; /* location of the color uniform */ GLint mColorLoc; }; } /* namespace android */ #endif /* SF_RENDER_ENGINE_PROGRAM_H */ services/surfaceflinger/RenderEngine/ProgramCache.cpp0100644 0000000 0000000 00000020064 13077405420 022037 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include "ProgramCache.h" #include "Program.h" #include "Description.h" namespace android { // ----------------------------------------------------------------------------------------------- /* * A simple formatter class to automatically add the endl and * manage the indentation. */ class Formatter; static Formatter& indent(Formatter& f); static Formatter& dedent(Formatter& f); class Formatter { String8 mString; int mIndent; typedef Formatter& (*FormaterManipFunc)(Formatter&); friend Formatter& indent(Formatter& f); friend Formatter& dedent(Formatter& f); public: Formatter() : mIndent(0) {} String8 getString() const { return mString; } friend Formatter& operator << (Formatter& out, const char* in) { for (int i=0 ; i(timeAfter - timeBefore) / 1.0E6; ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); } ProgramCache::Key ProgramCache::computeKey(const Description& description) { Key needs; needs.set(Key::TEXTURE_MASK, !description.mTextureEnabled ? Key::TEXTURE_OFF : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT : description.mTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D : Key::TEXTURE_OFF) .set(Key::PLANE_ALPHA_MASK, (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE) .set(Key::BLEND_MASK, description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) .set(Key::OPACITY_MASK, description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) .set(Key::COLOR_MATRIX_MASK, description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF); return needs; } String8 ProgramCache::generateVertexShader(const Key& needs) { Formatter vs; if (needs.isTexturing()) { vs << "attribute vec4 texCoords;" << "varying vec2 outTexCoords;"; } vs << "attribute vec4 position;" << "uniform mat4 projection;" << "uniform mat4 texture;" << "void main(void) {" << indent << "gl_Position = projection * position;"; if (needs.isTexturing()) { vs << "outTexCoords = (texture * texCoords).st;"; } vs << dedent << "}"; return vs.getString(); } String8 ProgramCache::generateFragmentShader(const Key& needs) { Formatter fs; if (needs.getTextureTarget() == Key::TEXTURE_EXT) { fs << "#extension GL_OES_EGL_image_external : require"; } // default precision is required-ish in fragment shaders fs << "precision mediump float;"; if (needs.getTextureTarget() == Key::TEXTURE_EXT) { fs << "uniform samplerExternalOES sampler;" << "varying vec2 outTexCoords;"; } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { fs << "uniform sampler2D sampler;" << "varying vec2 outTexCoords;"; } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { fs << "uniform vec4 color;"; } if (needs.hasPlaneAlpha()) { fs << "uniform float alphaPlane;"; } if (needs.hasColorMatrix()) { fs << "uniform mat4 colorMatrix;"; } fs << "void main(void) {" << indent; if (needs.isTexturing()) { fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; } else { fs << "gl_FragColor = color;"; } if (needs.isOpaque()) { fs << "gl_FragColor.a = 1.0;"; } if (needs.hasPlaneAlpha()) { // modulate the alpha value with planeAlpha if (needs.isPremultiplied()) { // ... and the color too if we're premultiplied fs << "gl_FragColor *= alphaPlane;"; } else { fs << "gl_FragColor.a *= alphaPlane;"; } } if (needs.hasColorMatrix()) { if (!needs.isOpaque() && needs.isPremultiplied()) { // un-premultiply if needed before linearization fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; } fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);"; fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;"; if (!needs.isOpaque() && needs.isPremultiplied()) { // and re-premultiply if needed after gamma correction fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; } } fs << dedent << "}"; return fs.getString(); } Program* ProgramCache::generateProgram(const Key& needs) { // vertex shader String8 vs = generateVertexShader(needs); // fragment shader String8 fs = generateFragmentShader(needs); Program* program = new Program(needs, vs.string(), fs.string()); return program; } void ProgramCache::useProgram(const Description& description) { // generate the key for the shader based on the description Key needs(computeKey(description)); // look-up the program in the cache Program* program = mCache.valueFor(needs); if (program == NULL) { // we didn't find our program, so generate one... nsecs_t time = -systemTime(); program = generateProgram(needs); mCache.add(needs, program); time += systemTime(); //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); } // here we have a suitable program for this description if (program->isValid()) { program->use(); program->setUniforms(description); } } } /* namespace android */ services/surfaceflinger/RenderEngine/ProgramCache.h0100644 0000000 0000000 00000010516 13077405420 021505 0ustar000000000 0000000 /* * Copyright 2013 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 SF_RENDER_ENGINE_PROGRAMCACHE_H #define SF_RENDER_ENGINE_PROGRAMCACHE_H #include #include #include #include #include "Description.h" namespace android { class Description; class Program; class String8; /* * This class generates GLSL programs suitable to handle a given * Description. It's responsible for figuring out what to * generate from a Description. * It also maintains a cache of these Programs. */ class ProgramCache : public Singleton { public: /* * Key is used to retrieve a Program in the cache. * A Key is generated from a Description. */ class Key { friend class ProgramCache; typedef uint32_t key_t; key_t mKey; public: enum { BLEND_PREMULT = 0x00000001, BLEND_NORMAL = 0x00000000, BLEND_MASK = 0x00000001, OPACITY_OPAQUE = 0x00000002, OPACITY_TRANSLUCENT = 0x00000000, OPACITY_MASK = 0x00000002, PLANE_ALPHA_LT_ONE = 0x00000004, PLANE_ALPHA_EQ_ONE = 0x00000000, PLANE_ALPHA_MASK = 0x00000004, TEXTURE_OFF = 0x00000000, TEXTURE_EXT = 0x00000008, TEXTURE_2D = 0x00000010, TEXTURE_MASK = 0x00000018, COLOR_MATRIX_OFF = 0x00000000, COLOR_MATRIX_ON = 0x00000020, COLOR_MATRIX_MASK = 0x00000020, }; inline Key() : mKey(0) { } inline Key(const Key& rhs) : mKey(rhs.mKey) { } inline Key& set(key_t mask, key_t value) { mKey = (mKey & ~mask) | value; return *this; } inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; } inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); } inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; } inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; } inline bool hasPlaneAlpha() const { return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE; } inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; } // this is the definition of a friend function -- not a method of class Needs friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { return (lhs.mKey < rhs.mKey) ? 1 : 0; } }; ProgramCache(); ~ProgramCache(); // useProgram lookup a suitable program in the cache or generates one // if none can be found. void useProgram(const Description& description); private: // Generate shaders to populate the cache void primeCache(); // compute a cache Key from a Description static Key computeKey(const Description& description); // generates a program from the Key static Program* generateProgram(const Key& needs); // generates the vertex shader from the Key static String8 generateVertexShader(const Key& needs); // generates the fragment shader from the Key static String8 generateFragmentShader(const Key& needs); // Key/Value map used for caching Programs. Currently the cache // is never shrunk. DefaultKeyedVector mCache; }; ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key) } /* namespace android */ #endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */ services/surfaceflinger/RenderEngine/RenderEngine.cpp0100644 0000000 0000000 00000035571 13077405420 022062 0ustar000000000 0000000 /* * Copyright 2013 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 #include #include #include "RenderEngine.h" #include "GLES10RenderEngine.h" #include "GLES11RenderEngine.h" #include "GLES20RenderEngine.h" #include "GLExtensions.h" #include "Mesh.h" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- static bool findExtension(const char* exts, const char* name) { if (!exts) return false; size_t len = strlen(name); const char* pos = exts; while ((pos = strstr(pos, name)) != NULL) { if (pos[len] == '\0' || pos[len] == ' ') return true; pos += len; } return false; } RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { // EGL_ANDROIDX_no_config_context is an experimental extension with no // written specification. It will be replaced by something more formal. // SurfaceFlinger is using it to allow a single EGLContext to render to // both a 16-bit primary display framebuffer and a 32-bit virtual display // framebuffer. // // The code assumes that ES2 or later is available if this extension is // supported. EGLConfig config = EGL_NO_CONFIG; if (!findExtension( eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), "EGL_ANDROIDX_no_config_context")) { config = chooseEglConfig(display, hwcFormat); } EGLint renderableType = 0; if (config == EGL_NO_CONFIG) { renderableType = EGL_OPENGL_ES2_BIT; } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); } EGLint contextClientVersion = 0; if (renderableType & EGL_OPENGL_ES2_BIT) { contextClientVersion = 2; } else if (renderableType & EGL_OPENGL_ES_BIT) { contextClientVersion = 1; } else { LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs"); } // Also create our EGLContext EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, contextClientVersion, // MUST be first #ifdef EGL_IMG_context_priority #ifdef HAS_CONTEXT_PRIORITY #warning "using EGL_IMG_context_priority" EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, #endif #endif EGL_NONE, EGL_NONE }; EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); // if can't create a GL context, we can only abort. LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); // now figure out what version of GL did we actually get // NOTE: a dummy surface is not needed if KHR_create_context is supported EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { dummyConfig = chooseEglConfig(display, hwcFormat); } EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs); LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer"); EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); GLExtensions& extensions(GLExtensions::getInstance()); extensions.initWithGLStrings( glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); GlesVersion version = parseGlesVersion( extensions.getVersion() ); // initialize the renderer while GL is current RenderEngine* engine = NULL; switch (version) { case GLES_VERSION_1_0: engine = new GLES10RenderEngine(); break; case GLES_VERSION_1_1: engine = new GLES11RenderEngine(); break; case GLES_VERSION_2_0: case GLES_VERSION_3_0: engine = new GLES20RenderEngine(); break; } engine->setEGLHandles(config, ctxt); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); ALOGI("renderer : %s", extensions.getRenderer()); ALOGI("version : %s", extensions.getVersion()); ALOGI("extensions: %s", extensions.getExtension()); ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(display, dummy); return engine; } RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) { } RenderEngine::~RenderEngine() { } void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) { mEGLConfig = config; mEGLContext = ctxt; } EGLContext RenderEngine::getEGLConfig() const { return mEGLConfig; } EGLContext RenderEngine::getEGLContext() const { return mEGLContext; } void RenderEngine::checkErrors() const { do { // there could be more than one error flag GLenum error = glGetError(); if (error == GL_NO_ERROR) break; ALOGE("GL error 0x%04x", int(error)); } while (true); } RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) { int major, minor; if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) { ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); return GLES_VERSION_1_0; } } if (major == 1 && minor == 0) return GLES_VERSION_1_0; if (major == 1 && minor >= 1) return GLES_VERSION_1_1; if (major == 2 && minor >= 0) return GLES_VERSION_2_0; if (major == 3 && minor >= 0) return GLES_VERSION_3_0; ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); return GLES_VERSION_1_0; } void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red, float green, float blue, float alpha) { size_t c; Rect const* r = region.getArray(&c); Mesh mesh(Mesh::TRIANGLES, c*6, 2); Mesh::VertexArray position(mesh.getPositionArray()); for (size_t i=0 ; ileft; position[i*6 + 0].y = height - r->top; position[i*6 + 1].x = r->left; position[i*6 + 1].y = height - r->bottom; position[i*6 + 2].x = r->right; position[i*6 + 2].y = height - r->bottom; position[i*6 + 3].x = r->left; position[i*6 + 3].y = height - r->top; position[i*6 + 4].x = r->right; position[i*6 + 4].y = height - r->bottom; position[i*6 + 5].x = r->right; position[i*6 + 5].y = height - r->top; } setupFillWithColor(red, green, blue, alpha); drawMesh(mesh); } void RenderEngine::flush() { glFlush(); } void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) { glClearColor(red, green, blue, alpha); glClear(GL_COLOR_BUFFER_BIT); } void RenderEngine::setScissor( uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) { glScissor(left, bottom, right, top); glEnable(GL_SCISSOR_TEST); } void RenderEngine::disableScissor() { glDisable(GL_SCISSOR_TEST); } void RenderEngine::genTextures(size_t count, uint32_t* names) { glGenTextures(count, names); } void RenderEngine::deleteTextures(size_t count, uint32_t const* names) { glDeleteTextures(count, names); } void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) { glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } void RenderEngine::dump(String8& result) { const GLExtensions& extensions(GLExtensions::getInstance()); result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), extensions.getVersion()); result.appendFormat("%s\n", extensions.getExtension()); } // --------------------------------------------------------------------------- RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( RenderEngine& engine, EGLImageKHR image) : mEngine(engine) { mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus); ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", mStatus); } RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() { // back to main framebuffer mEngine.unbindFramebuffer(mTexName, mFbName); } status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; } // --------------------------------------------------------------------------- static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint wanted, EGLConfig* outConfig) { EGLint numConfigs = -1, n = 0; eglGetConfigs(dpy, NULL, 0, &numConfigs); EGLConfig* const configs = new EGLConfig[numConfigs]; eglChooseConfig(dpy, attrs, configs, numConfigs, &n); if (n) { if (attribute != EGL_NONE) { for (int i=0 ; i mList; struct Attribute { Attribute() : v(0) {}; Attribute(EGLint v) : v(v) { } EGLint v; bool operator < (const Attribute& other) const { // this places EGL_NONE at the end EGLint lhs(v); EGLint rhs(other.v); if (lhs == EGL_NONE) lhs = 0x7FFFFFFF; if (rhs == EGL_NONE) rhs = 0x7FFFFFFF; return lhs < rhs; } }; class Adder { friend class EGLAttributeVector; EGLAttributeVector& v; EGLint attribute; Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) { } public: void operator = (EGLint value) { if (attribute != EGL_NONE) { v.mList.add(attribute, value); } } operator EGLint () const { return v.mList[attribute]; } }; public: EGLAttributeVector() { mList.add(EGL_NONE, EGL_NONE); } void remove(EGLint attribute) { if (attribute != EGL_NONE) { mList.removeItem(attribute); } } Adder operator [] (EGLint attribute) { return Adder(*this, attribute); } EGLint operator [] (EGLint attribute) const { return mList[attribute]; } // cast-operator to (EGLint const*) operator EGLint const* () const { return &mList.keyAt(0).v; } }; static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, EGLConfig* config) { // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if // it is to be used with WIFI displays status_t err; EGLint wantedAttribute; EGLint wantedAttributeValue; EGLAttributeVector attribs; if (renderableType) { attribs[EGL_RENDERABLE_TYPE] = renderableType; attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT|EGL_PBUFFER_BIT; attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; attribs[EGL_RED_SIZE] = 8; attribs[EGL_GREEN_SIZE] = 8; attribs[EGL_BLUE_SIZE] = 8; wantedAttribute = EGL_NONE; wantedAttributeValue = EGL_NONE; } else { // if no renderable type specified, fallback to a simplified query wantedAttribute = EGL_NATIVE_VISUAL_ID; wantedAttributeValue = format; } err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config); if (err == NO_ERROR) { EGLint caveat; if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); } return err; } EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) { status_t err; EGLConfig config; // First try to get an ES2 config err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config); if (err != NO_ERROR) { // If ES2 fails, try ES1 err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config); if (err != NO_ERROR) { // still didn't work, probably because we're on the emulator... // try a simplified query ALOGW("no suitable EGLConfig found, trying a simpler query"); err = selectEGLConfig(display, format, 0, &config); if (err != NO_ERROR) { // this EGL is too lame for android LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); } } } // print some debugging info EGLint r,g,b,a; eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); ALOGI("EGL information:"); ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); return config; } // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- services/surfaceflinger/RenderEngine/RenderEngine.h0100644 0000000 0000000 00000010213 13077405420 021511 0ustar000000000 0000000 /* * Copyright 2013 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 SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ #include #include #include #include #include #include #define EGL_NO_CONFIG ((EGLConfig)0) // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class String8; class Rect; class Region; class Mesh; class Texture; class RenderEngine { enum GlesVersion { GLES_VERSION_1_0 = 0x10000, GLES_VERSION_1_1 = 0x10001, GLES_VERSION_2_0 = 0x20000, GLES_VERSION_3_0 = 0x30000, }; static GlesVersion parseGlesVersion(const char* str); EGLConfig mEGLConfig; EGLContext mEGLContext; void setEGLHandles(EGLConfig config, EGLContext ctxt); virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0; virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0; protected: RenderEngine(); virtual ~RenderEngine() = 0; public: static RenderEngine* create(EGLDisplay display, int hwcFormat); static EGLConfig chooseEglConfig(EGLDisplay display, int format); // dump the extension strings. always call the base class. virtual void dump(String8& result); // helpers void flush(); void clearWithColor(float red, float green, float blue, float alpha); void fillRegionWithColor(const Region& region, uint32_t height, float red, float green, float blue, float alpha); // common to all GL versions void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top); void disableScissor(); void genTextures(size_t count, uint32_t* names); void deleteTextures(size_t count, uint32_t const* names); void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels); class BindImageAsFramebuffer { RenderEngine& mEngine; uint32_t mTexName, mFbName; uint32_t mStatus; public: BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image); ~BindImageAsFramebuffer(); int getStatus() const; }; // set-up virtual void checkErrors() const; virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0; #ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0; virtual void setupDimLayerBlending(float alpha) = 0; #else virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0; virtual void setupDimLayerBlending(int alpha) = 0; #endif virtual void setupLayerTexturing(const Texture& texture) = 0; virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { return mat4(); } virtual void disableTexturing() = 0; virtual void disableBlending() = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; EGLConfig getEGLConfig() const; EGLContext getEGLContext() const; }; // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- #endif /* SF_RENDERENGINE_H_ */ services/surfaceflinger/RenderEngine/Texture.cpp0100644 0000000 0000000 00000003455 13077405420 021151 0ustar000000000 0000000 /* * Copyright 2013 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 #include "Texture.h" namespace android { Texture::Texture() : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) { } Texture::Texture(Target textureTarget, uint32_t textureName) : mTextureName(textureName), mTextureTarget(textureTarget), mWidth(0), mHeight(0), mFiltering(false) { } void Texture::init(Target textureTarget, uint32_t textureName) { mTextureName = textureName; mTextureTarget = textureTarget; } Texture::~Texture() { } void Texture::setMatrix(float const* matrix) { mTextureMatrix = mat4(matrix); } void Texture::setFiltering(bool enabled) { mFiltering = enabled; } void Texture::setDimensions(size_t width, size_t height) { mWidth = width; mHeight = height; } uint32_t Texture::getTextureName() const { return mTextureName; } uint32_t Texture::getTextureTarget() const { return mTextureTarget; } const mat4& Texture::getMatrix() const { return mTextureMatrix; } bool Texture::getFiltering() const { return mFiltering; } size_t Texture::getWidth() const { return mWidth; } size_t Texture::getHeight() const { return mHeight; } } /* namespace android */ services/surfaceflinger/RenderEngine/Texture.h0100644 0000000 0000000 00000003003 13077405420 020603 0ustar000000000 0000000 /* * Copyright 2013 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 #include #ifndef SF_RENDER_ENGINE_TEXTURE_H #define SF_RENDER_ENGINE_TEXTURE_H namespace android { class Texture { uint32_t mTextureName; uint32_t mTextureTarget; size_t mWidth; size_t mHeight; bool mFiltering; mat4 mTextureMatrix; public: enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 }; Texture(); Texture(Target textureTarget, uint32_t textureName); ~Texture(); void init(Target textureTarget, uint32_t textureName); void setMatrix(float const* matrix); void setFiltering(bool enabled); void setDimensions(size_t width, size_t height); uint32_t getTextureName() const; uint32_t getTextureTarget() const; const mat4& getMatrix() const; bool getFiltering() const; size_t getWidth() const; size_t getHeight() const; }; } /* namespace android */ #endif /* SF_RENDER_ENGINE_TEXTURE_H */ services/surfaceflinger/SurfaceFlinger.cpp0100644 0000000 0000000 00000403060 13077405420 020037 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ // #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Client.h" #include "clz.h" #include "Colorizer.h" #include "DdmConnection.h" #include "DisplayDevice.h" #include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" #include "Layer.h" #include "LayerDim.h" #include "SurfaceFlinger.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "Effects/Daltonizer.h" #include "RenderEngine/RenderEngine.h" #include #define DISPLAY_COUNT 1 /* * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all * black pixels. */ #define DEBUG_SCREENSHOTS false EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { // This is the phase offset in nanoseconds of the software vsync event // relative to the vsync event reported by HWComposer. The software vsync // event is when SurfaceFlinger and Choreographer-based applications run each // frame. // // This phase offset allows adjustment of the minimum latency from application // wake-up (by Choregographer) time to the time at which the resulting window // image is displayed. This value may be either positive (after the HW vsync) // or negative (before the HW vsync). Setting it to 0 will result in a // minimum latency of two vsync periods because the app and SurfaceFlinger // will run just after the HW vsync. Setting it to a positive number will // result in the minimum latency being: // // (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD)) // // Note that reducing this latency makes it more likely for the applications // to not have their window content image ready in time. When this happens // the latency will end up being an additional vsync period, and animations // will hiccup. Therefore, this latency should be tuned somewhat // conservatively (or at least with awareness of the trade-off being made). static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS; // This is the phase offset at which SurfaceFlinger's composition runs. static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS; // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); // --------------------------------------------------------------------------- SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), mTransactionPending(false), mAnimTransactionPending(false), mLayersRemoved(false), mRepaintEverything(0), mRenderEngine(NULL), mBootTime(systemTime()), mBuiltinDisplays(), mVisibleRegionsDirty(false), mGeometryInvalid(false), mAnimCompositionPending(false), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), mDebugDisableTransformHint(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), mLastTransactionTime(0), mBootFinished(false), mForceFullDamage(false), mPrimaryDispSync("PrimaryDispSync"), mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), mHasColorMatrix(false), mHasPoweredOff(false), mFrameBuckets(), mTotalTime(0), mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); // debugging stuff... char value[PROPERTY_VALUE_MAX]; property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); property_get("debug.sf.drop_missed_frames", value, "0"); mDropMissedFrames = atoi(value); property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); property_get("debug.sf.ddms", value, "0"); mDebugDDMS = atoi(value); if (mDebugDDMS) { if (!startDdmConnection()) { // start failed, and DDMS debugging not enabled mDebugDDMS = 0; } } ALOGI_IF(mDebugRegion, "showupdates enabled"); ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); } void SurfaceFlinger::onFirstRef() { mEventQueue.init(this); } SurfaceFlinger::~SurfaceFlinger() { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(display); } void SurfaceFlinger::binderDied(const wp& /* who */) { // the window manager died on us. prepare its eulogy. // restore initial conditions (default device unblank, etc) initializeDisplays(); // restart the boot-animation startBootAnim(); } sp SurfaceFlinger::createConnection() { sp bclient; sp client(new Client(this)); status_t err = client->initCheck(); if (err == NO_ERROR) { bclient = client; } return bclient; } sp SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { class DisplayToken : public BBinder { sp flinger; virtual ~DisplayToken() { // no more references, this display must be terminated Mutex::Autolock _l(flinger->mStateLock); flinger->mCurrentState.displays.removeItem(this); flinger->setTransactionFlags(eDisplayTransactionNeeded); } public: DisplayToken(const sp& flinger) : flinger(flinger) { } }; sp token = new DisplayToken(this); Mutex::Autolock _l(mStateLock); DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); info.displayName = displayName; mCurrentState.displays.add(token, info); return token; } void SurfaceFlinger::destroyDisplay(const sp& display) { Mutex::Autolock _l(mStateLock); ssize_t idx = mCurrentState.displays.indexOfKey(display); if (idx < 0) { ALOGW("destroyDisplay: invalid display token"); return; } const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx)); if (!info.isVirtualDisplay()) { ALOGE("destroyDisplay called for non-virtual display"); return; } mCurrentState.displays.removeItemsAt(idx); setTransactionFlags(eDisplayTransactionNeeded); } void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) { ALOGV("createBuiltinDisplayLocked(%d)", type); ALOGW_IF(mBuiltinDisplays[type], "Overwriting display token for display type %d", type); mBuiltinDisplays[type] = new BBinder(); // All non-virtual displays are currently considered secure. DisplayDeviceState info(type, true); mCurrentState.displays.add(mBuiltinDisplays[type], info); } sp SurfaceFlinger::getBuiltInDisplay(int32_t id) { if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); return NULL; } return mBuiltinDisplays[id]; } sp SurfaceFlinger::createGraphicBufferAlloc() { sp gba(new GraphicBufferAlloc()); return gba; } void SurfaceFlinger::bootFinished() { const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mBootFinished = true; // wait patiently for the window manager death const String16 name("window"); sp window(defaultServiceManager()->getService(name)); if (window != 0) { window->linkToDeath(static_cast(this)); } // stop boot animation // formerly we would just kill the process, but we now ask it to exit so it // can choose where to stop the animation. property_set("service.bootanim.exit", "1"); const int LOGTAG_SF_STOP_BOOTANIM = 60110; LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { class MessageDestroyGLTexture : public MessageBase { RenderEngine& engine; uint32_t texture; public: MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture) : engine(engine), texture(texture) { } virtual bool handler() { engine.deleteTextures(1, &texture); return true; } }; postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture)); } class DispSyncSource : public VSyncSource, private DispSync::Callback { public: DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name) : mName(name), mValue(0), mTraceVsync(traceVsync), mVsyncOnLabel(String8::format("VsyncOn-%s", name)), mVsyncEventLabel(String8::format("VSYNC-%s", name)), mDispSync(dispSync), mCallbackMutex(), mCallback(), mVsyncMutex(), mPhaseOffset(phaseOffset), mEnabled(false) {} virtual ~DispSyncSource() {} virtual void setVSyncEnabled(bool enable) { Mutex::Autolock lock(mVsyncMutex); if (enable) { status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } //ATRACE_INT(mVsyncOnLabel.string(), 1); } else { status_t err = mDispSync->removeEventListener( static_cast(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } //ATRACE_INT(mVsyncOnLabel.string(), 0); } mEnabled = enable; } virtual void setCallback(const sp& callback) { Mutex::Autolock lock(mCallbackMutex); mCallback = callback; } virtual void setPhaseOffset(nsecs_t phaseOffset) { Mutex::Autolock lock(mVsyncMutex); // Normalize phaseOffset to [0, period) auto period = mDispSync->getPeriod(); phaseOffset %= period; if (phaseOffset < 0) { // If we're here, then phaseOffset is in (-period, 0). After this // operation, it will be in (0, period) phaseOffset += period; } mPhaseOffset = phaseOffset; // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { return; } // Remove the listener with the old offset status_t err = mDispSync->removeEventListener( static_cast(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } // Add a listener with the new offset err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } } private: virtual void onDispSyncEvent(nsecs_t when) { sp callback; { Mutex::Autolock lock(mCallbackMutex); callback = mCallback; if (mTraceVsync) { mValue = (mValue + 1) % 2; ATRACE_INT(mVsyncEventLabel.string(), mValue); } } if (callback != NULL) { callback->onVSyncEvent(when); } } const char* const mName; int mValue; const bool mTraceVsync; const String8 mVsyncOnLabel; const String8 mVsyncEventLabel; DispSync* mDispSync; Mutex mCallbackMutex; // Protects the following sp mCallback; Mutex mVsyncMutex; // Protects the following nsecs_t mPhaseOffset; bool mEnabled; }; void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); { // Autolock scope Mutex::Autolock _l(mStateLock); // initialize EGL for the default display mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(mEGLDisplay, NULL, NULL); // start the EventThread sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true, "app"); mEventThread = new EventThread(vsyncSrc, *this); sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, sfVsyncPhaseOffsetNs, true, "sf"); mSFEventThread = new EventThread(sfVsyncSrc, *this); mEventQueue.setEventThread(mSFEventThread); // Get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, HAL_PIXEL_FORMAT_RGBA_8888); } // Drop the state lock while we initialize the hardware composer. We drop // the lock because on creation, it will call back into SurfaceFlinger to // initialize the primary display. mHwc = new HWComposer(this); mHwc->setEventHandler(static_cast(this)); Mutex::Autolock _l(mStateLock); // retrieve the EGL context that was selected/created mEGLContext = mRenderEngine->getEGLContext(); LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); // make the GLContext current so that we can create textures when creating // Layers (which may happens before we render something) getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); // initialize our drawing state mDrawingState = mCurrentState; // set initial conditions (e.g. unblank default device) initializeDisplays(); // start boot animation startBootAnim(); ALOGV("Done initializing"); } void SurfaceFlinger::startBootAnim() { // start boot animation property_set("service.bootanim.exit", "0"); property_set("ctl.start", "bootanim"); } size_t SurfaceFlinger::getMaxTextureSize() const { return mRenderEngine->getMaxTextureSize(); } size_t SurfaceFlinger::getMaxViewportDims() const { return mRenderEngine->getMaxViewportDims(); } // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( const sp& bufferProducer) const { Mutex::Autolock _l(mStateLock); sp surfaceTextureBinder(IInterface::asBinder(bufferProducer)); return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } status_t SurfaceFlinger::getDisplayConfigs(const sp& display, Vector* configs) { if ((configs == NULL) || (display.get() == NULL)) { return BAD_VALUE; } if (!display.get()) return NAME_NOT_FOUND; int32_t type = NAME_NOT_FOUND; for (int i=0 ; i 0) { density = atoi(property); } return density; } public: static int getEmuDensity() { return getDensityFromProperty("qemu.sf.lcd_density"); } static int getBuildDensity() { return getDensityFromProperty("ro.sf.lcd_density"); } }; configs->clear(); for (const auto& hwConfig : getHwComposer().getConfigs(type)) { DisplayInfo info = DisplayInfo(); float xdpi = hwConfig->getDpiX(); float ydpi = hwConfig->getDpiY(); if (type == DisplayDevice::DISPLAY_PRIMARY) { // The density of the device is provided by a build property float density = Density::getBuildDensity() / 160.0f; if (density == 0) { // the build doesn't provide a density -- this is wrong! // use xdpi instead ALOGE("ro.sf.lcd_density must be defined as a build property"); density = xdpi / 160.0f; } if (Density::getEmuDensity()) { // if "qemu.sf.lcd_density" is specified, it overrides everything xdpi = ydpi = density = Density::getEmuDensity(); density /= 160.0f; } info.density = density; // TODO: this needs to go away (currently needed only by webkit) sp hw(getDefaultDisplayDevice()); info.orientation = hw->getOrientation(); } else { // TODO: where should this value come from? static const int TV_DENSITY = 213; info.density = TV_DENSITY / 160.0f; info.orientation = 0; } info.w = hwConfig->getWidth(); info.h = hwConfig->getHeight(); info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; // TODO: Hook this back up info.colorTransform = 0; // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear // on the screen at time N, you must submit the buffer before // (N - presentationDeadline). // // Normally it's one full refresh period (to give SF a chance to // latch the buffer), but this can be reduced by configuring a // DispSync offset. Any additional delays introduced by the hardware // composer or panel must be accounted for here. // // We add an additional 1ms to allow for processing time and // differences between the ideal and actual refresh rate. info.presentationDeadline = hwConfig->getVsyncPeriod() - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000; // All non-virtual displays are currently considered secure. info.secure = true; configs->push_back(info); } return NO_ERROR; } status_t SurfaceFlinger::getDisplayStats(const sp& /* display */, DisplayStatInfo* stats) { if (stats == NULL) { return BAD_VALUE; } // FIXME for now we always return stats for the primary display memset(stats, 0, sizeof(*stats)); stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0); stats->vsyncPeriod = mPrimaryDispSync.getPeriod(); return NO_ERROR; } int SurfaceFlinger::getActiveConfig(const sp& display) { sp device(getDisplayDevice(display)); if (device != NULL) { return device->getActiveConfig(); } return BAD_VALUE; } void SurfaceFlinger::setActiveConfigInternal(const sp& hw, int mode) { ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); int currentMode = hw->getActiveConfig(); if (mode == currentMode) { ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); return; } if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGW("Trying to set config for virtual display"); return; } hw->setActiveConfig(mode); getHwComposer().setActiveConfig(type, mode); } status_t SurfaceFlinger::setActiveConfig(const sp& display, int mode) { class MessageSetActiveConfig: public MessageBase { SurfaceFlinger& mFlinger; sp mDisplay; int mMode; public: MessageSetActiveConfig(SurfaceFlinger& flinger, const sp& disp, int mode) : mFlinger(flinger), mDisplay(disp) { mMode = mode; } virtual bool handler() { Vector configs; mFlinger.getDisplayConfigs(mDisplay, &configs); if (mMode < 0 || mMode >= static_cast(configs.size())) { ALOGE("Attempt to set active config = %d for display with %zu configs", mMode, configs.size()); } sp hw(mFlinger.getDisplayDevice(mDisplay)); if (hw == NULL) { ALOGE("Attempt to set active config = %d for null display %p", mMode, mDisplay.get()); } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { ALOGW("Attempt to set active config = %d for virtual display", mMode); } else { mFlinger.setActiveConfigInternal(hw, mMode); } return true; } }; sp msg = new MessageSetActiveConfig(*this, display, mode); postMessageSync(msg); return NO_ERROR; } status_t SurfaceFlinger::clearAnimationFrameStats() { Mutex::Autolock _l(mStateLock); mAnimFrameTracker.clearStats(); return NO_ERROR; } status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { Mutex::Autolock _l(mStateLock); mAnimFrameTracker.getStats(outStats); return NO_ERROR; } status_t SurfaceFlinger::getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities) const { Mutex::Autolock _l(mStateLock); sp displayDevice(getDisplayDevice(display)); if (displayDevice == nullptr) { ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get()); return BAD_VALUE; } std::unique_ptr capabilities = mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId()); if (capabilities) { std::swap(*outCapabilities, *capabilities); } else { return BAD_VALUE; } return NO_ERROR; } // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection() { return mEventThread->createEventConnection(); } // ---------------------------------------------------------------------------- void SurfaceFlinger::waitForEvent() { mEventQueue.waitMessage(); } void SurfaceFlinger::signalTransaction() { mEventQueue.invalidate(); } void SurfaceFlinger::signalLayerUpdate() { mEventQueue.invalidate(); } void SurfaceFlinger::signalRefresh() { mEventQueue.refresh(); } status_t SurfaceFlinger::postMessageAsync(const sp& msg, nsecs_t reltime, uint32_t /* flags */) { return mEventQueue.postMessage(msg, reltime); } status_t SurfaceFlinger::postMessageSync(const sp& msg, nsecs_t reltime, uint32_t /* flags */) { status_t res = mEventQueue.postMessage(msg, reltime); if (res == NO_ERROR) { msg->wait(); } return res; } void SurfaceFlinger::run() { do { waitForEvent(); } while (true); } void SurfaceFlinger::enableHardwareVsync() { Mutex::Autolock _l(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mPrimaryDispSync.beginResync(); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { Mutex::Autolock _l(mHWVsyncLock); if (makeAvailable) { mHWVsyncAvailable = true; } else if (!mHWVsyncAvailable) { // Hardware vsync is not currently available, so abort the resync // attempt for now return; } const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); mPrimaryDispSync.reset(); mPrimaryDispSync.setPeriod(period); if (!mPrimaryHWVsyncEnabled) { mPrimaryDispSync.beginResync(); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { Mutex::Autolock _l(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); mEventControlThread->setVsyncEnabled(false); mPrimaryDispSync.endResync(); mPrimaryHWVsyncEnabled = false; } if (makeUnavailable) { mHWVsyncAvailable = false; } } void SurfaceFlinger::resyncWithRateLimit() { static constexpr nsecs_t kIgnoreDelay = ms2ns(500); if (systemTime() - mLastSwapTime > kIgnoreDelay) { resyncToHardwareVsync(false); } } void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) { bool needsHwVsync = false; { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); if (type == 0 && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } if (needsHwVsync) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) { ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); if (disp == DisplayDevice::DISPLAY_PRIMARY) { Mutex::Autolock lock(mStateLock); // All non-virtual displays are currently considered secure. bool isSecure = true; int32_t type = DisplayDevice::DISPLAY_PRIMARY; createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); wp token = mBuiltinDisplays[type]; sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp fbs = new FramebufferSurface(*mHwc, DisplayDevice::DISPLAY_PRIMARY, consumer); sp hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); mDisplays.add(token, hw); } else { auto type = DisplayDevice::DISPLAY_EXTERNAL; Mutex::Autolock _l(mStateLock); if (connected) { createBuiltinDisplayLocked(type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); mBuiltinDisplays[type].clear(); } setTransactionFlags(eDisplayTransactionNeeded); // Defer EventThread notification until SF has updated mDisplays. } } void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { ATRACE_CALL(); getHwComposer().setVsyncEnabled(disp, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { bool refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); refreshNeeded |= mRepaintEverything; if (refreshNeeded) { // Signal a refresh if a transaction modified the window state, // a new buffer was latched, or if HWC has requested a full // repaint signalRefresh(); } break; } case MessageQueue::REFRESH: { handleMessageRefresh(); break; } } } bool SurfaceFlinger::handleMessageTransaction() { uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); if (transactionFlags) { handleTransaction(transactionFlags); return true; } return false; } bool SurfaceFlinger::handleMessageInvalidate() { ATRACE_CALL(); return handlePageFlip(); } void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); #ifdef ENABLE_FENCE_TRACKING nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); #else nsecs_t refreshStartTime = 0; #endif static nsecs_t previousExpectedPresent = 0; nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0); static bool previousFrameMissed = false; bool frameMissed = (expectedPresent == previousExpectedPresent); if (frameMissed != previousFrameMissed) { ATRACE_INT("FrameMissed", static_cast(frameMissed)); } previousFrameMissed = frameMissed; if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) { // Latch buffers, but don't send anything to HWC, then signal another // wakeup for the next vsync preComposition(); repaintEverything(); } else { preComposition(); rebuildLayerStacks(); setUpHWComposer(); doDebugFlashRegions(); doComposition(); postComposition(refreshStartTime); } // Release any buffers which were replaced this frame for (auto& layer : mLayersWithQueuedFrames) { layer->releasePendingBuffer(); } mLayersWithQueuedFrames.clear(); previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0); } void SurfaceFlinger::doDebugFlashRegions() { // is debugging enabled if (CC_LIKELY(!mDebugRegion)) return; const bool repaintEverything = mRepaintEverything; for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); if (!dirtyRegion.isEmpty()) { // redraw the whole screen doComposeSurfaces(hw, Region(hw->bounds())); // and draw the dirty region const int32_t height = hw->getHeight(); RenderEngine& engine(getRenderEngine()); engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1); hw->swapBuffers(getHwComposer()); } } } postFramebuffer(); if (mDebugRegion > 1) { usleep(mDebugRegion * 1000); } for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { status_t result = mDisplays[displayId]->prepareFrame(*mHwc); ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:" " %d (%s)", displayId, result, strerror(-result)); } } void SurfaceFlinger::preComposition() { ATRACE_CALL(); ALOGV("preComposition"); bool needExtraInvalidate = false; const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; ionPreComposition()) { needExtraInvalidate = true; } } if (needExtraInvalidate) { signalLayerUpdate(); } } #ifdef ENABLE_FENCE_TRACKING void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) #else void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/) #endif { ATRACE_CALL(); ALOGV("postComposition"); const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; ionPostComposition(); } sp presentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY); if (presentFence->isValid()) { if (mPrimaryDispSync.addPresentFence(presentFence)) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } const sp hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { if (hw->isDisplayOn()) { enableHardwareVsync(); } } #ifdef ENABLE_FENCE_TRACKING mFenceTracker.addFrame(refreshStartTime, presentFence, hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence()); #endif if (mAnimCompositionPending) { mAnimCompositionPending = false; if (presentFence->isValid()) { mAnimFrameTracker.setActualPresentFence(presentFence); } else { // The HWC doesn't support present fences, so use the refresh // timestamp instead. nsecs_t presentTime = mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); } if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { return; } nsecs_t currentTime = systemTime(); if (mHasPoweredOff) { mHasPoweredOff = false; } else { nsecs_t period = mPrimaryDispSync.getPeriod(); nsecs_t elapsedTime = currentTime - mLastSwapTime; size_t numPeriods = static_cast(elapsedTime / period); if (numPeriods < NUM_BUCKETS - 1) { mFrameBuckets[numPeriods] += elapsedTime; } else { mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; } mTotalTime += elapsedTime; } mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { ATRACE_CALL(); ALOGV("rebuildLayerStacks"); // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_CALL(); mVisibleRegionsDirty = false; invalidateHwcGeometry(); const LayerVector& layers(mDrawingState.layersSortedByZ); for (size_t dpy=0 ; dpy> layersSortedByZ; const sp& displayDevice(mDisplays[dpy]); const Transform& tr(displayDevice->getTransform()); const Rect bounds(displayDevice->getBounds()); if (displayDevice->isDisplayOn()) { SurfaceFlinger::computeVisibleRegions(layers, displayDevice->getLayerStack(), dirtyRegion, opaqueRegion); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& s(layer->getDrawingState()); if (s.layerStack == displayDevice->getLayerStack()) { Region drawRegion(tr.transform( layer->visibleNonTransparentRegion)); drawRegion.andSelf(bounds); if (!drawRegion.isEmpty()) { layersSortedByZ.add(layer); } else { // Clear out the HWC layer if this layer was // previously visible, but no longer is layer->setHwcLayer(displayDevice->getHwcDisplayId(), nullptr); } } } } displayDevice->setVisibleLayersSortedByZ(layersSortedByZ); displayDevice->undefinedRegion.set(bounds); displayDevice->undefinedRegion.subtractSelf( tr.transform(opaqueRegion)); displayDevice->dirtyRegion.orSelf(dirtyRegion); } } } void SurfaceFlinger::setUpHWComposer() { ATRACE_CALL(); ALOGV("setUpHWComposer"); for (size_t dpy=0 ; dpygetDirtyRegion(false).isEmpty(); bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0; bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers; // If nothing has changed (!dirty), don't recompose. // If something changed, but we don't currently have any visible layers, // and didn't when we last did a composition, then skip it this time. // The second rule does two things: // - When all layers are removed from a display, we'll emit one black // frame, then nothing more until we get new layers. // - When a display is created with a private layer stack, we won't // emit any black frames until a layer is added to the layer stack. bool mustRecompose = dirty && !(empty && wasEmpty); ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL, "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy, mustRecompose ? "doing" : "skipping", dirty ? "+" : "-", empty ? "+" : "-", wasEmpty ? "+" : "-"); mDisplays[dpy]->beginFrame(mustRecompose); if (mustRecompose) { mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty; } } // build the h/w work list if (CC_UNLIKELY(mGeometryInvalid)) { mGeometryInvalid = false; for (size_t dpy=0 ; dpy displayDevice(mDisplays[dpy]); const auto hwcId = displayDevice->getHwcDisplayId(); if (hwcId >= 0) { const Vector>& currentLayers( displayDevice->getVisibleLayersSortedByZ()); bool foundLayerWithoutHwc = false; for (auto& layer : currentLayers) { if (!layer->hasHwcLayer(hwcId)) { auto hwcLayer = mHwc->createLayer(hwcId); if (hwcLayer) { layer->setHwcLayer(hwcId, std::move(hwcLayer)); } else { layer->forceClientComposition(hwcId); foundLayerWithoutHwc = true; continue; } } layer->setGeometry(displayDevice); if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { layer->forceClientComposition(hwcId); } } } } } // Set the per-frame data for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { auto& displayDevice = mDisplays[displayId]; const auto hwcId = displayDevice->getHwcDisplayId(); if (hwcId < 0) { continue; } for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { layer->setPerFrameData(displayDevice); } } for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { status_t result = mDisplays[displayId]->prepareFrame(*mHwc); ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:" " %d (%s)", displayId, result, strerror(-result)); } } void SurfaceFlinger::doComposition() { ATRACE_CALL(); ALOGV("doComposition"); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); // repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } } postFramebuffer(); } void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); ALOGV("postFramebuffer"); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { auto& displayDevice = mDisplays[displayId]; const auto hwcId = displayDevice->getHwcDisplayId(); if (hwcId >= 0) { mHwc->commit(hwcId); } displayDevice->onSwapBuffersCompleted(); if (displayId == 0) { // Make the default display current because the VirtualDisplayDevice // code cannot deal with dequeueBuffer() being called outside of the // composition loop; however the code below can call glFlush() which // is allowed to (and does in some case) call dequeueBuffer(). displayDevice->makeCurrent(mEGLDisplay, mEGLContext); } for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { sp releaseFence = Fence::NO_FENCE; if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) { releaseFence = displayDevice->getClientTargetAcquireFence(); } else { auto hwcLayer = layer->getHwcLayer(hwcId); releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer); } layer->onLayerDisplayed(releaseFence); } if (hwcId >= 0) { mHwc->clearReleaseFences(hwcId); } } mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); } } void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); // here we keep a copy of the drawing state (that is the state that's // going to be overwritten by handleTransactionLocked()) outside of // mStateLock so that the side-effects of the State assignment // don't happen with mStateLock held (which can cause deadlocks). State drawingState(mDrawingState); Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; // Here we're guaranteed that some transaction flags are set // so we can call handleTransactionLocked() unconditionally. // We call getTransactionFlags(), which will also clear the flags, // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; invalidateHwcGeometry(); // here the transaction has been committed } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); // Notify all layers of available frames for (size_t i = 0; i < count; ++i) { currentLayers[i]->notifyAvailableFrames(); } /* * Traversal of the children * (perform the transaction for each of them if needed) */ if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i& layer(currentLayers[i]); uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; const uint32_t flags = layer->doTransaction(0); if (flags & Layer::eVisibleRegion) mVisibleRegionsDirty = true; } } /* * Perform display own transactions if needed */ if (transactionFlags & eDisplayTransactionNeeded) { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when // know that the lists are identical const KeyedVector< wp, DisplayDeviceState>& curr(mCurrentState.displays); const KeyedVector< wp, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; const size_t cc = curr.size(); size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) for (size_t i=0 ; i defaultDisplay(getDefaultDisplayDevice()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); } else { ALOGW("trying to remove the main display"); } } else { // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp& display(curr.keyAt(j)); const sp state_binder = IInterface::asBinder(state.surface); const sp draw_binder = IInterface::asBinder(draw[i].surface); if (state_binder != draw_binder) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. sp hw(getDisplayDevice(display)); if (hw != NULL) hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; // at this point we must loop to the next item continue; } const sp disp(getDisplayDevice(display)); if (disp != NULL) { if (state.layerStack != draw[i].layerStack) { disp->setLayerStack(state.layerStack); } if ((state.orientation != draw[i].orientation) || (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { disp->setProjection(state.orientation, state.viewport, state.frame); } if (state.width != draw[i].width || state.height != draw[i].height) { disp->setDisplaySize(state.width, state.height); } } } } // find displays that were added // (ie: in current state but not in drawing state) for (size_t i=0 ; i dispSurface; sp producer; sp bqProducer; sp bqConsumer; BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc()); int32_t hwcId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); int height = 0; status = state.surface->query( NATIVE_WINDOW_HEIGHT, &height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); int intFormat = 0; status = state.surface->query( NATIVE_WINDOW_FORMAT, &intFormat); ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); auto format = static_cast( intFormat); mHwc->allocateVirtualDisplay(width, height, &format, &hwcId); // TODO: Plumb requested format back up to consumer sp vds = new VirtualDisplaySurface(*mHwc, hwcId, state.surface, bqProducer, bqConsumer, state.displayName); dispSurface = vds; producer = vds; } } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); if (state.type == DisplayDevice::DISPLAY_EXTERNAL) { hwcId = DisplayDevice::DISPLAY_EXTERNAL; dispSurface = new FramebufferSurface(*mHwc, DisplayDevice::DISPLAY_EXTERNAL, bqConsumer); producer = bqProducer; } else { ALOGE("Attempted to add non-external non-virtual" " display"); } } const wp& display(curr.keyAt(i)); if (dispSurface != NULL) { sp hw = new DisplayDevice(this, state.type, hwcId, state.isSecure, display, dispSurface, producer, mRenderEngine->getEGLConfig()); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); mDisplays.add(display, hw); if (!state.isVirtualDisplay()) { mEventThread->onHotplugReceived(state.type, true); } } } } } } if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { // The transform hint might have changed for some layers // (either because a display has changed, or because a layer // as changed). // // Walk through all the layers in currentLayers, // and update their transform hint. // // If a layer is visible only on a single display, then that // display is used to calculate the hint, otherwise we use the // default display. // // NOTE: we do this here, rather than in rebuildLayerStacks() so that // the hint is set before we acquire a buffer from the surface texture. // // NOTE: layer transactions have taken place already, so we use their // drawing state. However, SurfaceFlinger's own transaction has not // happened yet, so we must use the current state layer list // (soon to become the drawing state list). // sp disp; uint32_t currentlayerStack = 0; for (size_t i=0; i& layer(currentLayers[i]); uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored // (more than one display) if so, pick the default display, // if not, pick the only display it's on. disp.clear(); for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); if (hw->getLayerStack() == currentlayerStack) { if (disp == NULL) { disp = hw; } else { disp = NULL; break; } } } } if (disp == NULL) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397. // could be null when this layer is using a layerStack // that is not visible on any display. Also can occur at // screen off/on times. disp = getDefaultDisplayDevice(); } layer->updateTransformHint(disp); } } /* * Perform our own transaction if needed */ const LayerVector& layers(mDrawingState.layersSortedByZ); if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; } // some layers might have been removed, so // we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.active.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); } } } commitTransaction(); updateCursorAsync(); } void SurfaceFlinger::updateCursorAsync() { for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { auto& displayDevice = mDisplays[displayId]; if (displayDevice->getHwcDisplayId() < 0) { continue; } for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { layer->updateCursorPosition(displayDevice); } } } void SurfaceFlinger::commitTransaction() { if (!mLayersPendingRemoval.isEmpty()) { // Notify removed layers now that they can't be drawn from for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { mLayersPendingRemoval[i]->onRemoved(); } mLayersPendingRemoval.clear(); } // If this transaction is part of a window animation then the next frame // we composite should be considered an animation as well. mAnimCompositionPending = mAnimTransactionPending; mDrawingState = mCurrentState; mTransactionPending = false; mAnimTransactionPending = false; mTransactionCV.broadcast(); } void SurfaceFlinger::computeVisibleRegions( const LayerVector& currentLayers, uint32_t layerStack, Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); ALOGV("computeVisibleRegions"); Region aboveOpaqueLayers; Region aboveCoveredLayers; Region dirty; outDirtyRegion.clear(); size_t i = currentLayers.size(); while (i--) { const sp& layer = currentLayers[i]; // start with the whole surface at its current location const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack if (s.layerStack != layerStack) continue; /* * opaqueRegion: area of a surface that is fully opaque. */ Region opaqueRegion; /* * visibleRegion: area of a surface that is visible on screen * and not fully transparent. This is essentially the layer's * footprint minus the opaque regions above it. * Areas covered by a translucent surface are considered visible. */ Region visibleRegion; /* * coveredRegion: area of a surface that is covered by all * visible regions above it (which includes the translucent areas). */ Region coveredRegion; /* * transparentRegion: area of a surface that is hinted to be completely * transparent. This is only used to tell when the layer has no visible * non-transparent regions and can be removed from the layer list. It * does not affect the visibleRegion of this layer or any layers * beneath it. The hint may not be correct if apps don't respect the * SurfaceView restrictions (which, sadly, some don't). */ Region transparentRegion; // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(s); Rect bounds(s.active.transform.transform(layer->computeBounds())); visibleRegion.set(bounds); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region if (translucent) { const Transform tr(s.active.transform); if (tr.preserveRects()) { // transform the transparent region transparentRegion = tr.transform(s.activeTransparentRegion); } else { // transformation too complex, can't do the // transparent region optimization. transparentRegion.clear(); } } // compute the opaque region const int32_t layerOrientation = s.active.transform.getOrientation(); if (s.alpha == 1.0f && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint opaqueRegion = visibleRegion; } } } // Clip the covered region to the visible region coveredRegion = aboveCoveredLayers.intersect(visibleRegion); // Update aboveCoveredLayers for next (lower) layer aboveCoveredLayers.orSelf(visibleRegion); // subtract the opaque region covered by the layers above us visibleRegion.subtractSelf(aboveOpaqueLayers); // compute this layer's dirty region if (layer->contentDirty) { // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region dirty.orSelf(layer->visibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: * the exposed region consists of two components: * 1) what's VISIBLE now and was COVERED before * 2) what's EXPOSED now less what was EXPOSED before * * note that (1) is conservative, we start with the whole * visible region but only keep what used to be covered by * something -- which mean it may have been exposed. * * (2) handles areas that were not covered by anything but got * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; const Region oldVisibleRegion = layer->visibleRegion; const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region outDirtyRegion.orSelf(dirty); // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); // Store the visible region in screen space layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); layer->setVisibleNonTransparentRegion( visibleRegion.subtract(transparentRegion)); } outOpaqueRegion = aboveOpaqueLayers; } void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, const Region& dirty) { for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->getLayerStack() == layerStack) { hw->dirtyRegion.orSelf(dirty); } } } bool SurfaceFlinger::handlePageFlip() { ALOGV("handlePageFlip"); Region dirtyRegion; bool visibleRegions = false; const LayerVector& layers(mDrawingState.layersSortedByZ); bool frameQueued = false; // Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. // Example: Two producers share the same command stream and: // 1.) Layer 0 is latched // 2.) Layer 0 gets a new frame // 2.) Layer 1 gets a new frame // 3.) Layer 1 is latched. // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. for (size_t i = 0, count = layers.size(); i& layer(layers[i]); if (layer->hasQueuedFrame()) { frameQueued = true; if (layer->shouldPresentNow(mPrimaryDispSync)) { mLayersWithQueuedFrames.push_back(layer.get()); } else { layer->useEmptyDamage(); } } else { layer->useEmptyDamage(); } } for (auto& layer : mLayersWithQueuedFrames) { const Region dirty(layer->latchBuffer(visibleRegions)); layer->useSurfaceDamage(); const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } mVisibleRegionsDirty |= visibleRegions; // If we will need to wake up at some time in the future to deal with a // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. if (frameQueued && mLayersWithQueuedFrames.empty()) { signalLayerUpdate(); } // Only continue with the refresh if there is actually new work to do return !mLayersWithQueuedFrames.empty(); } void SurfaceFlinger::invalidateHwcGeometry() { mGeometryInvalid = true; } void SurfaceFlinger::doDisplayComposition(const sp& hw, const Region& inDirtyRegion) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) bool isHwcDisplay = hw->getHwcDisplayId() >= 0; if (!isHwcDisplay && inDirtyRegion.isEmpty()) { ALOGV("Skipping display composition"); return; } ALOGV("doDisplayComposition"); Region dirtyRegion(inDirtyRegion); // compute the invalid region hw->swapRegion.orSelf(dirtyRegion); uint32_t flags = hw->getFlags(); if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole // rectangle in that case dirtyRegion.set(hw->swapRegion.bounds()); } else { if (flags & DisplayDevice::PARTIAL_UPDATES) { // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). // This is needed because PARTIAL_UPDATES only takes one // rectangle instead of a region (see DisplayDevice::flip()) dirtyRegion.set(hw->swapRegion.bounds()); } else { // we need to redraw everything (the whole screen) dirtyRegion.set(hw->bounds()); hw->swapRegion = dirtyRegion; } } if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { if (!doComposeSurfaces(hw, dirtyRegion)) return; } else { RenderEngine& engine(getRenderEngine()); mat4 colorMatrix = mColorMatrix; if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion); engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region hw->swapRegion.orSelf(dirtyRegion); // swap buffers (presentation) hw->swapBuffers(getHwComposer()); } bool SurfaceFlinger::doComposeSurfaces( const sp& displayDevice, const Region& dirty) { ALOGV("doComposeSurfaces"); const auto hwcId = displayDevice->getHwcDisplayId(); bool hasClientComposition = mHwc->hasClientComposition(hwcId); if (hasClientComposition) { ALOGV("hasClientComposition"); if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", displayDevice->getDisplayName().string()); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); } return false; } // Never touch the framebuffer if we don't have any framebuffer layers const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId); if (hasDeviceComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some // GPUs doing a "clean slate" clear might be more efficient. // We'll revisit later if needed. mRenderEngine->clearWithColor(0, 0, 0, 0); } else { // we start with the whole screen area const Region bounds(displayDevice->getBounds()); // we remove the scissor part // we're left with the letterbox region // (common case is that letterbox ends-up being empty) const Region letterbox(bounds.subtract(displayDevice->getScissor())); // compute the area to clear Region region(displayDevice->undefinedRegion.merge(letterbox)); // but limit it to the dirty region region.andSelf(dirty); // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView drawWormhole(displayDevice, region); } } if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { // just to be on the safe side, we don't set the // scissor on the main display. It should never be needed // anyways (though in theory it could since the API allows it). const Rect& bounds(displayDevice->getBounds()); const Rect& scissor(displayDevice->getScissor()); if (scissor != bounds) { // scissor doesn't match the screen's dimensions, so we // need to clear everything outside of it and enable // the GL scissor so we don't draw anything where we shouldn't // enable scissor for this frame const uint32_t height = displayDevice->getHeight(); mRenderEngine->setScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight()); } } } /* * and then, render the layers targeted at the framebuffer */ ALOGV("Rendering client layers"); const Transform& displayTransform = displayDevice->getTransform(); if (hwcId >= 0) { // we're using h/w composer bool firstLayer = true; for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { const Region clip(dirty.intersect( displayTransform.transform(layer->visibleRegion))); ALOGV("Layer: %s", layer->getName().string()); ALOGV(" Composition type: %s", to_string(layer->getCompositionType(hwcId)).c_str()); if (!clip.isEmpty()) { switch (layer->getCompositionType(hwcId)) { case HWC2::Composition::Cursor: case HWC2::Composition::Device: case HWC2::Composition::SolidColor: { const Layer::State& state(layer->getDrawingState()); if (layer->getClearClientTarget(hwcId) && !firstLayer && layer->isOpaque(state) && (state.alpha == 1.0f) && hasClientComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared layer->clearWithOpenGL(displayDevice, clip); } break; } case HWC2::Composition::Client: { layer->draw(displayDevice, clip); break; } default: break; } } else { ALOGV(" Skipping for empty clip"); } firstLayer = false; } } else { // we're not using h/w composer for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { const Region clip(dirty.intersect( displayTransform.transform(layer->visibleRegion))); if (!clip.isEmpty()) { layer->draw(displayDevice, clip); } } } // disable scissor at the end of the frame mRenderEngine->disableScissor(); return true; } void SurfaceFlinger::drawWormhole(const sp& hw, const Region& region) const { const int32_t height = hw->getHeight(); RenderEngine& engine(getRenderEngine()); engine.fillRegionWithColor(region, height, 0, 0, 0, 0); } status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc) { // add this layer to the current state list { Mutex::Autolock _l(mStateLock); if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) { return NO_MEMORY; } mCurrentState.layersSortedByZ.add(lbc); mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); } // attach this layer to the client client->attachLayer(handle, lbc); return NO_ERROR; } status_t SurfaceFlinger::removeLayer(const sp& layer) { Mutex::Autolock _l(mStateLock); ssize_t index = mCurrentState.layersSortedByZ.remove(layer); if (index >= 0) { mLayersPendingRemoval.push(layer); mLayersRemoved = true; setTransactionFlags(eTransactionNeeded); return NO_ERROR; } return status_t(index); } uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) { return android_atomic_release_load(&mTransactionFlags); } uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { return android_atomic_and(~flags, &mTransactionFlags) & flags; } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { uint32_t old = android_atomic_or(flags, &mTransactionFlags); if ((old & flags)==0) { // wake the server up signalTransaction(); } return old; } void SurfaceFlinger::setTransactionState( const Vector& state, const Vector& displays, uint32_t flags) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); uint32_t transactionFlags = 0; if (flags & eAnimation) { // For window updates that are part of an animation we must wait for // previous animation "frames" to be handled. while (mAnimTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // caller after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " "waiting for previous animation frame"); mAnimTransactionPending = false; break; } } } size_t count = displays.size(); for (size_t i=0 ; i binder = IInterface::asBinder(s.client); if (binder != NULL) { if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) { sp client( static_cast(s.client.get()) ); transactionFlags |= setClientStateLocked(client, s.state); } } } } // If a synchronous transaction is explicitly requested without any changes, // force a transaction anyway. This can be used as a flush mechanism for // previous async transactions. if (transactionFlags == 0 && (flags & eSynchronous)) { transactionFlags = eTransactionNeeded; } if (transactionFlags) { // this triggers the transaction setTransactionFlags(transactionFlags); // if this is a synchronous transaction, wait for it to take effect // before returning. if (flags & eSynchronous) { mTransactionPending = true; } if (flags & eAnimation) { mAnimTransactionPending = true; } while (mTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // called after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); mTransactionPending = false; break; } } } } uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token); if (dpyIdx < 0) return 0; uint32_t flags = 0; DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx)); if (disp.isValid()) { const uint32_t what = s.what; if (what & DisplayState::eSurfaceChanged) { if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) { disp.surface = s.surface; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eLayerStackChanged) { if (disp.layerStack != s.layerStack) { disp.layerStack = s.layerStack; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eDisplayProjectionChanged) { if (disp.orientation != s.orientation) { disp.orientation = s.orientation; flags |= eDisplayTransactionNeeded; } if (disp.frame != s.frame) { disp.frame = s.frame; flags |= eDisplayTransactionNeeded; } if (disp.viewport != s.viewport) { disp.viewport = s.viewport; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eDisplaySizeChanged) { if (disp.width != s.width) { disp.width = s.width; flags |= eDisplayTransactionNeeded; } if (disp.height != s.height) { disp.height = s.height; flags |= eDisplayTransactionNeeded; } } } return flags; } uint32_t SurfaceFlinger::setClientStateLocked( const sp& client, const layer_state_t& s) { uint32_t flags = 0; sp layer(client->getLayerUser(s.surface)); if (layer != 0) { const uint32_t what = s.what; bool positionAppliesWithResize = what & layer_state_t::ePositionAppliesWithResize; if (what & layer_state_t::ePositionChanged) { if (layer->setPosition(s.x, s.y, !positionAppliesWithResize)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eLayerChanged) { // NOTE: index needs to be calculated before we update the state ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } } if (what & layer_state_t::eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eAlphaChanged) { if (layer->setAlpha(s.alpha)) flags |= eTraversalNeeded; } if (what & layer_state_t::eMatrixChanged) { if (layer->setMatrix(s.matrix)) flags |= eTraversalNeeded; } if (what & layer_state_t::eTransparentRegionChanged) { if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFlagsChanged) { if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFinalCropChanged) { if (layer->setFinalCrop(s.finalCrop)) flags |= eTraversalNeeded; } if (what & layer_state_t::eLayerStackChanged) { // NOTE: index needs to be calculated before we update the state ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayerStack(s.layerStack) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } } if (what & layer_state_t::eDeferTransaction) { layer->deferTransactionUntil(s.handle, s.frameNumber); // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } if (what & layer_state_t::eOverrideScalingModeChanged) { layer->setOverrideScalingMode(s.overrideScalingMode); // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } } return flags; } status_t SurfaceFlinger::createLayer( const String8& name, const sp& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) { //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); if (int32_t(w|h) < 0) { ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", int(w), int(h)); return BAD_VALUE; } status_t result = NO_ERROR; sp layer; switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client, name, w, h, flags, format, handle, gbp, &layer); break; case ISurfaceComposerClient::eFXSurfaceDim: result = createDimLayer(client, name, w, h, flags, handle, gbp, &layer); break; default: result = BAD_VALUE; break; } if (result != NO_ERROR) { return result; } result = addClientLayer(client, *handle, *gbp, layer); if (result != NO_ERROR) { return result; } setTransactionFlags(eTransactionNeeded); return result; } status_t SurfaceFlinger::createNormalLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp* handle, sp* gbp, sp* outLayer) { // initialize the surfaces switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: format = PIXEL_FORMAT_RGBX_8888; break; } *outLayer = new Layer(this, client, name, w, h, flags); status_t err = (*outLayer)->setBuffers(w, h, format, flags); if (err == NO_ERROR) { *handle = (*outLayer)->getHandle(); *gbp = (*outLayer)->getProducer(); } ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); return err; } status_t SurfaceFlinger::createDimLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, sp* handle, sp* gbp, sp* outLayer) { *outLayer = new LayerDim(this, client, name, w, h, flags); *handle = (*outLayer)->getHandle(); *gbp = (*outLayer)->getProducer(); return NO_ERROR; } status_t SurfaceFlinger::onLayerRemoved(const sp& client, const sp& handle) { // called by the window manager when it wants to remove a Layer status_t err = NO_ERROR; sp l(client->getLayerUser(handle)); if (l != NULL) { err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); } return err; } status_t SurfaceFlinger::onLayerDestroyed(const wp& layer) { // called by ~LayerCleaner() when all references to the IBinder (handle) // are gone status_t err = NO_ERROR; sp l(layer.promote()); if (l != NULL) { err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); } return err; } // --------------------------------------------------------------------------- void SurfaceFlinger::onInitializeDisplays() { // reset screen orientation and use primary layer stack Vector state; Vector displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; d.layerStack = 0; d.orientation = DisplayState::eOrientationDefault; d.frame.makeInvalid(); d.viewport.makeInvalid(); d.width = 0; d.height = 0; displays.add(d); setTransactionState(state, displays, 0); setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(period); } void SurfaceFlinger::initializeDisplays() { class MessageScreenInitialized : public MessageBase { SurfaceFlinger* flinger; public: MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { } virtual bool handler() { flinger->onInitializeDisplays(); return true; } }; sp msg = new MessageScreenInitialized(this); postMessageAsync(msg); // we may be called from main thread, use async message } void SurfaceFlinger::setPowerModeInternal(const sp& hw, int mode) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); int currentMode = hw->getPowerMode(); if (mode == currentMode) { ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); return; } hw->setPowerMode(mode); if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGW("Trying to set power mode for virtual display"); return; } if (currentMode == HWC_POWER_MODE_OFF) { getHwComposer().setPowerMode(type, mode); if (type == DisplayDevice::DISPLAY_PRIMARY) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); } mVisibleRegionsDirty = true; mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { disableHardwareVsync(true); // also cancels any in-progress resync // FIXME: eventthread only knows about the main display right now mEventThread->onScreenReleased(); } getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display } else { getHwComposer().setPowerMode(type, mode); } } void SurfaceFlinger::setPowerMode(const sp& display, int mode) { class MessageSetPowerMode: public MessageBase { SurfaceFlinger& mFlinger; sp mDisplay; int mMode; public: MessageSetPowerMode(SurfaceFlinger& flinger, const sp& disp, int mode) : mFlinger(flinger), mDisplay(disp) { mMode = mode; } virtual bool handler() { sp hw(mFlinger.getDisplayDevice(mDisplay)); if (hw == NULL) { ALOGE("Attempt to set power mode = %d for null display %p", mMode, mDisplay.get()); } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { mFlinger.setPowerModeInternal(hw, mMode); } return true; } }; sp msg = new MessageSetPowerMode(*this, display, mode); postMessageSync(msg); } // --------------------------------------------------------------------------- status_t SurfaceFlinger::dump(int fd, const Vector& args) { String8 result; IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); } else { // Try to get the main lock, but give up after one second // (this would indicate SF is stuck, but we want to be able to // print something in dumpsys). status_t err = mStateLock.timedLock(s2ns(1)); bool locked = (err == NO_ERROR); if (!locked) { result.appendFormat( "SurfaceFlinger appears to be unresponsive (%s [%d]), " "dumping anyways (no locks held)\n", strerror(-err), err); } bool dumpAll = true; size_t index = 0; size_t numArgs = args.size(); if (numArgs) { if ((index < numArgs) && (args[index] == String16("--list"))) { index++; listLayersLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency"))) { index++; dumpStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency-clear"))) { index++; clearStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--dispsync"))) { index++; mPrimaryDispSync.dump(result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--static-screen"))) { index++; dumpStaticScreenStats(result); dumpAll = false; } #ifdef ENABLE_FENCE_TRACKING if ((index < numArgs) && (args[index] == String16("--fences"))) { index++; mFenceTracker.dump(&result); dumpAll = false; } #endif } if (dumpAll) { dumpAllLocked(args, index, result); } if (locked) { mStateLock.unlock(); } } write(fd, result.string(), result.size()); return NO_ERROR; } void SurfaceFlinger::listLayersLocked(const Vector& /* args */, size_t& /* index */, String8& result) const { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); result.appendFormat("%s\n", layer->getName().string()); } } void SurfaceFlinger::dumpStatsLocked(const Vector& args, size_t& index, String8& result) const { String8 name; if (index < args.size()) { name = String8(args[index]); index++; } const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); const nsecs_t period = activeConfig->getVsyncPeriod(); result.appendFormat("%" PRId64 "\n", period); if (name.isEmpty()) { mAnimFrameTracker.dumpStats(result); } else { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); if (name == layer->getName()) { layer->dumpFrameStats(result); } } } } void SurfaceFlinger::clearStatsLocked(const Vector& args, size_t& index, String8& /* result */) { String8 name; if (index < args.size()) { name = String8(args[index]); index++; } const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); if (name.isEmpty() || (name == layer->getName())) { layer->clearFrameStats(); } } mAnimFrameTracker.clearStats(); } // This should only be called from the main thread. Otherwise it would need // the lock and should use mCurrentState rather than mDrawingState. void SurfaceFlinger::logFrameStats() { const LayerVector& drawingLayers = mDrawingState.layersSortedByZ; const size_t count = drawingLayers.size(); for (size_t i=0 ; i& layer(drawingLayers[i]); layer->logFrameStats(); } mAnimFrameTracker.logAndResetStats(String8("")); } /*static*/ void SurfaceFlinger::appendSfConfigString(String8& result) { static const char* config = " [sf" #ifdef HAS_CONTEXT_PRIORITY " HAS_CONTEXT_PRIORITY" #endif #ifdef NEVER_DEFAULT_TO_ASYNC_MODE " NEVER_DEFAULT_TO_ASYNC_MODE" #endif #ifdef TARGET_DISABLE_TRIPLE_BUFFERING " TARGET_DISABLE_TRIPLE_BUFFERING" #endif "]"; result.append(config); } void SurfaceFlinger::dumpStaticScreenStats(String8& result) const { result.appendFormat("Static screen stats:\n"); for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { float bucketTimeSec = mFrameBuckets[b] / 1e9; float percent = 100.0f * static_cast(mFrameBuckets[b]) / mTotalTime; result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent); } float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; float percent = 100.0f * static_cast(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", NUM_BUCKETS - 1, bucketTimeSec, percent); } void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, String8& result) const { bool colorize = false; if (index < args.size() && (args[index] == String16("--color"))) { colorize = true; index++; } Colorizer colorizer(colorize); // figure out if we're stuck somewhere const nsecs_t now = systemTime(); const nsecs_t inSwapBuffers(mDebugInSwapBuffers); const nsecs_t inTransaction(mDebugInTransaction); nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; /* * Dump library configuration. */ colorizer.bold(result); result.append("Build configuration:"); colorizer.reset(result); appendSfConfigString(result); appendUiConfigString(result); appendGuiConfigString(result); result.append("\n"); colorizer.bold(result); result.append("Sync configuration: "); colorizer.reset(result); result.append(SyncFeatures::getInstance().toString()); result.append("\n"); const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); colorizer.bold(result); result.append("DispSync configuration: "); colorizer.reset(result); result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, " "present offset %d ns (refresh %" PRId64 " ns)", vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS, activeConfig->getVsyncPeriod()); result.append("\n"); // Dump static screen stats result.append("\n"); dumpStaticScreenStats(result); result.append("\n"); /* * Dump the visible layer list */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); colorizer.bold(result); result.appendFormat("Visible layers (count = %zu)\n", count); colorizer.reset(result); for (size_t i=0 ; i& layer(currentLayers[i]); layer->dump(result, colorizer); } /* * Dump Display state */ colorizer.bold(result); result.appendFormat("Displays (%zu entries)\n", mDisplays.size()); colorizer.reset(result); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); hw->dump(result); } /* * Dump SurfaceFlinger global state */ colorizer.bold(result); result.append("SurfaceFlinger global state:\n"); colorizer.reset(result); HWComposer& hwc(getHwComposer()); sp hw(getDefaultDisplayDevice()); colorizer.bold(result); result.appendFormat("EGL implementation : %s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); colorizer.reset(result); result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); mRenderEngine->dump(result); hw->undefinedRegion.dump(result, "undefinedRegion"); result.appendFormat(" orientation=%d, isDisplayOn=%d\n", hw->getOrientation(), hw->isDisplayOn()); result.appendFormat( " last eglSwapBuffers() time: %f us\n" " last transaction time : %f us\n" " transaction-flags : %08x\n" " refresh-rate : %f fps\n" " x-dpi : %f\n" " y-dpi : %f\n" " gpu_to_cpu_unsupported : %d\n" , mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0, mTransactionFlags, 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(), activeConfig->getDpiY(), !mGpuToCpuSupported); result.appendFormat(" eglSwapBuffers time: %f us\n", inSwapBuffersDuration/1000.0); result.appendFormat(" transaction time: %f us\n", inTransactionDuration/1000.0); /* * VSYNC state */ mEventThread->dump(result); /* * Dump HWComposer state */ colorizer.bold(result); result.append("h/w composer state:\n"); colorizer.reset(result); bool hwcDisabled = mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix; result.appendFormat(" h/w composer %s\n", hwcDisabled ? "disabled" : "enabled"); hwc.dump(result); /* * Dump gralloc state */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); } const Vector< sp >& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { // Note: mStateLock is held here wp dpy; for (size_t i=0 ; igetHwcDisplayId() == id) { dpy = mDisplays.keyAt(i); break; } } if (dpy == NULL) { ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); // Just use the primary display so we have something to return dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); } return getDisplayDevice(dpy)->getVisibleLayersSortedByZ(); } bool SurfaceFlinger::startDdmConnection() { void* libddmconnection_dso = dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW); if (!libddmconnection_dso) { return false; } void (*DdmConnection_start)(const char* name); DdmConnection_start = (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start"); if (!DdmConnection_start) { dlclose(libddmconnection_dso); return false; } (*DdmConnection_start)(getServiceName()); return true; } status_t SurfaceFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case CREATE_CONNECTION: case CREATE_DISPLAY: case SET_TRANSACTION_STATE: case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: case GET_ANIMATION_FRAME_STATS: case SET_POWER_MODE: case GET_HDR_CAPABILITIES: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } case CAPTURE_SCREEN: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS) && !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { ALOGE("Permission Denial: " "can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } } status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } int n; switch (code) { case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE return NO_ERROR; case 1002: // SHOW_UPDATES n = data.readInt32(); mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1004:{ // repaint everything repaintEverything(); return NO_ERROR; } case 1005:{ // force transaction setTransactionFlags( eTransactionNeeded| eDisplayTransactionNeeded| eTraversalNeeded); return NO_ERROR; } case 1006:{ // send empty update signalRefresh(); return NO_ERROR; } case 1008: // toggle use of hw composer n = data.readInt32(); mDebugDisableHWC = n ? 1 : 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1009: // toggle use of transform hint n = data.readInt32(); mDebugDisableTransformHint = n ? 1 : 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1010: // interrogate. reply->writeInt32(0); reply->writeInt32(0); reply->writeInt32(mDebugRegion); reply->writeInt32(0); reply->writeInt32(mDebugDisableHWC); return NO_ERROR; case 1013: { Mutex::Autolock _l(mStateLock); sp hw(getDefaultDisplayDevice()); reply->writeInt32(hw->getPageFlipCount()); return NO_ERROR; } case 1014: { // daltonize n = data.readInt32(); switch (n % 10) { case 1: mDaltonizer.setType(Daltonizer::protanomaly); break; case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break; case 3: mDaltonizer.setType(Daltonizer::tritanomaly); break; } if (n >= 10) { mDaltonizer.setMode(Daltonizer::correction); } else { mDaltonizer.setMode(Daltonizer::simulation); } mDaltonize = n > 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; } case 1015: { // apply a color matrix n = data.readInt32(); mHasColorMatrix = n ? 1 : 0; if (n) { // color matrix is sent as mat3 matrix followed by vec3 // offset, then packed into a mat4 where the last row is // the offset and extra values are 0 for (size_t i = 0 ; i < 4; i++) { for (size_t j = 0; j < 4; j++) { mColorMatrix[i][j] = data.readFloat(); } } } else { mColorMatrix = mat4(); } invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; } // This is an experimental interface // Needs to be shifted to proper binder interface when we productize case 1016: { n = data.readInt32(); mPrimaryDispSync.setRefreshSkipCount(n); return NO_ERROR; } case 1017: { n = data.readInt32(); mForceFullDamage = static_cast(n); return NO_ERROR; } case 1018: { // Modify Choreographer's phase offset n = data.readInt32(); mEventThread->setPhaseOffset(static_cast(n)); return NO_ERROR; } case 1019: { // Modify SurfaceFlinger's phase offset n = data.readInt32(); mSFEventThread->setPhaseOffset(static_cast(n)); return NO_ERROR; } } } return err; } void SurfaceFlinger::repaintEverything() { android_atomic_or(1, &mRepaintEverything); signalTransaction(); } // --------------------------------------------------------------------------- // Capture screen into an IGraphiBufferProducer // --------------------------------------------------------------------------- /* The code below is here to handle b/8734824 * * We create a IGraphicBufferProducer wrapper that forwards all calls * from the surfaceflinger thread to the calling binder thread, where they * are executed. This allows the calling thread in the calling process to be * reused and not depend on having "enough" binder threads to handle the * requests. */ class GraphicProducerWrapper : public BBinder, public MessageHandler { /* Parts of GraphicProducerWrapper are run on two different threads, * communicating by sending messages via Looper but also by shared member * data. Coherence maintenance is subtle and in places implicit (ugh). * * Don't rely on Looper's sendMessage/handleMessage providing * release/acquire semantics for any data not actually in the Message. * Data going from surfaceflinger to binder threads needs to be * synchronized explicitly. * * Barrier open/wait do provide release/acquire semantics. This provides * implicit synchronization for data coming back from binder to * surfaceflinger threads. */ sp impl; sp looper; status_t result; bool exitPending; bool exitRequested; Barrier barrier; uint32_t code; Parcel const* data; Parcel* reply; enum { MSG_API_CALL, MSG_EXIT }; /* * Called on surfaceflinger thread. This is called by our "fake" * BpGraphicBufferProducer. We package the data and reply Parcel and * forward them to the binder thread. */ virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t /* flags */) { this->code = code; this->data = &data; this->reply = reply; if (exitPending) { // if we've exited, we run the message synchronously right here. // note (JH): as far as I can tell from looking at the code, this // never actually happens. if it does, i'm not sure if it happens // on the surfaceflinger or binder thread. handleMessage(Message(MSG_API_CALL)); } else { barrier.close(); // Prevent stores to this->{code, data, reply} from being // reordered later than the construction of Message. atomic_thread_fence(memory_order_release); looper->sendMessage(this, Message(MSG_API_CALL)); barrier.wait(); } return result; } /* * here we run on the binder thread. All we've got to do is * call the real BpGraphicBufferProducer. */ virtual void handleMessage(const Message& message) { int what = message.what; // Prevent reads below from happening before the read from Message atomic_thread_fence(memory_order_acquire); if (what == MSG_API_CALL) { result = IInterface::asBinder(impl)->transact(code, data[0], reply); barrier.open(); } else if (what == MSG_EXIT) { exitRequested = true; } } public: GraphicProducerWrapper(const sp& impl) : impl(impl), looper(new Looper(true)), result(NO_ERROR), exitPending(false), exitRequested(false), code(0), data(NULL), reply(NULL) {} // Binder thread status_t waitForResponse() { do { looper->pollOnce(-1); } while (!exitRequested); return result; } // Client thread void exit(status_t result) { this->result = result; exitPending = true; // Ensure this->result is visible to the binder thread before it // handles the message. atomic_thread_fence(memory_order_release); looper->sendMessage(this, Message(MSG_EXIT)); } }; status_t SurfaceFlinger::captureScreen(const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { if (CC_UNLIKELY(display == 0)) return BAD_VALUE; if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; // if we have secure windows on this display, never allow the screen capture // unless the producer interface is local (i.e.: we can take a screenshot for // ourselves). bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); // Convert to surfaceflinger's internal rotation type. Transform::orientation_flags rotationFlags; switch (rotation) { case ISurfaceComposer::eRotateNone: rotationFlags = Transform::ROT_0; break; case ISurfaceComposer::eRotate90: rotationFlags = Transform::ROT_90; break; case ISurfaceComposer::eRotate180: rotationFlags = Transform::ROT_180; break; case ISurfaceComposer::eRotate270: rotationFlags = Transform::ROT_270; break; default: rotationFlags = Transform::ROT_0; ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); break; } class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; sp display; sp producer; Rect sourceCrop; uint32_t reqWidth, reqHeight; uint32_t minLayerZ,maxLayerZ; bool useIdentityTransform; Transform::orientation_flags rotation; status_t result; bool isLocalScreenshot; public: MessageCaptureScreen(SurfaceFlinger* flinger, const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot) : flinger(flinger), display(display), producer(producer), sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), useIdentityTransform(useIdentityTransform), rotation(rotation), result(PERMISSION_DENIED), isLocalScreenshot(isLocalScreenshot) { } status_t getResult() const { return result; } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp hw(flinger->getDisplayDevice(display)); result = flinger->captureScreenImplLocked(hw, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, rotation, isLocalScreenshot); static_cast(IInterface::asBinder(producer).get())->exit(result); return true; } }; // this creates a "fake" BBinder which will serve as a "fake" remote // binder to receive the marshaled calls and forward them to the // real remote (a BpGraphicBufferProducer) sp wrapper = new GraphicProducerWrapper(producer); // the asInterface() call below creates our "fake" BpGraphicBufferProducer // which does the marshaling work forwards to our "fake remote" above. sp msg = new MessageCaptureScreen(this, display, IGraphicBufferProducer::asInterface( wrapper ), sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, rotationFlags, isLocalScreenshot); status_t res = postMessageAsync(msg); if (res == NO_ERROR) { res = wrapper->waitForResponse(); } return res; } void SurfaceFlinger::renderScreenImplLocked( const sp& hw, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) { ATRACE_CALL(); RenderEngine& engine(getRenderEngine()); // get screen geometry const int32_t hw_w = hw->getWidth(); const int32_t hw_h = hw->getHeight(); const bool filtering = static_cast(reqWidth) != hw_w || static_cast(reqHeight) != hw_h; // if a default or invalid sourceCrop is passed in, set reasonable values if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) { sourceCrop.setLeftTop(Point(0, 0)); sourceCrop.setRightBottom(Point(hw_w, hw_h)); } // ensure that sourceCrop is inside screen if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } if (sourceCrop.right > hw_w) { ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } if (sourceCrop.bottom > hw_h) { ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); } // make sure to clear all GL error flags engine.checkErrors(); // set-up our viewport engine.setViewportAndProjection( reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); engine.disableTexturing(); // redraw the screen entirely... engine.clearWithColor(0, 0, 0, 1); const LayerVector& layers( mDrawingState.layersSortedByZ ); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack()) { if (state.z >= minLayerZ && state.z <= maxLayerZ) { if (layer->isVisible()) { if (filtering) layer->setFiltering(true); layer->draw(hw, useIdentityTransform); if (filtering) layer->setFiltering(false); } } } } hw->setViewportAndProjection(); } status_t SurfaceFlinger::captureScreenImplLocked( const sp& hw, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot) { ATRACE_CALL(); // get screen geometry uint32_t hw_w = hw->getWidth(); uint32_t hw_h = hw->getHeight(); if (rotation & Transform::ROT_90) { std::swap(hw_w, hw_h); } if ((reqWidth > hw_w) || (reqHeight > hw_h)) { ALOGE("size mismatch (%d, %d) > (%d, %d)", reqWidth, reqHeight, hw_w, hw_h); return BAD_VALUE; } reqWidth = (!reqWidth) ? hw_w : reqWidth; reqHeight = (!reqHeight) ? hw_h : reqHeight; bool secureLayerIsVisible = false; const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i = 0 ; i < count ; ++i) { const sp& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ && state.z <= maxLayerZ && layer->isVisible() && layer->isSecure()) { secureLayerIsVisible = true; } } if (!isLocalScreenshot && secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED"); return PERMISSION_DENIED; } // create a surface (because we're a producer, and we need to // dequeue/queue a buffer) sp sur = new Surface(producer, false); ANativeWindow* window = sur.get(); status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); if (result == NO_ERROR) { uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; int err = 0; err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); err |= native_window_set_usage(window, usage); if (err == NO_ERROR) { ANativeWindowBuffer* buffer; /* TODO: Once we have the sync framework everywhere this can use * server-side waits on the fence that dequeueBuffer returns. */ result = native_window_dequeue_buffer_and_wait(window, &buffer); if (result == NO_ERROR) { int syncFd = -1; // create an EGLImage from the buffer so we can later // turn it into a texture EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); if (image != EGL_NO_IMAGE_KHR) { // this binds the given EGLImage as a framebuffer for the // duration of this scope. RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); if (imageBond.getStatus() == NO_ERROR) { // this will in fact render into our dequeued buffer // via an FBO, which means we didn't have to create // an EGLSurface and therefore we're not // dependent on the context's EGLConfig. renderScreenImplLocked( hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, useIdentityTransform, rotation); // Attempt to create a sync khr object that can produce a sync point. If that // isn't available, create a non-dupable sync object in the fallback path and // wait on it directly. EGLSyncKHR sync; if (!DEBUG_SCREENSHOTS) { sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); // native fence fd will not be populated until flush() is done. getRenderEngine().flush(); } else { sync = EGL_NO_SYNC_KHR; } if (sync != EGL_NO_SYNC_KHR) { // get the sync fd syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ALOGW("captureScreen: failed to dup sync khr object"); syncFd = -1; } eglDestroySyncKHR(mEGLDisplay, sync); } else { // fallback path sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); if (sync != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); EGLint eglErr = eglGetError(); if (result == EGL_TIMEOUT_EXPIRED_KHR) { ALOGW("captureScreen: fence wait timed out"); } else { ALOGW_IF(eglErr != EGL_SUCCESS, "captureScreen: error waiting on EGL fence: %#x", eglErr); } eglDestroySyncKHR(mEGLDisplay, sync); } else { ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); } } if (DEBUG_SCREENSHOTS) { uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, hw, minLayerZ, maxLayerZ); delete [] pixels; } } else { ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); result = INVALID_OPERATION; window->cancelBuffer(window, buffer, syncFd); buffer = NULL; } // destroy our image eglDestroyImageKHR(mEGLDisplay, image); } else { result = BAD_VALUE; } if (buffer) { // queueBuffer takes ownership of syncFd result = window->queueBuffer(window, buffer, syncFd); } } } else { result = BAD_VALUE; } native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } return result; } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, const sp& hw, uint32_t minLayerZ, uint32_t maxLayerZ) { if (DEBUG_SCREENSHOTS) { for (size_t y=0 ; ygetLayerStack()); const LayerVector& layers( mDrawingState.layersSortedByZ ); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); const bool visible = (state.layerStack == hw->getLayerStack()) && (state.z >= minLayerZ && state.z <= maxLayerZ) && (layer->isVisible()); ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", visible ? '+' : '-', i, layer->getName().string(), state.layerStack, state.z, layer->isVisible(), state.flags, state.alpha); } } } // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector() { } SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) : SortedVector >(rhs) { } int SurfaceFlinger::LayerVector::do_compare(const void* lhs, const void* rhs) const { // sort layers per layer-stack, then by z-order and finally by sequence const sp& l(*reinterpret_cast*>(lhs)); const sp& r(*reinterpret_cast*>(rhs)); uint32_t ls = l->getCurrentState().layerStack; uint32_t rs = r->getCurrentState().layerStack; if (ls != rs) return ls - rs; uint32_t lz = l->getCurrentState().z; uint32_t rz = r->getCurrentState().z; if (lz != rz) return lz - rz; return l->sequence - r->sequence; } // --------------------------------------------------------------------------- SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() : type(DisplayDevice::DISPLAY_ID_INVALID), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0), isSecure(false) { } SurfaceFlinger::DisplayDeviceState::DisplayDeviceState( DisplayDevice::DisplayType type, bool isSecure) : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0), isSecure(isSecure) { viewport.makeInvalid(); frame.makeInvalid(); } // --------------------------------------------------------------------------- }; // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" #endif #if defined(__gl2_h_) #error "don't include gl2/gl2.h in this file" #endif services/surfaceflinger/SurfaceFlinger.h0100644 0000000 0000000 00000044273 13077405420 017513 0ustar000000000 0000000 /* * Copyright (C) 2007 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_SURFACE_FLINGER_H #define ANDROID_SURFACE_FLINGER_H #include #include #include /* * NOTE: Make sure this file doesn't include anything from or */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Barrier.h" #include "DisplayDevice.h" #include "DispSync.h" #include "FenceTracker.h" #include "FrameTracker.h" #include "MessageQueue.h" #include "DisplayHardware/HWComposer.h" #include "Effects/Daltonizer.h" namespace android { // --------------------------------------------------------------------------- class Client; class DisplayEventConnection; class EventThread; class IGraphicBufferAlloc; class Layer; class LayerDim; class Surface; class RenderEngine; class EventControlThread; // --------------------------------------------------------------------------- enum { eTransactionNeeded = 0x01, eTraversalNeeded = 0x02, eDisplayTransactionNeeded = 0x04, eTransactionMask = 0x07 }; class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWComposer::EventHandler { public: static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } SurfaceFlinger() ANDROID_API; // must be called before clients can connect void init() ANDROID_API; // starts SurfaceFlinger main loop in the current thread void run() ANDROID_API; enum { EVENT_VSYNC = HWC_EVENT_VSYNC }; // post an asynchronous message to the main thread status_t postMessageAsync(const sp& msg, nsecs_t reltime = 0, uint32_t flags = 0); // post a synchronous message to the main thread status_t postMessageSync(const sp& msg, nsecs_t reltime = 0, uint32_t flags = 0); // force full composition on all displays void repaintEverything(); // returns the default Display sp getDefaultDisplayDevice() const { return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]); } // utility function to delete a texture on the main thread void deleteTextureAsync(uint32_t texture); // enable/disable h/w composer event // TODO: this should be made accessible only to EventThread #ifdef USE_HWC2 void setVsyncEnabled(int disp, int enabled); #else void eventControl(int disp, int event, int enabled); #endif // called on the main thread by MessageQueue when an internal message // is received // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); // for debugging only // TODO: this should be made accessible only to HWComposer const Vector< sp >& getLayerSortedByZForHwcDisplay(int id); RenderEngine& getRenderEngine() const { return *mRenderEngine; } private: friend class Client; friend class DisplayEventConnection; friend class Layer; friend class MonitoredProducer; // This value is specified in number of frames. Log frame stats at most // every half hour. enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; static const size_t MAX_LAYERS = 4096; // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); /* ------------------------------------------------------------------------ * Internal data structures */ class LayerVector : public SortedVector< sp > { public: LayerVector(); LayerVector(const LayerVector& rhs); virtual int do_compare(const void* lhs, const void* rhs) const; }; struct DisplayDeviceState { DisplayDeviceState(); DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure); bool isValid() const { return type >= 0; } bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; } bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; } DisplayDevice::DisplayType type; sp surface; uint32_t layerStack; Rect viewport; Rect frame; uint8_t orientation; uint32_t width, height; String8 displayName; bool isSecure; }; struct State { LayerVector layersSortedByZ; DefaultKeyedVector< wp, DisplayDeviceState> displays; }; /* ------------------------------------------------------------------------ * IBinder interface */ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); virtual status_t dump(int fd, const Vector& args); /* ------------------------------------------------------------------------ * ISurfaceComposer interface */ virtual sp createConnection(); virtual sp createGraphicBufferAlloc(); virtual sp createDisplay(const String8& displayName, bool secure); virtual void destroyDisplay(const sp& display); virtual sp getBuiltInDisplay(int32_t id); virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags); virtual void bootFinished(); virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const; virtual sp createDisplayEventConnection(); virtual status_t captureScreen(const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation); virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp& display, Vector* configs); virtual int getActiveConfig(const sp& display); virtual void setPowerMode(const sp& display, int mode); virtual status_t setActiveConfig(const sp& display, int id); virtual status_t clearAnimationFrameStats(); virtual status_t getAnimationFrameStats(FrameStats* outStats) const; virtual status_t getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities) const; /* ------------------------------------------------------------------------ * DeathRecipient interface */ virtual void binderDied(const wp& who); /* ------------------------------------------------------------------------ * RefBase interface */ virtual void onFirstRef(); /* ------------------------------------------------------------------------ * HWComposer::EventHandler interface */ virtual void onVSyncReceived(int type, nsecs_t timestamp); virtual void onHotplugReceived(int disp, bool connected); /* ------------------------------------------------------------------------ * Message handling */ void waitForEvent(); void signalTransaction(); void signalLayerUpdate(); void signalRefresh(); // called on the main thread in response to initializeDisplays() void onInitializeDisplays(); // called on the main thread in response to setActiveConfig() void setActiveConfigInternal(const sp& hw, int mode); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& hw, int mode); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); // Returns whether a new buffer has been latched (see handlePageFlip()) bool handleMessageInvalidate(); void handleMessageRefresh(); void handleTransaction(uint32_t transactionFlags); void handleTransactionLocked(uint32_t transactionFlags); void updateCursorAsync(); /* handlePageFlip - latch a new buffer if available and compute the dirty * region. Returns whether a new buffer has been latched, i.e., whether it * is necessary to perform a refresh during this vsync. */ bool handlePageFlip(); /* ------------------------------------------------------------------------ * Transactions */ uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); void commitTransaction(); uint32_t setClientStateLocked(const sp& client, const layer_state_t& s); uint32_t setDisplayStateLocked(const DisplayState& s); /* ------------------------------------------------------------------------ * Layer management */ status_t createLayer(const String8& name, const sp& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp); status_t createNormalLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp* outHandle, sp* outGbp, sp* outLayer); status_t createDimLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, sp* outHandle, sp* outGbp, sp* outLayer); // called in response to the window-manager calling // ISurfaceComposerClient::destroySurface() status_t onLayerRemoved(const sp& client, const sp& handle); // called when all clients have released all their references to // this layer meaning it is entirely safe to destroy all // resources associated to this layer. status_t onLayerDestroyed(const wp& layer); // remove a layer from SurfaceFlinger immediately status_t removeLayer(const sp& layer); // add a layer to SurfaceFlinger status_t addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc); /* ------------------------------------------------------------------------ * Boot animation, on/off animations and screen capture */ void startBootAnim(); void renderScreenImplLocked( const sp& hw, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation); status_t captureScreenImplLocked( const sp& hw, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot); /* ------------------------------------------------------------------------ * EGL */ size_t getMaxTextureSize() const; size_t getMaxViewportDims() const; /* ------------------------------------------------------------------------ * Display and layer stack management */ // called when starting, or restarting after system_server death void initializeDisplays(); // Create an IBinder for a builtin display and add it to current state void createBuiltinDisplayLocked(DisplayDevice::DisplayType type); // NOTE: can only be called from the main thread or with mStateLock held sp getDisplayDevice(const wp& dpy) const { return mDisplays.valueFor(dpy); } // NOTE: can only be called from the main thread or with mStateLock held sp getDisplayDevice(const wp& dpy) { return mDisplays.valueFor(dpy); } // mark a region of a layer stack dirty. this updates the dirty // region of all screens presenting this layer stack. void invalidateLayerStack(uint32_t layerStack, const Region& dirty); #ifndef USE_HWC2 int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type); #endif /* ------------------------------------------------------------------------ * H/W composer */ HWComposer& getHwComposer() const { return *mHwc; } /* ------------------------------------------------------------------------ * Compositing */ void invalidateHwcGeometry(); static void computeVisibleRegions( const LayerVector& currentLayers, uint32_t layerStack, Region& dirtyRegion, Region& opaqueRegion); void preComposition(); void postComposition(nsecs_t refreshStartTime); void rebuildLayerStacks(); void setUpHWComposer(); void doComposition(); void doDebugFlashRegions(); void doDisplayComposition(const sp& hw, const Region& dirtyRegion); // compose surfaces for display hw. this fails if using GL and the surface // has been destroyed and is no longer valid. bool doComposeSurfaces(const sp& hw, const Region& dirty); void postFramebuffer(); void drawWormhole(const sp& hw, const Region& region) const; /* ------------------------------------------------------------------------ * Display management */ /* ------------------------------------------------------------------------ * VSync */ void enableHardwareVsync(); void resyncToHardwareVsync(bool makeAvailable); void disableHardwareVsync(bool makeUnavailable); public: void resyncWithRateLimit(); private: /* ------------------------------------------------------------------------ * Debugging & dumpsys */ void listLayersLocked(const Vector& args, size_t& index, String8& result) const; void dumpStatsLocked(const Vector& args, size_t& index, String8& result) const; void clearStatsLocked(const Vector& args, size_t& index, String8& result); void dumpAllLocked(const Vector& args, size_t& index, String8& result) const; bool startDdmConnection(); static void appendSfConfigString(String8& result); void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, const sp& hw, uint32_t minLayerZ, uint32_t maxLayerZ); void logFrameStats(); void dumpStaticScreenStats(String8& result) const; /* ------------------------------------------------------------------------ * Attributes */ // access must be protected by mStateLock mutable Mutex mStateLock; State mCurrentState; volatile int32_t mTransactionFlags; Condition mTransactionCV; bool mTransactionPending; bool mAnimTransactionPending; Vector< sp > mLayersPendingRemoval; SortedVector< wp > mGraphicBufferProducerList; // protected by mStateLock (but we could use another lock) bool mLayersRemoved; // access must be protected by mInvalidateLock volatile int32_t mRepaintEverything; // constant members (no synchronization needed for access) HWComposer* mHwc; RenderEngine* mRenderEngine; nsecs_t mBootTime; bool mGpuToCpuSupported; bool mDropMissedFrames; sp mEventThread; sp mSFEventThread; sp mEventControlThread; EGLContext mEGLContext; EGLDisplay mEGLDisplay; sp mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState; bool mVisibleRegionsDirty; #ifndef USE_HWC2 bool mHwWorkListDirty; #else bool mGeometryInvalid; #endif bool mAnimCompositionPending; #ifdef USE_HWC2 std::vector> mLayersWithQueuedFrames; #endif // this may only be written from the main thread with mStateLock held // it may be read from other threads with mStateLock held DefaultKeyedVector< wp, sp > mDisplays; // don't use a lock for these, we don't care int mDebugRegion; int mDebugDDMS; int mDebugDisableHWC; int mDebugDisableTransformHint; volatile nsecs_t mDebugInSwapBuffers; nsecs_t mLastSwapBufferTime; volatile nsecs_t mDebugInTransaction; nsecs_t mLastTransactionTime; bool mBootFinished; bool mForceFullDamage; FenceTracker mFenceTracker; // these are thread safe mutable MessageQueue mEventQueue; FrameTracker mAnimFrameTracker; DispSync mPrimaryDispSync; // protected by mDestroyedLayerLock; mutable Mutex mDestroyedLayerLock; Vector mDestroyedLayers; // protected by mHWVsyncLock Mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled; bool mHWVsyncAvailable; /* ------------------------------------------------------------------------ * Feature prototyping */ Daltonizer mDaltonizer; bool mDaltonize; mat4 mColorMatrix; bool mHasColorMatrix; // Static screen stats bool mHasPoweredOff; static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ nsecs_t mFrameBuckets[NUM_BUCKETS]; nsecs_t mTotalTime; std::atomic mLastSwapTime; }; }; // namespace android #endif // ANDROID_SURFACE_FLINGER_H services/surfaceflinger/SurfaceFlingerConsumer.cpp0100644 0000000 0000000 00000021202 13077405420 021545 0ustar000000000 0000000 /* * Copyright (C) 2012 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include "SurfaceFlingerConsumer.h" #include #include #include #include #include namespace android { // --------------------------------------------------------------------------- status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber) { ATRACE_CALL(); ALOGV("updateTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { ALOGE("updateTexImage: GLConsumer is abandoned!"); return NO_INIT; } // Make sure the EGL state is the same as in previous calls. status_t err = checkAndUpdateEglStateLocked(); if (err != NO_ERROR) { return err; } BufferItem item; // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { err = NO_ERROR; } else if (err == BufferQueue::PRESENT_LATER) { // return the error, without logging } else { ALOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); } return err; } // We call the rejecter here, in case the caller has a reason to // not accept this buffer. This is used by SurfaceFlinger to // reject buffers which have the wrong size int slot = item.mSlot; if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR); return BUFFER_REJECTED; } if (autoRefresh) { *autoRefresh = item.mAutoRefresh; } if (queuedBuffer) { *queuedBuffer = item.mQueuedBuffer; } // Release the previous buffer. #ifdef USE_HWC2 err = updateAndReleaseLocked(item, &mPendingRelease); #else err = updateAndReleaseLocked(item); #endif if (err != NO_ERROR) { return err; } if (!SyncFeatures::getInstance().useNativeFenceSync()) { // Bind the new buffer to the GL texture. // // Older devices require the "implicit" synchronization provided // by glEGLImageTargetTexture2DOES, which this method calls. Newer // devices will either call this in Layer::onDraw, or (if it's not // a GL-composited layer) not at all. err = bindTextureImageLocked(); } return err; } status_t SurfaceFlingerConsumer::bindTextureImage() { Mutex::Autolock lock(mMutex); return bindTextureImageLocked(); } status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, uint64_t maxFrameNumber) { status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, maxFrameNumber); if (result == NO_ERROR) { mTransformToDisplayInverse = item->mTransformToDisplayInverse; mSurfaceDamage = item->mSurfaceDamage; } return result; } bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { return mTransformToDisplayInverse; } const Region& SurfaceFlingerConsumer::getSurfaceDamage() const { return mSurfaceDamage; } sp SurfaceFlingerConsumer::getSidebandStream() const { return mConsumer->getSidebandStream(); } // We need to determine the time when a buffer acquired now will be // displayed. This can be calculated: // time when previous buffer's actual-present fence was signaled // + current display refresh rate * HWC latency // + a little extra padding // // Buffer producers are expected to set their desired presentation time // based on choreographer time stamps, which (coming from vsync events) // will be slightly later then the actual-present timing. If we get a // desired-present time that is unintentionally a hair after the next // vsync, we'll hold the frame when we really want to display it. We // need to take the offset between actual-present and reported-vsync // into account. // // If the system is configured without a DispSync phase offset for the app, // we also want to throw in a bit of padding to avoid edge cases where we // just barely miss. We want to do it here, not in every app. A major // source of trouble is the app's use of the display's ideal refresh time // (via Display.getRefreshRate()), which could be off of the actual refresh // by a few percent, with the error multiplied by the number of frames // between now and when the buffer should be displayed. // // If the refresh reported to the app has a phase offset, we shouldn't need // to tweak anything here. nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync) { // The HWC doesn't currently have a way to report additional latency. // Assume that whatever we submit now will appear right after the flip. // For a smart panel this might be 1. This is expressed in frames, // rather than time, because we expect to have a constant frame delay // regardless of the refresh rate. const uint32_t hwcLatency = 0; // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency); // The DispSync time is already adjusted for the difference between // vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so // we don't need to factor that in here. Pad a little to avoid // weird effects if apps might be requesting times right on the edge. nsecs_t extraPadding = 0; if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) { extraPadding = 1000000; // 1ms (6% of 60Hz) } return nextRefresh + extraPadding; } #ifdef USE_HWC2 void SurfaceFlingerConsumer::setReleaseFence(const sp& fence) { mPrevReleaseFence = fence; if (!mPendingRelease.isPending) { GLConsumer::setReleaseFence(fence); return; } auto currentTexture = mPendingRelease.currentTexture; if (fence->isValid() && currentTexture != BufferQueue::INVALID_BUFFER_SLOT) { status_t result = addReleaseFence(currentTexture, mPendingRelease.graphicBuffer, fence); ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the" " fence: %s (%d)", strerror(-result), result); } } void SurfaceFlingerConsumer::releasePendingBuffer() { if (!mPendingRelease.isPending) { ALOGV("Pending buffer already released"); return; } ALOGV("Releasing pending buffer"); Mutex::Autolock lock(mMutex); status_t result = releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer, mPendingRelease.display, mPendingRelease.fence); ALOGE_IF(result != NO_ERROR, "releasePendingBuffer failed: %s (%d)", strerror(-result), result); mPendingRelease = PendingRelease(); } #else void SurfaceFlingerConsumer::setReleaseFence(const sp& fence) { mPrevReleaseFence = fence; GLConsumer::setReleaseFence(fence); } #endif sp SurfaceFlingerConsumer::getPrevReleaseFence() const { return mPrevReleaseFence; } void SurfaceFlingerConsumer::setContentsChangedListener( const wp& listener) { setFrameAvailableListener(listener); Mutex::Autolock lock(mMutex); mContentsChangedListener = listener; } void SurfaceFlingerConsumer::onSidebandStreamChanged() { sp listener; { // scope for the lock Mutex::Autolock lock(mMutex); ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get()); listener = mContentsChangedListener.promote(); } if (listener != NULL) { listener->onSidebandStreamChanged(); } } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/SurfaceFlingerConsumer.h0100644 0000000 0000000 00000007404 13077405420 021222 0ustar000000000 0000000 /* * Copyright (C) 2012 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_SURFACEFLINGERCONSUMER_H #define ANDROID_SURFACEFLINGERCONSUMER_H #include "DispSync.h" #include namespace android { // ---------------------------------------------------------------------------- /* * This is a thin wrapper around GLConsumer. */ class SurfaceFlingerConsumer : public GLConsumer { public: static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; struct ContentsChangedListener: public FrameAvailableListener { virtual void onSidebandStreamChanged() = 0; }; SurfaceFlingerConsumer(const sp& consumer, uint32_t tex) : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), mTransformToDisplayInverse(false), mSurfaceDamage(), mPrevReleaseFence(Fence::NO_FENCE) {} class BufferRejecter { friend class SurfaceFlingerConsumer; virtual bool reject(const sp& buf, const BufferItem& item) = 0; protected: virtual ~BufferRejecter() { } }; virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber = 0) override; // This version of updateTexImage() takes a functor that may be used to // reject the newly acquired buffer. Unlike the GLConsumer version, // this does not guarantee that the buffer has been bound to the GL // texture. status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber = 0); // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); // must be called from SF main thread bool getTransformToDisplayInverse() const; const Region& getSurfaceDamage() const; // Sets the contents changed listener. This should be used instead of // ConsumerBase::setFrameAvailableListener(). void setContentsChangedListener(const wp& listener); sp getSidebandStream() const; nsecs_t computeExpectedPresent(const DispSync& dispSync); virtual void setReleaseFence(const sp& fence) override; sp getPrevReleaseFence() const; #ifdef USE_HWC2 void releasePendingBuffer(); #endif private: virtual void onSidebandStreamChanged(); wp mContentsChangedListener; // Indicates this buffer must be transformed by the inverse transform of the screen // it is displayed onto. This is applied after GLConsumer::mCurrentTransform. // This must be set/read from SurfaceFlinger's main thread. bool mTransformToDisplayInverse; // The portion of this surface that has changed since the previous frame Region mSurfaceDamage; #ifdef USE_HWC2 // A release that is pending on the receipt of a new release fence from // presentDisplay PendingRelease mPendingRelease; #endif // The release fence of the already displayed buffer (previous frame). sp mPrevReleaseFence; }; // ---------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SURFACEFLINGERCONSUMER_H services/surfaceflinger/SurfaceFlinger_hwc1.cpp0100644 0000000 0000000 00000406145 13077405420 020770 0ustar000000000 0000000 /* * Copyright (C) 2007 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Client.h" #include "clz.h" #include "Colorizer.h" #include "DdmConnection.h" #include "DisplayDevice.h" #include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" #include "Layer.h" #include "LayerDim.h" #include "SurfaceFlinger.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "Effects/Daltonizer.h" #include "RenderEngine/RenderEngine.h" #include #define DISPLAY_COUNT 1 /* * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all * black pixels. */ #define DEBUG_SCREENSHOTS false EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); namespace android { // This is the phase offset in nanoseconds of the software vsync event // relative to the vsync event reported by HWComposer. The software vsync // event is when SurfaceFlinger and Choreographer-based applications run each // frame. // // This phase offset allows adjustment of the minimum latency from application // wake-up (by Choregographer) time to the time at which the resulting window // image is displayed. This value may be either positive (after the HW vsync) // or negative (before the HW vsync). Setting it to 0 will result in a // minimum latency of two vsync periods because the app and SurfaceFlinger // will run just after the HW vsync. Setting it to a positive number will // result in the minimum latency being: // // (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD)) // // Note that reducing this latency makes it more likely for the applications // to not have their window content image ready in time. When this happens // the latency will end up being an additional vsync period, and animations // will hiccup. Therefore, this latency should be tuned somewhat // conservatively (or at least with awareness of the trade-off being made). static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS; // This is the phase offset at which SurfaceFlinger's composition runs. static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS; // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); // --------------------------------------------------------------------------- SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), mTransactionPending(false), mAnimTransactionPending(false), mLayersRemoved(false), mRepaintEverything(0), mRenderEngine(NULL), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), mAnimCompositionPending(false), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), mDebugDisableTransformHint(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), mLastTransactionTime(0), mBootFinished(false), mForceFullDamage(false), mPrimaryDispSync("PrimaryDispSync"), mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), mHasColorMatrix(false), mHasPoweredOff(false), mFrameBuckets(), mTotalTime(0), mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); // debugging stuff... char value[PROPERTY_VALUE_MAX]; property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); property_get("debug.sf.drop_missed_frames", value, "0"); mDropMissedFrames = atoi(value); property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); property_get("debug.sf.ddms", value, "0"); mDebugDDMS = atoi(value); if (mDebugDDMS) { if (!startDdmConnection()) { // start failed, and DDMS debugging not enabled mDebugDDMS = 0; } } ALOGI_IF(mDebugRegion, "showupdates enabled"); ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); } void SurfaceFlinger::onFirstRef() { mEventQueue.init(this); } SurfaceFlinger::~SurfaceFlinger() { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(display); } void SurfaceFlinger::binderDied(const wp& /* who */) { // the window manager died on us. prepare its eulogy. // restore initial conditions (default device unblank, etc) initializeDisplays(); // restart the boot-animation startBootAnim(); } sp SurfaceFlinger::createConnection() { sp bclient; sp client(new Client(this)); status_t err = client->initCheck(); if (err == NO_ERROR) { bclient = client; } return bclient; } sp SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { class DisplayToken : public BBinder { sp flinger; virtual ~DisplayToken() { // no more references, this display must be terminated Mutex::Autolock _l(flinger->mStateLock); flinger->mCurrentState.displays.removeItem(this); flinger->setTransactionFlags(eDisplayTransactionNeeded); } public: DisplayToken(const sp& flinger) : flinger(flinger) { } }; sp token = new DisplayToken(this); Mutex::Autolock _l(mStateLock); DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); info.displayName = displayName; mCurrentState.displays.add(token, info); return token; } void SurfaceFlinger::destroyDisplay(const sp& display) { Mutex::Autolock _l(mStateLock); ssize_t idx = mCurrentState.displays.indexOfKey(display); if (idx < 0) { ALOGW("destroyDisplay: invalid display token"); return; } const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx)); if (!info.isVirtualDisplay()) { ALOGE("destroyDisplay called for non-virtual display"); return; } mCurrentState.displays.removeItemsAt(idx); setTransactionFlags(eDisplayTransactionNeeded); } void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) { ALOGW_IF(mBuiltinDisplays[type], "Overwriting display token for display type %d", type); mBuiltinDisplays[type] = new BBinder(); // All non-virtual displays are currently considered secure. DisplayDeviceState info(type, true); mCurrentState.displays.add(mBuiltinDisplays[type], info); } sp SurfaceFlinger::getBuiltInDisplay(int32_t id) { if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); return NULL; } return mBuiltinDisplays[id]; } sp SurfaceFlinger::createGraphicBufferAlloc() { sp gba(new GraphicBufferAlloc()); return gba; } void SurfaceFlinger::bootFinished() { const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mBootFinished = true; // wait patiently for the window manager death const String16 name("window"); sp window(defaultServiceManager()->getService(name)); if (window != 0) { window->linkToDeath(static_cast(this)); } // stop boot animation // formerly we would just kill the process, but we now ask it to exit so it // can choose where to stop the animation. property_set("service.bootanim.exit", "1"); const int LOGTAG_SF_STOP_BOOTANIM = 60110; LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { class MessageDestroyGLTexture : public MessageBase { RenderEngine& engine; uint32_t texture; public: MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture) : engine(engine), texture(texture) { } virtual bool handler() { engine.deleteTextures(1, &texture); return true; } }; postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture)); } class DispSyncSource : public VSyncSource, private DispSync::Callback { public: DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name) : mName(name), mValue(0), mTraceVsync(traceVsync), mVsyncOnLabel(String8::format("VsyncOn-%s", name)), mVsyncEventLabel(String8::format("VSYNC-%s", name)), mDispSync(dispSync), mCallbackMutex(), mCallback(), mVsyncMutex(), mPhaseOffset(phaseOffset), mEnabled(false) {} virtual ~DispSyncSource() {} virtual void setVSyncEnabled(bool enable) { Mutex::Autolock lock(mVsyncMutex); if (enable) { status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } //ATRACE_INT(mVsyncOnLabel.string(), 1); } else { status_t err = mDispSync->removeEventListener( static_cast(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } //ATRACE_INT(mVsyncOnLabel.string(), 0); } mEnabled = enable; } virtual void setCallback(const sp& callback) { Mutex::Autolock lock(mCallbackMutex); mCallback = callback; } virtual void setPhaseOffset(nsecs_t phaseOffset) { Mutex::Autolock lock(mVsyncMutex); // Normalize phaseOffset to [0, period) auto period = mDispSync->getPeriod(); phaseOffset %= period; if (phaseOffset < 0) { // If we're here, then phaseOffset is in (-period, 0). After this // operation, it will be in (0, period) phaseOffset += period; } mPhaseOffset = phaseOffset; // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { return; } // Remove the listener with the old offset status_t err = mDispSync->removeEventListener( static_cast(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } // Add a listener with the new offset err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } } private: virtual void onDispSyncEvent(nsecs_t when) { sp callback; { Mutex::Autolock lock(mCallbackMutex); callback = mCallback; if (mTraceVsync) { mValue = (mValue + 1) % 2; ATRACE_INT(mVsyncEventLabel.string(), mValue); } } if (callback != NULL) { callback->onVSyncEvent(when); } } const char* const mName; int mValue; const bool mTraceVsync; const String8 mVsyncOnLabel; const String8 mVsyncEventLabel; DispSync* mDispSync; Mutex mCallbackMutex; // Protects the following sp mCallback; Mutex mVsyncMutex; // Protects the following nsecs_t mPhaseOffset; bool mEnabled; }; void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); Mutex::Autolock _l(mStateLock); // initialize EGL for the default display mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(mEGLDisplay, NULL, NULL); // start the EventThread sp vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true, "app"); mEventThread = new EventThread(vsyncSrc, *this); sp sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, sfVsyncPhaseOffsetNs, true, "sf"); mSFEventThread = new EventThread(sfVsyncSrc, *this); mEventQueue.setEventThread(mSFEventThread); // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. mHwc = new HWComposer(this, *static_cast(this)); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID()); // retrieve the EGL context that was selected/created mEGLContext = mRenderEngine->getEGLContext(); LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); // initialize our non-virtual displays for (size_t i=0 ; iisConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { // All non-virtual displays are currently considered secure. bool isSecure = true; createBuiltinDisplayLocked(type); wp token = mBuiltinDisplays[i]; sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp hw = new DisplayDevice(this, type, hwcId, mHwc->getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests // for displays other than the main display, so we always // assume a connected display is unblanked. ALOGD("marking display %zu as acquired/unblanked", i); hw->setPowerMode(HWC_POWER_MODE_NORMAL); } mDisplays.add(token, hw); } } // make the GLContext current so that we can create textures when creating Layers // (which may happens before we render something) getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); // set a fake vsync period if there is no HWComposer if (mHwc->initCheck() != NO_ERROR) { mPrimaryDispSync.setPeriod(16666667); } // initialize our drawing state mDrawingState = mCurrentState; // set initial conditions (e.g. unblank default device) initializeDisplays(); // start boot animation startBootAnim(); } int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) { return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ? type : mHwc->allocateDisplayId(); } void SurfaceFlinger::startBootAnim() { // start boot animation property_set("service.bootanim.exit", "0"); property_set("ctl.start", "bootanim"); } size_t SurfaceFlinger::getMaxTextureSize() const { return mRenderEngine->getMaxTextureSize(); } size_t SurfaceFlinger::getMaxViewportDims() const { return mRenderEngine->getMaxViewportDims(); } // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( const sp& bufferProducer) const { Mutex::Autolock _l(mStateLock); sp surfaceTextureBinder(IInterface::asBinder(bufferProducer)); return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } status_t SurfaceFlinger::getDisplayConfigs(const sp& display, Vector* configs) { if ((configs == NULL) || (display.get() == NULL)) { return BAD_VALUE; } if (!display.get()) return NAME_NOT_FOUND; int32_t type = NAME_NOT_FOUND; for (int i=0 ; i 0) { density = atoi(property); } return density; } public: static int getEmuDensity() { return getDensityFromProperty("qemu.sf.lcd_density"); } static int getBuildDensity() { return getDensityFromProperty("ro.sf.lcd_density"); } }; configs->clear(); const Vector& hwConfigs = getHwComposer().getConfigs(type); for (size_t c = 0; c < hwConfigs.size(); ++c) { const HWComposer::DisplayConfig& hwConfig = hwConfigs[c]; DisplayInfo info = DisplayInfo(); float xdpi = hwConfig.xdpi; float ydpi = hwConfig.ydpi; if (type == DisplayDevice::DISPLAY_PRIMARY) { // The density of the device is provided by a build property float density = Density::getBuildDensity() / 160.0f; if (density == 0) { // the build doesn't provide a density -- this is wrong! // use xdpi instead ALOGE("ro.sf.lcd_density must be defined as a build property"); density = xdpi / 160.0f; } if (Density::getEmuDensity()) { // if "qemu.sf.lcd_density" is specified, it overrides everything xdpi = ydpi = density = Density::getEmuDensity(); density /= 160.0f; } info.density = density; // TODO: this needs to go away (currently needed only by webkit) sp hw(getDefaultDisplayDevice()); info.orientation = hw->getOrientation(); } else { // TODO: where should this value come from? static const int TV_DENSITY = 213; info.density = TV_DENSITY / 160.0f; info.orientation = 0; } info.w = hwConfig.width; info.h = hwConfig.height; info.xdpi = xdpi; info.ydpi = ydpi; info.fps = float(1e9 / hwConfig.refresh); info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; info.colorTransform = hwConfig.colorTransform; // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear // on the screen at time N, you must submit the buffer before // (N - presentationDeadline). // // Normally it's one full refresh period (to give SF a chance to // latch the buffer), but this can be reduced by configuring a // DispSync offset. Any additional delays introduced by the hardware // composer or panel must be accounted for here. // // We add an additional 1ms to allow for processing time and // differences between the ideal and actual refresh rate. info.presentationDeadline = hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000; // All non-virtual displays are currently considered secure. info.secure = true; configs->push_back(info); } return NO_ERROR; } status_t SurfaceFlinger::getDisplayStats(const sp& /* display */, DisplayStatInfo* stats) { if (stats == NULL) { return BAD_VALUE; } // FIXME for now we always return stats for the primary display memset(stats, 0, sizeof(*stats)); stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0); stats->vsyncPeriod = mPrimaryDispSync.getPeriod(); return NO_ERROR; } int SurfaceFlinger::getActiveConfig(const sp& display) { sp device(getDisplayDevice(display)); if (device != NULL) { return device->getActiveConfig(); } return BAD_VALUE; } void SurfaceFlinger::setActiveConfigInternal(const sp& hw, int mode) { ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); int currentMode = hw->getActiveConfig(); if (mode == currentMode) { ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); return; } if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGW("Trying to set config for virtual display"); return; } hw->setActiveConfig(mode); getHwComposer().setActiveConfig(type, mode); } status_t SurfaceFlinger::setActiveConfig(const sp& display, int mode) { class MessageSetActiveConfig: public MessageBase { SurfaceFlinger& mFlinger; sp mDisplay; int mMode; public: MessageSetActiveConfig(SurfaceFlinger& flinger, const sp& disp, int mode) : mFlinger(flinger), mDisplay(disp) { mMode = mode; } virtual bool handler() { Vector configs; mFlinger.getDisplayConfigs(mDisplay, &configs); if (mMode < 0 || mMode >= static_cast(configs.size())) { ALOGE("Attempt to set active config = %d for display with %zu configs", mMode, configs.size()); } sp hw(mFlinger.getDisplayDevice(mDisplay)); if (hw == NULL) { ALOGE("Attempt to set active config = %d for null display %p", mMode, mDisplay.get()); } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { ALOGW("Attempt to set active config = %d for virtual display", mMode); } else { mFlinger.setActiveConfigInternal(hw, mMode); } return true; } }; sp msg = new MessageSetActiveConfig(*this, display, mode); postMessageSync(msg); return NO_ERROR; } status_t SurfaceFlinger::clearAnimationFrameStats() { Mutex::Autolock _l(mStateLock); mAnimFrameTracker.clearStats(); return NO_ERROR; } status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { Mutex::Autolock _l(mStateLock); mAnimFrameTracker.getStats(outStats); return NO_ERROR; } status_t SurfaceFlinger::getHdrCapabilities(const sp& /*display*/, HdrCapabilities* outCapabilities) const { // HWC1 does not provide HDR capabilities *outCapabilities = HdrCapabilities(); return NO_ERROR; } // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection() { return mEventThread->createEventConnection(); } // ---------------------------------------------------------------------------- void SurfaceFlinger::waitForEvent() { mEventQueue.waitMessage(); } void SurfaceFlinger::signalTransaction() { mEventQueue.invalidate(); } void SurfaceFlinger::signalLayerUpdate() { mEventQueue.invalidate(); } void SurfaceFlinger::signalRefresh() { mEventQueue.refresh(); } status_t SurfaceFlinger::postMessageAsync(const sp& msg, nsecs_t reltime, uint32_t /* flags */) { return mEventQueue.postMessage(msg, reltime); } status_t SurfaceFlinger::postMessageSync(const sp& msg, nsecs_t reltime, uint32_t /* flags */) { status_t res = mEventQueue.postMessage(msg, reltime); if (res == NO_ERROR) { msg->wait(); } return res; } void SurfaceFlinger::run() { do { waitForEvent(); } while (true); } void SurfaceFlinger::enableHardwareVsync() { Mutex::Autolock _l(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mPrimaryDispSync.beginResync(); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { Mutex::Autolock _l(mHWVsyncLock); if (makeAvailable) { mHWVsyncAvailable = true; } else if (!mHWVsyncAvailable) { // Hardware vsync is not currently available, so abort the resync // attempt for now return; } const nsecs_t period = getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); mPrimaryDispSync.reset(); mPrimaryDispSync.setPeriod(period); if (!mPrimaryHWVsyncEnabled) { mPrimaryDispSync.beginResync(); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { Mutex::Autolock _l(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); mEventControlThread->setVsyncEnabled(false); mPrimaryDispSync.endResync(); mPrimaryHWVsyncEnabled = false; } if (makeUnavailable) { mHWVsyncAvailable = false; } } void SurfaceFlinger::resyncWithRateLimit() { static constexpr nsecs_t kIgnoreDelay = ms2ns(500); if (systemTime() - mLastSwapTime > kIgnoreDelay) { resyncToHardwareVsync(false); } } void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) { bool needsHwVsync = false; { // Scope for the lock Mutex::Autolock _l(mHWVsyncLock); if (type == 0 && mPrimaryHWVsyncEnabled) { needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } if (needsHwVsync) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } void SurfaceFlinger::onHotplugReceived(int type, bool connected) { if (mEventThread == NULL) { // This is a temporary workaround for b/7145521. A non-null pointer // does not mean EventThread has finished initializing, so this // is not a correct fix. ALOGW("WARNING: EventThread not started, ignoring hotplug"); return; } if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { Mutex::Autolock _l(mStateLock); if (connected) { createBuiltinDisplayLocked((DisplayDevice::DisplayType)type); } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); mBuiltinDisplays[type].clear(); } setTransactionFlags(eDisplayTransactionNeeded); // Defer EventThread notification until SF has updated mDisplays. } } void SurfaceFlinger::eventControl(int disp, int event, int enabled) { ATRACE_CALL(); getHwComposer().eventControl(disp, event, enabled); } void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { bool refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); refreshNeeded |= mRepaintEverything; if (refreshNeeded) { // Signal a refresh if a transaction modified the window state, // a new buffer was latched, or if HWC has requested a full // repaint signalRefresh(); } break; } case MessageQueue::REFRESH: { handleMessageRefresh(); break; } } } bool SurfaceFlinger::handleMessageTransaction() { uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); if (transactionFlags) { handleTransaction(transactionFlags); return true; } return false; } bool SurfaceFlinger::handleMessageInvalidate() { ATRACE_CALL(); return handlePageFlip(); } void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); #ifdef ENABLE_FENCE_TRACKING nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); #else nsecs_t refreshStartTime = 0; #endif static nsecs_t previousExpectedPresent = 0; nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0); static bool previousFrameMissed = false; bool frameMissed = (expectedPresent == previousExpectedPresent); if (frameMissed != previousFrameMissed) { ATRACE_INT("FrameMissed", static_cast(frameMissed)); } previousFrameMissed = frameMissed; if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) { // Latch buffers, but don't send anything to HWC, then signal another // wakeup for the next vsync preComposition(); repaintEverything(); } else { preComposition(); rebuildLayerStacks(); setUpHWComposer(); doDebugFlashRegions(); doComposition(); postComposition(refreshStartTime); } previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0); } void SurfaceFlinger::doDebugFlashRegions() { // is debugging enabled if (CC_LIKELY(!mDebugRegion)) return; const bool repaintEverything = mRepaintEverything; for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); if (!dirtyRegion.isEmpty()) { // redraw the whole screen doComposeSurfaces(hw, Region(hw->bounds())); // and draw the dirty region const int32_t height = hw->getHeight(); RenderEngine& engine(getRenderEngine()); engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1); hw->compositionComplete(); hw->swapBuffers(getHwComposer()); } } } postFramebuffer(); if (mDebugRegion > 1) { usleep(mDebugRegion * 1000); } HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { status_t err = hwc.prepare(); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); } } void SurfaceFlinger::preComposition() { bool needExtraInvalidate = false; const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; ionPreComposition()) { needExtraInvalidate = true; } } if (needExtraInvalidate) { signalLayerUpdate(); } } #ifdef ENABLE_FENCE_TRACKING void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) #else void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/) #endif { const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; ionPostComposition(); } const HWComposer& hwc = getHwComposer(); sp presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); if (presentFence->isValid()) { if (mPrimaryDispSync.addPresentFence(presentFence)) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } const sp hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { if (hw->isDisplayOn()) { enableHardwareVsync(); } } #ifdef ENABLE_FENCE_TRACKING mFenceTracker.addFrame(refreshStartTime, presentFence, hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence()); #endif if (mAnimCompositionPending) { mAnimCompositionPending = false; if (presentFence->isValid()) { mAnimFrameTracker.setActualPresentFence(presentFence); } else { // The HWC doesn't support present fences, so use the refresh // timestamp instead. nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); } if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { return; } nsecs_t currentTime = systemTime(); if (mHasPoweredOff) { mHasPoweredOff = false; } else { nsecs_t period = mPrimaryDispSync.getPeriod(); nsecs_t elapsedTime = currentTime - mLastSwapTime; size_t numPeriods = static_cast(elapsedTime / period); if (numPeriods < NUM_BUCKETS - 1) { mFrameBuckets[numPeriods] += elapsedTime; } else { mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; } mTotalTime += elapsedTime; } mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_CALL(); mVisibleRegionsDirty = false; invalidateHwcGeometry(); const LayerVector& layers(mDrawingState.layersSortedByZ); for (size_t dpy=0 ; dpy > layersSortedByZ; const sp& hw(mDisplays[dpy]); const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); if (hw->isDisplayOn()) { SurfaceFlinger::computeVisibleRegions(layers, hw->getLayerStack(), dirtyRegion, opaqueRegion); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& s(layer->getDrawingState()); if (s.layerStack == hw->getLayerStack()) { Region drawRegion(tr.transform( layer->visibleNonTransparentRegion)); drawRegion.andSelf(bounds); if (!drawRegion.isEmpty()) { layersSortedByZ.add(layer); } } } } hw->setVisibleLayersSortedByZ(layersSortedByZ); hw->undefinedRegion.set(bounds); hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); hw->dirtyRegion.orSelf(dirtyRegion); } } } void SurfaceFlinger::setUpHWComposer() { for (size_t dpy=0 ; dpygetDirtyRegion(false).isEmpty(); bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0; bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers; // If nothing has changed (!dirty), don't recompose. // If something changed, but we don't currently have any visible layers, // and didn't when we last did a composition, then skip it this time. // The second rule does two things: // - When all layers are removed from a display, we'll emit one black // frame, then nothing more until we get new layers. // - When a display is created with a private layer stack, we won't // emit any black frames until a layer is added to the layer stack. bool mustRecompose = dirty && !(empty && wasEmpty); ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL, "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy, mustRecompose ? "doing" : "skipping", dirty ? "+" : "-", empty ? "+" : "-", wasEmpty ? "+" : "-"); mDisplays[dpy]->beginFrame(mustRecompose); if (mustRecompose) { mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty; } } HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { // build the h/w work list if (CC_UNLIKELY(mHwWorkListDirty)) { mHwWorkListDirty = false; for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { const Vector< sp >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); if (hwc.createWorkList(id, count) == NO_ERROR) { HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); layer->setGeometry(hw, *cur); if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { cur->setSkip(true); } } } } } } // set the per-frame data for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { const Vector< sp >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); layer->setPerFrameData(hw, *cur); } } } // If possible, attempt to use the cursor overlay on each display. for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { const Vector< sp >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); if (layer->isPotentialCursor()) { cur->setIsCursorLayerHint(); break; } } } } status_t err = hwc.prepare(); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); hw->prepareFrame(hwc); } } } void SurfaceFlinger::doComposition() { ATRACE_CALL(); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); // repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } // inform the h/w that we're done compositing hw->compositionComplete(); } postFramebuffer(); } void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { if (!hwc.supportsFramebufferTarget()) { // EGL spec says: // "surface must be bound to the calling thread's current context, // for the current rendering API." getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); } hwc.commit(); } // make the default display current because the VirtualDisplayDevice code cannot // deal with dequeueBuffer() being called outside of the composition loop; however // the code below can call glFlush() which is allowed (and does in some case) call // dequeueBuffer(). getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const Vector< sp >& currentLayers(hw->getVisibleLayersSortedByZ()); hw->onSwapBuffersCompleted(hwc); const size_t count = currentLayers.size(); int32_t id = hw->getHwcDisplayId(); if (id >=0 && hwc.initCheck() == NO_ERROR) { HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i = 0; cur != end && i < count; ++i, ++cur) { currentLayers[i]->onLayerDisplayed(hw, &*cur); } } else { for (size_t i = 0; i < count; i++) { currentLayers[i]->onLayerDisplayed(hw, NULL); } } } mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); } } void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); // here we keep a copy of the drawing state (that is the state that's // going to be overwritten by handleTransactionLocked()) outside of // mStateLock so that the side-effects of the State assignment // don't happen with mStateLock held (which can cause deadlocks). State drawingState(mDrawingState); Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; // Here we're guaranteed that some transaction flags are set // so we can call handleTransactionLocked() unconditionally. // We call getTransactionFlags(), which will also clear the flags, // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; invalidateHwcGeometry(); // here the transaction has been committed } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); // Notify all layers of available frames for (size_t i = 0; i < count; ++i) { currentLayers[i]->notifyAvailableFrames(); } /* * Traversal of the children * (perform the transaction for each of them if needed) */ if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i& layer(currentLayers[i]); uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; const uint32_t flags = layer->doTransaction(0); if (flags & Layer::eVisibleRegion) mVisibleRegionsDirty = true; } } /* * Perform display own transactions if needed */ if (transactionFlags & eDisplayTransactionNeeded) { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when // know that the lists are identical const KeyedVector< wp, DisplayDeviceState>& curr(mCurrentState.displays); const KeyedVector< wp, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; const size_t cc = curr.size(); size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) for (size_t i=0 ; i defaultDisplay(getDefaultDisplayDevice()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); } else { ALOGW("trying to remove the main display"); } } else { // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp& display(curr.keyAt(j)); const sp state_binder = IInterface::asBinder(state.surface); const sp draw_binder = IInterface::asBinder(draw[i].surface); if (state_binder != draw_binder) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. sp hw(getDisplayDevice(display)); if (hw != NULL) hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; // at this point we must loop to the next item continue; } const sp disp(getDisplayDevice(display)); if (disp != NULL) { if (state.layerStack != draw[i].layerStack) { disp->setLayerStack(state.layerStack); } if ((state.orientation != draw[i].orientation) || (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { disp->setProjection(state.orientation, state.viewport, state.frame); } if (state.width != draw[i].width || state.height != draw[i].height) { disp->setDisplaySize(state.width, state.height); } } } } // find displays that were added // (ie: in current state but not in drawing state) for (size_t i=0 ; i dispSurface; sp producer; sp bqProducer; sp bqConsumer; BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc()); int32_t hwcDisplayId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { int width = 0; int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); int height = 0; status = state.surface->query( NATIVE_WINDOW_HEIGHT, &height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) { hwcDisplayId = allocateHwcDisplayId(state.type); } sp vds = new VirtualDisplaySurface( *mHwc, hwcDisplayId, state.surface, bqProducer, bqConsumer, state.displayName); dispSurface = vds; producer = vds; } } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface dispSurface = new FramebufferSurface(*mHwc, state.type, bqConsumer); producer = bqProducer; } const wp& display(curr.keyAt(i)); if (dispSurface != NULL) { sp hw = new DisplayDevice(this, state.type, hwcDisplayId, mHwc->getFormat(hwcDisplayId), state.isSecure, display, dispSurface, producer, mRenderEngine->getEGLConfig()); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); mDisplays.add(display, hw); if (state.isVirtualDisplay()) { if (hwcDisplayId >= 0) { mHwc->setVirtualDisplayProperties(hwcDisplayId, hw->getWidth(), hw->getHeight(), hw->getFormat()); } } else { mEventThread->onHotplugReceived(state.type, true); } } } } } } if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { // The transform hint might have changed for some layers // (either because a display has changed, or because a layer // as changed). // // Walk through all the layers in currentLayers, // and update their transform hint. // // If a layer is visible only on a single display, then that // display is used to calculate the hint, otherwise we use the // default display. // // NOTE: we do this here, rather than in rebuildLayerStacks() so that // the hint is set before we acquire a buffer from the surface texture. // // NOTE: layer transactions have taken place already, so we use their // drawing state. However, SurfaceFlinger's own transaction has not // happened yet, so we must use the current state layer list // (soon to become the drawing state list). // sp disp; uint32_t currentlayerStack = 0; for (size_t i=0; i& layer(currentLayers[i]); uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored // (more than one display) if so, pick the default display, // if not, pick the only display it's on. disp.clear(); for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); if (hw->getLayerStack() == currentlayerStack) { if (disp == NULL) { disp = hw; } else { disp = NULL; break; } } } } if (disp == NULL) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397. // could be null when this layer is using a layerStack // that is not visible on any display. Also can occur at // screen off/on times. disp = getDefaultDisplayDevice(); } layer->updateTransformHint(disp); } } /* * Perform our own transaction if needed */ const LayerVector& layers(mDrawingState.layersSortedByZ); if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; } // some layers might have been removed, so // we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.active.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); } } } commitTransaction(); updateCursorAsync(); } void SurfaceFlinger::updateCursorAsync() { HWComposer& hwc(getHwComposer()); for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id < 0) { continue; } const Vector< sp >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && igetCompositionType() != HWC_CURSOR_OVERLAY) { continue; } const sp& layer(currentLayers[i]); Rect cursorPos = layer->getPosition(hw); hwc.setCursorPositionAsync(id, cursorPos); break; } } } void SurfaceFlinger::commitTransaction() { if (!mLayersPendingRemoval.isEmpty()) { // Notify removed layers now that they can't be drawn from for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { mLayersPendingRemoval[i]->onRemoved(); } mLayersPendingRemoval.clear(); } // If this transaction is part of a window animation then the next frame // we composite should be considered an animation as well. mAnimCompositionPending = mAnimTransactionPending; mDrawingState = mCurrentState; mTransactionPending = false; mAnimTransactionPending = false; mTransactionCV.broadcast(); } void SurfaceFlinger::computeVisibleRegions( const LayerVector& currentLayers, uint32_t layerStack, Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); Region aboveOpaqueLayers; Region aboveCoveredLayers; Region dirty; outDirtyRegion.clear(); size_t i = currentLayers.size(); while (i--) { const sp& layer = currentLayers[i]; // start with the whole surface at its current location const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack if (s.layerStack != layerStack) continue; /* * opaqueRegion: area of a surface that is fully opaque. */ Region opaqueRegion; /* * visibleRegion: area of a surface that is visible on screen * and not fully transparent. This is essentially the layer's * footprint minus the opaque regions above it. * Areas covered by a translucent surface are considered visible. */ Region visibleRegion; /* * coveredRegion: area of a surface that is covered by all * visible regions above it (which includes the translucent areas). */ Region coveredRegion; /* * transparentRegion: area of a surface that is hinted to be completely * transparent. This is only used to tell when the layer has no visible * non-transparent regions and can be removed from the layer list. It * does not affect the visibleRegion of this layer or any layers * beneath it. The hint may not be correct if apps don't respect the * SurfaceView restrictions (which, sadly, some don't). */ Region transparentRegion; // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(s); Rect bounds(s.active.transform.transform(layer->computeBounds())); visibleRegion.set(bounds); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region if (translucent) { const Transform tr(s.active.transform); if (tr.preserveRects()) { // transform the transparent region transparentRegion = tr.transform(s.activeTransparentRegion); } else { // transformation too complex, can't do the // transparent region optimization. transparentRegion.clear(); } } // compute the opaque region const int32_t layerOrientation = s.active.transform.getOrientation(); if (s.alpha==255 && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint opaqueRegion = visibleRegion; } } } // Clip the covered region to the visible region coveredRegion = aboveCoveredLayers.intersect(visibleRegion); // Update aboveCoveredLayers for next (lower) layer aboveCoveredLayers.orSelf(visibleRegion); // subtract the opaque region covered by the layers above us visibleRegion.subtractSelf(aboveOpaqueLayers); // compute this layer's dirty region if (layer->contentDirty) { // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region dirty.orSelf(layer->visibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: * the exposed region consists of two components: * 1) what's VISIBLE now and was COVERED before * 2) what's EXPOSED now less what was EXPOSED before * * note that (1) is conservative, we start with the whole * visible region but only keep what used to be covered by * something -- which mean it may have been exposed. * * (2) handles areas that were not covered by anything but got * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; const Region oldVisibleRegion = layer->visibleRegion; const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region outDirtyRegion.orSelf(dirty); // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); // Store the visible region in screen space layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); layer->setVisibleNonTransparentRegion( visibleRegion.subtract(transparentRegion)); } outOpaqueRegion = aboveOpaqueLayers; } void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, const Region& dirty) { for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); if (hw->getLayerStack() == layerStack) { hw->dirtyRegion.orSelf(dirty); } } } bool SurfaceFlinger::handlePageFlip() { Region dirtyRegion; bool visibleRegions = false; const LayerVector& layers(mDrawingState.layersSortedByZ); bool frameQueued = false; // Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. // Example: Two producers share the same command stream and: // 1.) Layer 0 is latched // 2.) Layer 0 gets a new frame // 2.) Layer 1 gets a new frame // 3.) Layer 1 is latched. // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. Vector layersWithQueuedFrames; for (size_t i = 0, count = layers.size(); i& layer(layers[i]); if (layer->hasQueuedFrame()) { frameQueued = true; if (layer->shouldPresentNow(mPrimaryDispSync)) { layersWithQueuedFrames.push_back(layer.get()); } else { layer->useEmptyDamage(); } } else { layer->useEmptyDamage(); } } for (size_t i = 0, count = layersWithQueuedFrames.size() ; ilatchBuffer(visibleRegions)); layer->useSurfaceDamage(); const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } mVisibleRegionsDirty |= visibleRegions; // If we will need to wake up at some time in the future to deal with a // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. if (frameQueued && layersWithQueuedFrames.empty()) { signalLayerUpdate(); } // Only continue with the refresh if there is actually new work to do return !layersWithQueuedFrames.empty(); } void SurfaceFlinger::invalidateHwcGeometry() { mHwWorkListDirty = true; } void SurfaceFlinger::doDisplayComposition(const sp& hw, const Region& inDirtyRegion) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) bool isHwcDisplay = hw->getHwcDisplayId() >= 0; if (!isHwcDisplay && inDirtyRegion.isEmpty()) { return; } Region dirtyRegion(inDirtyRegion); // compute the invalid region hw->swapRegion.orSelf(dirtyRegion); uint32_t flags = hw->getFlags(); if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole // rectangle in that case dirtyRegion.set(hw->swapRegion.bounds()); } else { if (flags & DisplayDevice::PARTIAL_UPDATES) { // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). // This is needed because PARTIAL_UPDATES only takes one // rectangle instead of a region (see DisplayDevice::flip()) dirtyRegion.set(hw->swapRegion.bounds()); } else { // we need to redraw everything (the whole screen) dirtyRegion.set(hw->bounds()); hw->swapRegion = dirtyRegion; } } if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { if (!doComposeSurfaces(hw, dirtyRegion)) return; } else { RenderEngine& engine(getRenderEngine()); mat4 colorMatrix = mColorMatrix; if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion); engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region hw->swapRegion.orSelf(dirtyRegion); // swap buffers (presentation) hw->swapBuffers(getHwComposer()); } bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty) { RenderEngine& engine(getRenderEngine()); const int32_t id = hw->getHwcDisplayId(); HWComposer& hwc(getHwComposer()); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); bool hasGlesComposition = hwc.hasGlesComposition(id); if (hasGlesComposition) { if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", hw->getDisplayName().string()); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); } return false; } // Never touch the framebuffer if we don't have any framebuffer layers const bool hasHwcComposition = hwc.hasHwcComposition(id); if (hasHwcComposition) { // when using overlays, we assume a fully transparent framebuffer // NOTE: we could reduce how much we need to clear, for instance // remove where there are opaque FB layers. however, on some // GPUs doing a "clean slate" clear might be more efficient. // We'll revisit later if needed. engine.clearWithColor(0, 0, 0, 0); } else { // we start with the whole screen area const Region bounds(hw->getBounds()); // we remove the scissor part // we're left with the letterbox region // (common case is that letterbox ends-up being empty) const Region letterbox(bounds.subtract(hw->getScissor())); // compute the area to clear Region region(hw->undefinedRegion.merge(letterbox)); // but limit it to the dirty region region.andSelf(dirty); // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView drawWormhole(hw, region); } } if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { // just to be on the safe side, we don't set the // scissor on the main display. It should never be needed // anyways (though in theory it could since the API allows it). const Rect& bounds(hw->getBounds()); const Rect& scissor(hw->getScissor()); if (scissor != bounds) { // scissor doesn't match the screen's dimensions, so we // need to clear everything outside of it and enable // the GL scissor so we don't draw anything where we shouldn't // enable scissor for this frame const uint32_t height = hw->getHeight(); engine.setScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight()); } } } /* * and then, render the layers targeted at the framebuffer */ const Vector< sp >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); const Transform& tr = hw->getTransform(); if (cur != end) { // we're using h/w composer for (size_t i=0 ; i& layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { switch (cur->getCompositionType()) { case HWC_CURSOR_OVERLAY: case HWC_OVERLAY: { const Layer::State& state(layer->getDrawingState()); if ((cur->getHints() & HWC_HINT_CLEAR_FB) && i && layer->isOpaque(state) && (state.alpha == 0xFF) && hasGlesComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared layer->clearWithOpenGL(hw, clip); } break; } case HWC_FRAMEBUFFER: { layer->draw(hw, clip); break; } case HWC_FRAMEBUFFER_TARGET: { // this should not happen as the iterator shouldn't // let us get there. ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i); break; } } } layer->setAcquireFence(hw, *cur); } } else { // we're not using h/w composer for (size_t i=0 ; i& layer(layers[i]); const Region clip(dirty.intersect( tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { layer->draw(hw, clip); } } } // disable scissor at the end of the frame engine.disableScissor(); return true; } void SurfaceFlinger::drawWormhole(const sp& hw, const Region& region) const { const int32_t height = hw->getHeight(); RenderEngine& engine(getRenderEngine()); engine.fillRegionWithColor(region, height, 0, 0, 0, 0); } status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc) { // add this layer to the current state list { Mutex::Autolock _l(mStateLock); if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) { return NO_MEMORY; } mCurrentState.layersSortedByZ.add(lbc); mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); } // attach this layer to the client client->attachLayer(handle, lbc); return NO_ERROR; } status_t SurfaceFlinger::removeLayer(const sp& layer) { Mutex::Autolock _l(mStateLock); ssize_t index = mCurrentState.layersSortedByZ.remove(layer); if (index >= 0) { mLayersPendingRemoval.push(layer); mLayersRemoved = true; setTransactionFlags(eTransactionNeeded); return NO_ERROR; } return status_t(index); } uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) { return android_atomic_release_load(&mTransactionFlags); } uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { return android_atomic_and(~flags, &mTransactionFlags) & flags; } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { uint32_t old = android_atomic_or(flags, &mTransactionFlags); if ((old & flags)==0) { // wake the server up signalTransaction(); } return old; } void SurfaceFlinger::setTransactionState( const Vector& state, const Vector& displays, uint32_t flags) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); uint32_t transactionFlags = 0; if (flags & eAnimation) { // For window updates that are part of an animation we must wait for // previous animation "frames" to be handled. while (mAnimTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // caller after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " "waiting for previous animation frame"); mAnimTransactionPending = false; break; } } } size_t count = displays.size(); for (size_t i=0 ; i binder = IInterface::asBinder(s.client); if (binder != NULL) { if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) { sp client( static_cast(s.client.get()) ); transactionFlags |= setClientStateLocked(client, s.state); } } } } // If a synchronous transaction is explicitly requested without any changes, // force a transaction anyway. This can be used as a flush mechanism for // previous async transactions. if (transactionFlags == 0 && (flags & eSynchronous)) { transactionFlags = eTransactionNeeded; } if (transactionFlags) { // this triggers the transaction setTransactionFlags(transactionFlags); // if this is a synchronous transaction, wait for it to take effect // before returning. if (flags & eSynchronous) { mTransactionPending = true; } if (flags & eAnimation) { mAnimTransactionPending = true; } while (mTransactionPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // called after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); mTransactionPending = false; break; } } } } uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token); if (dpyIdx < 0) return 0; uint32_t flags = 0; DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx)); if (disp.isValid()) { const uint32_t what = s.what; if (what & DisplayState::eSurfaceChanged) { if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) { disp.surface = s.surface; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eLayerStackChanged) { if (disp.layerStack != s.layerStack) { disp.layerStack = s.layerStack; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eDisplayProjectionChanged) { if (disp.orientation != s.orientation) { disp.orientation = s.orientation; flags |= eDisplayTransactionNeeded; } if (disp.frame != s.frame) { disp.frame = s.frame; flags |= eDisplayTransactionNeeded; } if (disp.viewport != s.viewport) { disp.viewport = s.viewport; flags |= eDisplayTransactionNeeded; } } if (what & DisplayState::eDisplaySizeChanged) { if (disp.width != s.width) { disp.width = s.width; flags |= eDisplayTransactionNeeded; } if (disp.height != s.height) { disp.height = s.height; flags |= eDisplayTransactionNeeded; } } } return flags; } uint32_t SurfaceFlinger::setClientStateLocked( const sp& client, const layer_state_t& s) { uint32_t flags = 0; sp layer(client->getLayerUser(s.surface)); if (layer != 0) { const uint32_t what = s.what; bool positionAppliesWithResize = what & layer_state_t::ePositionAppliesWithResize; if (what & layer_state_t::ePositionChanged) { if (layer->setPosition(s.x, s.y, !positionAppliesWithResize)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eLayerChanged) { // NOTE: index needs to be calculated before we update the state ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } } if (what & layer_state_t::eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eAlphaChanged) { if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) flags |= eTraversalNeeded; } if (what & layer_state_t::eMatrixChanged) { if (layer->setMatrix(s.matrix)) flags |= eTraversalNeeded; } if (what & layer_state_t::eTransparentRegionChanged) { if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFlagsChanged) { if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFinalCropChanged) { if (layer->setFinalCrop(s.finalCrop)) flags |= eTraversalNeeded; } if (what & layer_state_t::eLayerStackChanged) { // NOTE: index needs to be calculated before we update the state ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayerStack(s.layerStack) && idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; } } if (what & layer_state_t::eDeferTransaction) { layer->deferTransactionUntil(s.handle, s.frameNumber); // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } if (what & layer_state_t::eOverrideScalingModeChanged) { layer->setOverrideScalingMode(s.overrideScalingMode); // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } } return flags; } status_t SurfaceFlinger::createLayer( const String8& name, const sp& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp* handle, sp* gbp) { //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); if (int32_t(w|h) < 0) { ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", int(w), int(h)); return BAD_VALUE; } status_t result = NO_ERROR; sp layer; switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client, name, w, h, flags, format, handle, gbp, &layer); break; case ISurfaceComposerClient::eFXSurfaceDim: result = createDimLayer(client, name, w, h, flags, handle, gbp, &layer); break; default: result = BAD_VALUE; break; } if (result != NO_ERROR) { return result; } result = addClientLayer(client, *handle, *gbp, layer); if (result != NO_ERROR) { return result; } setTransactionFlags(eTransactionNeeded); return result; } status_t SurfaceFlinger::createNormalLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp* handle, sp* gbp, sp* outLayer) { // initialize the surfaces switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: format = PIXEL_FORMAT_RGBX_8888; break; } *outLayer = new Layer(this, client, name, w, h, flags); status_t err = (*outLayer)->setBuffers(w, h, format, flags); if (err == NO_ERROR) { *handle = (*outLayer)->getHandle(); *gbp = (*outLayer)->getProducer(); } ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); return err; } status_t SurfaceFlinger::createDimLayer(const sp& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, sp* handle, sp* gbp, sp* outLayer) { *outLayer = new LayerDim(this, client, name, w, h, flags); *handle = (*outLayer)->getHandle(); *gbp = (*outLayer)->getProducer(); return NO_ERROR; } status_t SurfaceFlinger::onLayerRemoved(const sp& client, const sp& handle) { // called by the window manager when it wants to remove a Layer status_t err = NO_ERROR; sp l(client->getLayerUser(handle)); if (l != NULL) { err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); } return err; } status_t SurfaceFlinger::onLayerDestroyed(const wp& layer) { // called by ~LayerCleaner() when all references to the IBinder (handle) // are gone status_t err = NO_ERROR; sp l(layer.promote()); if (l != NULL) { err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); } return err; } // --------------------------------------------------------------------------- void SurfaceFlinger::onInitializeDisplays() { // reset screen orientation and use primary layer stack Vector state; Vector displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; d.layerStack = 0; d.orientation = DisplayState::eOrientationDefault; d.frame.makeInvalid(); d.viewport.makeInvalid(); d.width = 0; d.height = 0; displays.add(d); setTransactionState(state, displays, 0); setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); const nsecs_t period = getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); mAnimFrameTracker.setDisplayRefreshPeriod(period); } void SurfaceFlinger::initializeDisplays() { class MessageScreenInitialized : public MessageBase { SurfaceFlinger* flinger; public: MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { } virtual bool handler() { flinger->onInitializeDisplays(); return true; } }; sp msg = new MessageScreenInitialized(this); postMessageAsync(msg); // we may be called from main thread, use async message } void SurfaceFlinger::setPowerModeInternal(const sp& hw, int mode) { ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), this); int32_t type = hw->getDisplayType(); int currentMode = hw->getPowerMode(); if (mode == currentMode) { ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); return; } hw->setPowerMode(mode); if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { ALOGW("Trying to set power mode for virtual display"); return; } if (currentMode == HWC_POWER_MODE_OFF) { getHwComposer().setPowerMode(type, mode); if (type == DisplayDevice::DISPLAY_PRIMARY) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); } mVisibleRegionsDirty = true; mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { disableHardwareVsync(true); // also cancels any in-progress resync // FIXME: eventthread only knows about the main display right now mEventThread->onScreenReleased(); } getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display } else { getHwComposer().setPowerMode(type, mode); } } void SurfaceFlinger::setPowerMode(const sp& display, int mode) { class MessageSetPowerMode: public MessageBase { SurfaceFlinger& mFlinger; sp mDisplay; int mMode; public: MessageSetPowerMode(SurfaceFlinger& flinger, const sp& disp, int mode) : mFlinger(flinger), mDisplay(disp) { mMode = mode; } virtual bool handler() { sp hw(mFlinger.getDisplayDevice(mDisplay)); if (hw == NULL) { ALOGE("Attempt to set power mode = %d for null display %p", mMode, mDisplay.get()); } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { ALOGW("Attempt to set power mode = %d for virtual display", mMode); } else { mFlinger.setPowerModeInternal(hw, mMode); } return true; } }; sp msg = new MessageSetPowerMode(*this, display, mode); postMessageSync(msg); } // --------------------------------------------------------------------------- status_t SurfaceFlinger::dump(int fd, const Vector& args) { String8 result; IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); } else { // Try to get the main lock, but give up after one second // (this would indicate SF is stuck, but we want to be able to // print something in dumpsys). status_t err = mStateLock.timedLock(s2ns(1)); bool locked = (err == NO_ERROR); if (!locked) { result.appendFormat( "SurfaceFlinger appears to be unresponsive (%s [%d]), " "dumping anyways (no locks held)\n", strerror(-err), err); } bool dumpAll = true; size_t index = 0; size_t numArgs = args.size(); if (numArgs) { if ((index < numArgs) && (args[index] == String16("--list"))) { index++; listLayersLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency"))) { index++; dumpStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency-clear"))) { index++; clearStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--dispsync"))) { index++; mPrimaryDispSync.dump(result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--static-screen"))) { index++; dumpStaticScreenStats(result); dumpAll = false; } #ifdef ENABLE_FENCE_TRACKING if ((index < numArgs) && (args[index] == String16("--fences"))) { index++; mFenceTracker.dump(&result); dumpAll = false; } #endif } if (dumpAll) { dumpAllLocked(args, index, result); } if (locked) { mStateLock.unlock(); } } write(fd, result.string(), result.size()); return NO_ERROR; } void SurfaceFlinger::listLayersLocked(const Vector& /* args */, size_t& /* index */, String8& result) const { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); result.appendFormat("%s\n", layer->getName().string()); } } void SurfaceFlinger::dumpStatsLocked(const Vector& args, size_t& index, String8& result) const { String8 name; if (index < args.size()) { name = String8(args[index]); index++; } const nsecs_t period = getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); result.appendFormat("%" PRId64 "\n", period); if (name.isEmpty()) { mAnimFrameTracker.dumpStats(result); } else { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); if (name == layer->getName()) { layer->dumpFrameStats(result); } } } } void SurfaceFlinger::clearStatsLocked(const Vector& args, size_t& index, String8& /* result */) { String8 name; if (index < args.size()) { name = String8(args[index]); index++; } const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i& layer(currentLayers[i]); if (name.isEmpty() || (name == layer->getName())) { layer->clearFrameStats(); } } mAnimFrameTracker.clearStats(); } // This should only be called from the main thread. Otherwise it would need // the lock and should use mCurrentState rather than mDrawingState. void SurfaceFlinger::logFrameStats() { const LayerVector& drawingLayers = mDrawingState.layersSortedByZ; const size_t count = drawingLayers.size(); for (size_t i=0 ; i& layer(drawingLayers[i]); layer->logFrameStats(); } mAnimFrameTracker.logAndResetStats(String8("")); } /*static*/ void SurfaceFlinger::appendSfConfigString(String8& result) { static const char* config = " [sf" #ifdef HAS_CONTEXT_PRIORITY " HAS_CONTEXT_PRIORITY" #endif #ifdef NEVER_DEFAULT_TO_ASYNC_MODE " NEVER_DEFAULT_TO_ASYNC_MODE" #endif #ifdef TARGET_DISABLE_TRIPLE_BUFFERING " TARGET_DISABLE_TRIPLE_BUFFERING" #endif "]"; result.append(config); } void SurfaceFlinger::dumpStaticScreenStats(String8& result) const { result.appendFormat("Static screen stats:\n"); for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { float bucketTimeSec = mFrameBuckets[b] / 1e9; float percent = 100.0f * static_cast(mFrameBuckets[b]) / mTotalTime; result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent); } float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; float percent = 100.0f * static_cast(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", NUM_BUCKETS - 1, bucketTimeSec, percent); } void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, String8& result) const { bool colorize = false; if (index < args.size() && (args[index] == String16("--color"))) { colorize = true; index++; } Colorizer colorizer(colorize); // figure out if we're stuck somewhere const nsecs_t now = systemTime(); const nsecs_t inSwapBuffers(mDebugInSwapBuffers); const nsecs_t inTransaction(mDebugInTransaction); nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; /* * Dump library configuration. */ colorizer.bold(result); result.append("Build configuration:"); colorizer.reset(result); appendSfConfigString(result); appendUiConfigString(result); appendGuiConfigString(result); result.append("\n"); colorizer.bold(result); result.append("Sync configuration: "); colorizer.reset(result); result.append(SyncFeatures::getInstance().toString()); result.append("\n"); colorizer.bold(result); result.append("DispSync configuration: "); colorizer.reset(result); result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, " "present offset %d ns (refresh %" PRId64 " ns)", vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); result.append("\n"); // Dump static screen stats result.append("\n"); dumpStaticScreenStats(result); result.append("\n"); /* * Dump the visible layer list */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); colorizer.bold(result); result.appendFormat("Visible layers (count = %zu)\n", count); colorizer.reset(result); for (size_t i=0 ; i& layer(currentLayers[i]); layer->dump(result, colorizer); } /* * Dump Display state */ colorizer.bold(result); result.appendFormat("Displays (%zu entries)\n", mDisplays.size()); colorizer.reset(result); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); hw->dump(result); } /* * Dump SurfaceFlinger global state */ colorizer.bold(result); result.append("SurfaceFlinger global state:\n"); colorizer.reset(result); HWComposer& hwc(getHwComposer()); sp hw(getDefaultDisplayDevice()); colorizer.bold(result); result.appendFormat("EGL implementation : %s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); colorizer.reset(result); result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); mRenderEngine->dump(result); hw->undefinedRegion.dump(result, "undefinedRegion"); result.appendFormat(" orientation=%d, isDisplayOn=%d\n", hw->getOrientation(), hw->isDisplayOn()); result.appendFormat( " last eglSwapBuffers() time: %f us\n" " last transaction time : %f us\n" " transaction-flags : %08x\n" " refresh-rate : %f fps\n" " x-dpi : %f\n" " y-dpi : %f\n" " gpu_to_cpu_unsupported : %d\n" , mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0, mTransactionFlags, 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY), hwc.getDpiX(HWC_DISPLAY_PRIMARY), hwc.getDpiY(HWC_DISPLAY_PRIMARY), !mGpuToCpuSupported); result.appendFormat(" eglSwapBuffers time: %f us\n", inSwapBuffersDuration/1000.0); result.appendFormat(" transaction time: %f us\n", inTransactionDuration/1000.0); /* * VSYNC state */ mEventThread->dump(result); /* * Dump HWComposer state */ colorizer.bold(result); result.append("h/w composer state:\n"); colorizer.reset(result); result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) ? "disabled" : "enabled"); hwc.dump(result); /* * Dump gralloc state */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); } const Vector< sp >& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { // Note: mStateLock is held here wp dpy; for (size_t i=0 ; igetHwcDisplayId() == id) { dpy = mDisplays.keyAt(i); break; } } if (dpy == NULL) { ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); // Just use the primary display so we have something to return dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); } return getDisplayDevice(dpy)->getVisibleLayersSortedByZ(); } bool SurfaceFlinger::startDdmConnection() { void* libddmconnection_dso = dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW); if (!libddmconnection_dso) { return false; } void (*DdmConnection_start)(const char* name); DdmConnection_start = (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start"); if (!DdmConnection_start) { dlclose(libddmconnection_dso); return false; } (*DdmConnection_start)(getServiceName()); return true; } status_t SurfaceFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case CREATE_CONNECTION: case CREATE_DISPLAY: case SET_TRANSACTION_STATE: case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: case GET_ANIMATION_FRAME_STATS: case SET_POWER_MODE: case GET_HDR_CAPABILITIES: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } case CAPTURE_SCREEN: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS) && !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { ALOGE("Permission Denial: " "can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } } status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } int n; switch (code) { case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE return NO_ERROR; case 1002: // SHOW_UPDATES n = data.readInt32(); mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1004:{ // repaint everything repaintEverything(); return NO_ERROR; } case 1005:{ // force transaction setTransactionFlags( eTransactionNeeded| eDisplayTransactionNeeded| eTraversalNeeded); return NO_ERROR; } case 1006:{ // send empty update signalRefresh(); return NO_ERROR; } case 1008: // toggle use of hw composer n = data.readInt32(); mDebugDisableHWC = n ? 1 : 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1009: // toggle use of transform hint n = data.readInt32(); mDebugDisableTransformHint = n ? 1 : 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; case 1010: // interrogate. reply->writeInt32(0); reply->writeInt32(0); reply->writeInt32(mDebugRegion); reply->writeInt32(0); reply->writeInt32(mDebugDisableHWC); return NO_ERROR; case 1013: { Mutex::Autolock _l(mStateLock); sp hw(getDefaultDisplayDevice()); reply->writeInt32(hw->getPageFlipCount()); return NO_ERROR; } case 1014: { // daltonize n = data.readInt32(); switch (n % 10) { case 1: mDaltonizer.setType(Daltonizer::protanomaly); break; case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break; case 3: mDaltonizer.setType(Daltonizer::tritanomaly); break; } if (n >= 10) { mDaltonizer.setMode(Daltonizer::correction); } else { mDaltonizer.setMode(Daltonizer::simulation); } mDaltonize = n > 0; invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; } case 1015: { // apply a color matrix n = data.readInt32(); mHasColorMatrix = n ? 1 : 0; if (n) { // color matrix is sent as mat3 matrix followed by vec3 // offset, then packed into a mat4 where the last row is // the offset and extra values are 0 for (size_t i = 0 ; i < 4; i++) { for (size_t j = 0; j < 4; j++) { mColorMatrix[i][j] = data.readFloat(); } } } else { mColorMatrix = mat4(); } invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; } // This is an experimental interface // Needs to be shifted to proper binder interface when we productize case 1016: { n = data.readInt32(); mPrimaryDispSync.setRefreshSkipCount(n); return NO_ERROR; } case 1017: { n = data.readInt32(); mForceFullDamage = static_cast(n); return NO_ERROR; } case 1018: { // Modify Choreographer's phase offset n = data.readInt32(); mEventThread->setPhaseOffset(static_cast(n)); return NO_ERROR; } case 1019: { // Modify SurfaceFlinger's phase offset n = data.readInt32(); mSFEventThread->setPhaseOffset(static_cast(n)); return NO_ERROR; } } } return err; } void SurfaceFlinger::repaintEverything() { android_atomic_or(1, &mRepaintEverything); signalTransaction(); } // --------------------------------------------------------------------------- // Capture screen into an IGraphiBufferProducer // --------------------------------------------------------------------------- /* The code below is here to handle b/8734824 * * We create a IGraphicBufferProducer wrapper that forwards all calls * from the surfaceflinger thread to the calling binder thread, where they * are executed. This allows the calling thread in the calling process to be * reused and not depend on having "enough" binder threads to handle the * requests. */ class GraphicProducerWrapper : public BBinder, public MessageHandler { /* Parts of GraphicProducerWrapper are run on two different threads, * communicating by sending messages via Looper but also by shared member * data. Coherence maintenance is subtle and in places implicit (ugh). * * Don't rely on Looper's sendMessage/handleMessage providing * release/acquire semantics for any data not actually in the Message. * Data going from surfaceflinger to binder threads needs to be * synchronized explicitly. * * Barrier open/wait do provide release/acquire semantics. This provides * implicit synchronization for data coming back from binder to * surfaceflinger threads. */ sp impl; sp looper; status_t result; bool exitPending; bool exitRequested; Barrier barrier; uint32_t code; Parcel const* data; Parcel* reply; enum { MSG_API_CALL, MSG_EXIT }; /* * Called on surfaceflinger thread. This is called by our "fake" * BpGraphicBufferProducer. We package the data and reply Parcel and * forward them to the binder thread. */ virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t /* flags */) { this->code = code; this->data = &data; this->reply = reply; if (exitPending) { // if we've exited, we run the message synchronously right here. // note (JH): as far as I can tell from looking at the code, this // never actually happens. if it does, i'm not sure if it happens // on the surfaceflinger or binder thread. handleMessage(Message(MSG_API_CALL)); } else { barrier.close(); // Prevent stores to this->{code, data, reply} from being // reordered later than the construction of Message. atomic_thread_fence(memory_order_release); looper->sendMessage(this, Message(MSG_API_CALL)); barrier.wait(); } return result; } /* * here we run on the binder thread. All we've got to do is * call the real BpGraphicBufferProducer. */ virtual void handleMessage(const Message& message) { int what = message.what; // Prevent reads below from happening before the read from Message atomic_thread_fence(memory_order_acquire); if (what == MSG_API_CALL) { result = IInterface::asBinder(impl)->transact(code, data[0], reply); barrier.open(); } else if (what == MSG_EXIT) { exitRequested = true; } } public: GraphicProducerWrapper(const sp& impl) : impl(impl), looper(new Looper(true)), result(NO_ERROR), exitPending(false), exitRequested(false), code(0), data(NULL), reply(NULL) {} // Binder thread status_t waitForResponse() { do { looper->pollOnce(-1); } while (!exitRequested); return result; } // Client thread void exit(status_t result) { this->result = result; exitPending = true; // Ensure this->result is visible to the binder thread before it // handles the message. atomic_thread_fence(memory_order_release); looper->sendMessage(this, Message(MSG_EXIT)); } }; status_t SurfaceFlinger::captureScreen(const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { if (CC_UNLIKELY(display == 0)) return BAD_VALUE; if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; // if we have secure windows on this display, never allow the screen capture // unless the producer interface is local (i.e.: we can take a screenshot for // ourselves). bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); // Convert to surfaceflinger's internal rotation type. Transform::orientation_flags rotationFlags; switch (rotation) { case ISurfaceComposer::eRotateNone: rotationFlags = Transform::ROT_0; break; case ISurfaceComposer::eRotate90: rotationFlags = Transform::ROT_90; break; case ISurfaceComposer::eRotate180: rotationFlags = Transform::ROT_180; break; case ISurfaceComposer::eRotate270: rotationFlags = Transform::ROT_270; break; default: rotationFlags = Transform::ROT_0; ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); break; } class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; sp display; sp producer; Rect sourceCrop; uint32_t reqWidth, reqHeight; uint32_t minLayerZ,maxLayerZ; bool useIdentityTransform; Transform::orientation_flags rotation; status_t result; bool isLocalScreenshot; public: MessageCaptureScreen(SurfaceFlinger* flinger, const sp& display, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot) : flinger(flinger), display(display), producer(producer), sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), useIdentityTransform(useIdentityTransform), rotation(rotation), result(PERMISSION_DENIED), isLocalScreenshot(isLocalScreenshot) { } status_t getResult() const { return result; } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp hw(flinger->getDisplayDevice(display)); result = flinger->captureScreenImplLocked(hw, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, rotation, isLocalScreenshot); static_cast(IInterface::asBinder(producer).get())->exit(result); return true; } }; // this creates a "fake" BBinder which will serve as a "fake" remote // binder to receive the marshaled calls and forward them to the // real remote (a BpGraphicBufferProducer) sp wrapper = new GraphicProducerWrapper(producer); // the asInterface() call below creates our "fake" BpGraphicBufferProducer // which does the marshaling work forwards to our "fake remote" above. sp msg = new MessageCaptureScreen(this, display, IGraphicBufferProducer::asInterface( wrapper ), sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, rotationFlags, isLocalScreenshot); status_t res = postMessageAsync(msg); if (res == NO_ERROR) { res = wrapper->waitForResponse(); } return res; } void SurfaceFlinger::renderScreenImplLocked( const sp& hw, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) { ATRACE_CALL(); RenderEngine& engine(getRenderEngine()); // get screen geometry const int32_t hw_w = hw->getWidth(); const int32_t hw_h = hw->getHeight(); const bool filtering = static_cast(reqWidth) != hw_w || static_cast(reqHeight) != hw_h; // if a default or invalid sourceCrop is passed in, set reasonable values if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) { sourceCrop.setLeftTop(Point(0, 0)); sourceCrop.setRightBottom(Point(hw_w, hw_h)); } // ensure that sourceCrop is inside screen if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } if (sourceCrop.right > hw_w) { ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } if (sourceCrop.bottom > hw_h) { ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); } // make sure to clear all GL error flags engine.checkErrors(); // set-up our viewport engine.setViewportAndProjection( reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); engine.disableTexturing(); // redraw the screen entirely... engine.clearWithColor(0, 0, 0, 1); const LayerVector& layers( mDrawingState.layersSortedByZ ); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack()) { if (state.z >= minLayerZ && state.z <= maxLayerZ) { if (layer->isVisible()) { if (filtering) layer->setFiltering(true); layer->draw(hw, useIdentityTransform); if (filtering) layer->setFiltering(false); } } } } // compositionComplete is needed for older driver hw->compositionComplete(); hw->setViewportAndProjection(); } status_t SurfaceFlinger::captureScreenImplLocked( const sp& hw, const sp& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot) { ATRACE_CALL(); // get screen geometry uint32_t hw_w = hw->getWidth(); uint32_t hw_h = hw->getHeight(); if (rotation & Transform::ROT_90) { std::swap(hw_w, hw_h); } if ((reqWidth > hw_w) || (reqHeight > hw_h)) { ALOGE("size mismatch (%d, %d) > (%d, %d)", reqWidth, reqHeight, hw_w, hw_h); return BAD_VALUE; } reqWidth = (!reqWidth) ? hw_w : reqWidth; reqHeight = (!reqHeight) ? hw_h : reqHeight; bool secureLayerIsVisible = false; const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i = 0 ; i < count ; ++i) { const sp& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ && state.z <= maxLayerZ && layer->isVisible() && layer->isSecure()) { secureLayerIsVisible = true; } } if (!isLocalScreenshot && secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED"); return PERMISSION_DENIED; } // create a surface (because we're a producer, and we need to // dequeue/queue a buffer) sp sur = new Surface(producer, false); ANativeWindow* window = sur.get(); status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); if (result == NO_ERROR) { uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; int err = 0; err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); err |= native_window_set_usage(window, usage); if (err == NO_ERROR) { ANativeWindowBuffer* buffer; /* TODO: Once we have the sync framework everywhere this can use * server-side waits on the fence that dequeueBuffer returns. */ result = native_window_dequeue_buffer_and_wait(window, &buffer); if (result == NO_ERROR) { int syncFd = -1; // create an EGLImage from the buffer so we can later // turn it into a texture EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); if (image != EGL_NO_IMAGE_KHR) { // this binds the given EGLImage as a framebuffer for the // duration of this scope. RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); if (imageBond.getStatus() == NO_ERROR) { // this will in fact render into our dequeued buffer // via an FBO, which means we didn't have to create // an EGLSurface and therefore we're not // dependent on the context's EGLConfig. renderScreenImplLocked( hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, useIdentityTransform, rotation); // Attempt to create a sync khr object that can produce a sync point. If that // isn't available, create a non-dupable sync object in the fallback path and // wait on it directly. EGLSyncKHR sync; if (!DEBUG_SCREENSHOTS) { sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); // native fence fd will not be populated until flush() is done. getRenderEngine().flush(); } else { sync = EGL_NO_SYNC_KHR; } if (sync != EGL_NO_SYNC_KHR) { // get the sync fd syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ALOGW("captureScreen: failed to dup sync khr object"); syncFd = -1; } eglDestroySyncKHR(mEGLDisplay, sync); } else { // fallback path sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); if (sync != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); EGLint eglErr = eglGetError(); if (result == EGL_TIMEOUT_EXPIRED_KHR) { ALOGW("captureScreen: fence wait timed out"); } else { ALOGW_IF(eglErr != EGL_SUCCESS, "captureScreen: error waiting on EGL fence: %#x", eglErr); } eglDestroySyncKHR(mEGLDisplay, sync); } else { ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); } } if (DEBUG_SCREENSHOTS) { uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, hw, minLayerZ, maxLayerZ); delete [] pixels; } } else { ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); result = INVALID_OPERATION; window->cancelBuffer(window, buffer, syncFd); buffer = NULL; } // destroy our image eglDestroyImageKHR(mEGLDisplay, image); } else { result = BAD_VALUE; } if (buffer) { // queueBuffer takes ownership of syncFd result = window->queueBuffer(window, buffer, syncFd); } } } else { result = BAD_VALUE; } native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } return result; } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, const sp& hw, uint32_t minLayerZ, uint32_t maxLayerZ) { if (DEBUG_SCREENSHOTS) { for (size_t y=0 ; ygetLayerStack()); const LayerVector& layers( mDrawingState.layersSortedByZ ); const size_t count = layers.size(); for (size_t i=0 ; i& layer(layers[i]); const Layer::State& state(layer->getDrawingState()); const bool visible = (state.layerStack == hw->getLayerStack()) && (state.z >= minLayerZ && state.z <= maxLayerZ) && (layer->isVisible()); ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x", visible ? '+' : '-', i, layer->getName().string(), state.layerStack, state.z, layer->isVisible(), state.flags, state.alpha); } } } // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector() { } SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) : SortedVector >(rhs) { } int SurfaceFlinger::LayerVector::do_compare(const void* lhs, const void* rhs) const { // sort layers per layer-stack, then by z-order and finally by sequence const sp& l(*reinterpret_cast*>(lhs)); const sp& r(*reinterpret_cast*>(rhs)); uint32_t ls = l->getCurrentState().layerStack; uint32_t rs = r->getCurrentState().layerStack; if (ls != rs) return ls - rs; uint32_t lz = l->getCurrentState().z; uint32_t rz = r->getCurrentState().z; if (lz != rz) return lz - rz; return l->sequence - r->sequence; } // --------------------------------------------------------------------------- SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() : type(DisplayDevice::DISPLAY_ID_INVALID), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0), isSecure(false) { } SurfaceFlinger::DisplayDeviceState::DisplayDeviceState( DisplayDevice::DisplayType type, bool isSecure) : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0), isSecure(isSecure) { viewport.makeInvalid(); frame.makeInvalid(); } // --------------------------------------------------------------------------- }; // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" #endif #if defined(__gl2_h_) #error "don't include gl2/gl2.h in this file" #endif services/surfaceflinger/Transform.cpp0100644 0000000 0000000 00000023252 13077405420 017114 0ustar000000000 0000000 /* * Copyright (C) 2007 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 #include #include #include #include "clz.h" #include "Transform.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- Transform::Transform() { reset(); } Transform::Transform(const Transform& other) : mMatrix(other.mMatrix), mType(other.mType) { } Transform::Transform(uint32_t orientation) { set(orientation, 0, 0); } Transform::~Transform() { } static const float EPSILON = 0.0f; bool Transform::isZero(float f) { return fabs(f) <= EPSILON; } bool Transform::absIsOne(float f) { return isZero(fabs(f) - 1.0f); } Transform Transform::operator * (const Transform& rhs) const { if (CC_LIKELY(mType == IDENTITY)) return rhs; Transform r(*this); if (rhs.mType == IDENTITY) return r; // TODO: we could use mType to optimize the matrix multiply const mat33& A(mMatrix); const mat33& B(rhs.mMatrix); mat33& D(r.mMatrix); for (int i=0 ; i<3 ; i++) { const float v0 = A[0][i]; const float v1 = A[1][i]; const float v2 = A[2][i]; D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2]; D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2]; D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2]; } r.mType |= rhs.mType; // TODO: we could recompute this value from r and rhs r.mType &= 0xFF; r.mType |= UNKNOWN_TYPE; return r; } const vec3& Transform::operator [] (size_t i) const { return mMatrix[i]; } float Transform::tx() const { return mMatrix[2][0]; } float Transform::ty() const { return mMatrix[2][1]; } void Transform::reset() { mType = IDENTITY; for(int i=0 ; i<3 ; i++) { vec3& v(mMatrix[i]); for (int j=0 ; j<3 ; j++) v[j] = ((i==j) ? 1.0f : 0.0f); } } void Transform::set(float tx, float ty) { mMatrix[2][0] = tx; mMatrix[2][1] = ty; mMatrix[2][2] = 1.0f; if (isZero(tx) && isZero(ty)) { mType &= ~TRANSLATE; } else { mType |= TRANSLATE; } } void Transform::set(float a, float b, float c, float d) { mat33& M(mMatrix); M[0][0] = a; M[1][0] = b; M[0][1] = c; M[1][1] = d; M[0][2] = 0; M[1][2] = 0; mType = UNKNOWN_TYPE; } status_t Transform::set(uint32_t flags, float w, float h) { if (flags & ROT_INVALID) { // that's not allowed! reset(); return BAD_VALUE; } Transform H, V, R; if (flags & ROT_90) { // w & h are inverted when rotating by 90 degrees swap(w, h); } if (flags & FLIP_H) { H.mType = (FLIP_H << 8) | SCALE; H.mType |= isZero(w) ? IDENTITY : TRANSLATE; mat33& M(H.mMatrix); M[0][0] = -1; M[2][0] = w; } if (flags & FLIP_V) { V.mType = (FLIP_V << 8) | SCALE; V.mType |= isZero(h) ? IDENTITY : TRANSLATE; mat33& M(V.mMatrix); M[1][1] = -1; M[2][1] = h; } if (flags & ROT_90) { const float original_w = h; R.mType = (ROT_90 << 8) | ROTATE; R.mType |= isZero(original_w) ? IDENTITY : TRANSLATE; mat33& M(R.mMatrix); M[0][0] = 0; M[1][0] =-1; M[2][0] = original_w; M[0][1] = 1; M[1][1] = 0; } *this = (R*(H*V)); return NO_ERROR; } vec2 Transform::transform(const vec2& v) const { vec2 r; const mat33& M(mMatrix); r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]; r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]; return r; } vec3 Transform::transform(const vec3& v) const { vec3 r; const mat33& M(mMatrix); r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2]; r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2]; r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2]; return r; } vec2 Transform::transform(int x, int y) const { return transform(vec2(x,y)); } Rect Transform::makeBounds(int w, int h) const { return transform( Rect(w, h) ); } Rect Transform::transform(const Rect& bounds) const { Rect r; vec2 lt( bounds.left, bounds.top ); vec2 rt( bounds.right, bounds.top ); vec2 lb( bounds.left, bounds.bottom ); vec2 rb( bounds.right, bounds.bottom ); lt = transform(lt); rt = transform(rt); lb = transform(lb); rb = transform(rb); r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f); r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f); r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f); r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f); return r; } Region Transform::transform(const Region& reg) const { Region out; if (CC_UNLIKELY(type() > TRANSLATE)) { if (CC_LIKELY(preserveRects())) { Region::const_iterator it = reg.begin(); Region::const_iterator const end = reg.end(); while (it != end) { out.orSelf(transform(*it++)); } } else { out.set(transform(reg.bounds())); } } else { int xpos = floorf(tx() + 0.5f); int ypos = floorf(ty() + 0.5f); out = reg.translate(xpos, ypos); } return out; } uint32_t Transform::type() const { if (mType & UNKNOWN_TYPE) { // recompute what this transform is const mat33& M(mMatrix); const float a = M[0][0]; const float b = M[1][0]; const float c = M[0][1]; const float d = M[1][1]; const float x = M[2][0]; const float y = M[2][1]; bool scale = false; uint32_t flags = ROT_0; if (isZero(b) && isZero(c)) { if (a<0) flags |= FLIP_H; if (d<0) flags |= FLIP_V; if (!absIsOne(a) || !absIsOne(d)) { scale = true; } } else if (isZero(a) && isZero(d)) { flags |= ROT_90; if (b>0) flags |= FLIP_V; if (c<0) flags |= FLIP_H; if (!absIsOne(b) || !absIsOne(c)) { scale = true; } } else { // there is a skew component and/or a non 90 degrees rotation flags = ROT_INVALID; } mType = flags << 8; if (flags & ROT_INVALID) { mType |= UNKNOWN; } else { if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180)) mType |= ROTATE; if (flags & FLIP_H) mType ^= SCALE; if (flags & FLIP_V) mType ^= SCALE; if (scale) mType |= SCALE; } if (!isZero(x) || !isZero(y)) mType |= TRANSLATE; } return mType; } Transform Transform::inverse() const { // our 3x3 matrix is always of the form of a 2x2 transformation // followed by a translation: T*M, therefore: // (T*M)^-1 = M^-1 * T^-1 Transform result; if (mType <= TRANSLATE) { // 1 0 0 // 0 1 0 // x y 1 result = *this; result.mMatrix[2][0] = -result.mMatrix[2][0]; result.mMatrix[2][1] = -result.mMatrix[2][1]; } else { // a c 0 // b d 0 // x y 1 const mat33& M(mMatrix); const float a = M[0][0]; const float b = M[1][0]; const float c = M[0][1]; const float d = M[1][1]; const float x = M[2][0]; const float y = M[2][1]; const float idet = 1.0 / (a*d - b*c); result.mMatrix[0][0] = d*idet; result.mMatrix[0][1] = -c*idet; result.mMatrix[1][0] = -b*idet; result.mMatrix[1][1] = a*idet; result.mType = mType; vec2 T(-x, -y); T = result.transform(T); result.mMatrix[2][0] = T[0]; result.mMatrix[2][1] = T[1]; } return result; } uint32_t Transform::getType() const { return type() & 0xFF; } uint32_t Transform::getOrientation() const { return (type() >> 8) & 0xFF; } bool Transform::preserveRects() const { return (getOrientation() & ROT_INVALID) ? false : true; } void Transform::dump(const char* name) const { type(); // updates the type String8 flags, type; const mat33& m(mMatrix); uint32_t orient = mType >> 8; if (orient&ROT_INVALID) { flags.append("ROT_INVALID "); } else { if (orient&ROT_90) { flags.append("ROT_90 "); } else { flags.append("ROT_0 "); } if (orient&FLIP_V) flags.append("FLIP_V "); if (orient&FLIP_H) flags.append("FLIP_H "); } if (!(mType&(SCALE|ROTATE|TRANSLATE))) type.append("IDENTITY "); if (mType&SCALE) type.append("SCALE "); if (mType&ROTATE) type.append("ROTATE "); if (mType&TRANSLATE) type.append("TRANSLATE "); ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string()); ALOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]); ALOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]); ALOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); } // --------------------------------------------------------------------------- }; // namespace android services/surfaceflinger/Transform.h0100644 0000000 0000000 00000006547 13077405420 016571 0ustar000000000 0000000 /* * Copyright (C) 2007 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_TRANSFORM_H #define ANDROID_TRANSFORM_H #include #include #include #include #include #include #include namespace android { class Region; // --------------------------------------------------------------------------- class Transform { public: Transform(); Transform(const Transform& other); explicit Transform(uint32_t orientation); ~Transform(); enum orientation_flags { ROT_0 = 0x00000000, FLIP_H = HAL_TRANSFORM_FLIP_H, FLIP_V = HAL_TRANSFORM_FLIP_V, ROT_90 = HAL_TRANSFORM_ROT_90, ROT_180 = FLIP_H|FLIP_V, ROT_270 = ROT_180|ROT_90, ROT_INVALID = 0x80 }; enum type_mask { IDENTITY = 0, TRANSLATE = 0x1, ROTATE = 0x2, SCALE = 0x4, UNKNOWN = 0x8 }; // query the transform bool preserveRects() const; uint32_t getType() const; uint32_t getOrientation() const; const vec3& operator [] (size_t i) const; // returns column i float tx() const; float ty() const; // modify the transform void reset(); void set(float tx, float ty); void set(float a, float b, float c, float d); status_t set(uint32_t flags, float w, float h); // transform data Rect makeBounds(int w, int h) const; vec2 transform(int x, int y) const; Region transform(const Region& reg) const; Rect transform(const Rect& bounds) const; Transform operator * (const Transform& rhs) const; // assumes the last row is < 0 , 0 , 1 > vec2 transform(const vec2& v) const; vec3 transform(const vec3& v) const; Transform inverse() const; // for debugging void dump(const char* name) const; private: struct mat33 { vec3 v[3]; inline const vec3& operator [] (int i) const { return v[i]; } inline vec3& operator [] (int i) { return v[i]; } }; enum { UNKNOWN_TYPE = 0x80000000 }; uint32_t type() const; static bool absIsOne(float f); static bool isZero(float f); mat33 mMatrix; mutable uint32_t mType; }; // --------------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_TRANSFORM_H */ services/surfaceflinger/clz.h0100644 0000000 0000000 00000002676 13077405420 015405 0ustar000000000 0000000 /* * Copyright (C) 2007 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_SURFACE_FLINGER_CLZ_H #include namespace android { int inline clz(int32_t x) { return __builtin_clz(x); } template static inline T min(T a, T b) { return a static inline T min(T a, T b, T c) { return min(a, min(b, c)); } template static inline T min(T a, T b, T c, T d) { return min(a, b, min(c, d)); } template static inline T max(T a, T b) { return a>b ? a : b; } template static inline T max(T a, T b, T c) { return max(a, max(b, c)); } template static inline T max(T a, T b, T c, T d) { return max(a, b, max(c, d)); } template static inline void swap(T& a, T& b) { T t(a); a = b; b = t; } }; // namespace android #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */ services/surfaceflinger/main_surfaceflinger.cpp0100644 0000000 0000000 00000004070 13077405420 021141 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include #include #include #include #include "GpuService.h" #include "SurfaceFlinger.h" using namespace android; int main(int, char**) { signal(SIGPIPE, SIG_IGN); // When SF is launched in its own process, limit the number of // binder threads to 4. ProcessState::self()->setThreadPoolMaxThreadCount(4); // start the thread pool sp ps(ProcessState::self()); ps->startThreadPool(); // instantiate surfaceflinger sp flinger = new SurfaceFlinger(); setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); set_sched_policy(0, SP_FOREGROUND); #ifdef ENABLE_CPUSETS // Put most SurfaceFlinger threads in the system-background cpuset // Keeps us from unnecessarily using big cores // Do this after the binder thread pool init set_cpuset_policy(0, SP_SYSTEM); #endif // initialize before clients can connect flinger->init(); // publish surface flinger sp sm(defaultServiceManager()); sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); // publish GpuService sp gpuservice = new GpuService(); sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false); // run surface flinger in this thread flinger->run(); return 0; } services/surfaceflinger/surfaceflinger.rc0100644 0000000 0000000 00000000304 13077405420 017753 0ustar000000000 0000000 service surfaceflinger /system/bin/surfaceflinger class core user system group graphics drmrpc readproc onrestart restart zygote writepid /sys/fs/cgroup/stune/foreground/tasks services/surfaceflinger/tests/0040755 0000000 0000000 00000000000 13077405420 015576 5ustar000000000 0000000 services/surfaceflinger/tests/Android.mk0100644 0000000 0000000 00000001473 13077405420 017511 0ustar000000000 0000000 # Build the unit tests, LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := SurfaceFlinger_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ Transaction_test.cpp \ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv2 \ libbinder \ libcutils \ libgui \ libui \ libutils \ # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) # Include subdirectory makefiles # ============================================================ # If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework # team really wants is to build the stuff defined by this makefile. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif services/surfaceflinger/tests/Transaction_test.cpp0100644 0000000 0000000 00000044707 13077405420 021637 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #include #include #include #include #include namespace android { // Fill an RGBA_8888 formatted surface with a single color. static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b) { ANativeWindow_Buffer outBuffer; sp s = sc->getSurface(); ASSERT_TRUE(s != NULL); ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, NULL)); uint8_t* img = reinterpret_cast(outBuffer.bits); for (int y = 0; y < outBuffer.height; y++) { for (int x = 0; x < outBuffer.width; x++) { uint8_t* pixel = img + (4 * (y*outBuffer.stride + x)); pixel[0] = r; pixel[1] = g; pixel[2] = b; pixel[3] = 255; } } ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check // individual pixel values for testing purposes. class ScreenCapture : public RefBase { public: static void captureScreen(sp* sc) { sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); IGraphicBufferProducer::QueueBufferOutput bufferOutput; sp cpuConsumer = new CpuConsumer(consumer, 1); sp sf(ComposerService::getComposerService()); sp display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); SurfaceComposerClient::openGlobalTransaction(); SurfaceComposerClient::closeGlobalTransaction(true); ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0, 0, INT_MAX, false)); *sc = new ScreenCapture(cpuConsumer); } void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format); const uint8_t* img = static_cast(mBuf.data); const uint8_t* pixel = img + (4 * (y * mBuf.stride + x)); if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", x, y, r, g, b, pixel[0], pixel[1], pixel[2])); EXPECT_EQ(String8(), err) << err.string(); } } private: ScreenCapture(const sp& cc) : mCC(cc) { EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf)); } ~ScreenCapture() { mCC->unlockBuffer(mBuf); } sp mCC; CpuConsumer::LockedBuffer mBuf; }; class LayerUpdateTest : public ::testing::Test { protected: virtual void SetUp() { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); sp display(SurfaceComposerClient::getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); DisplayInfo info; SurfaceComposerClient::getDisplayInfo(display, &info); ssize_t displayWidth = info.w; ssize_t displayHeight = info.h; // Background surface mBGSurfaceControl = mComposerClient->createSurface( String8("BG Test Surface"), displayWidth, displayHeight, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mBGSurfaceControl != NULL); ASSERT_TRUE(mBGSurfaceControl->isValid()); fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); // Foreground surface mFGSurfaceControl = mComposerClient->createSurface( String8("FG Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mFGSurfaceControl != NULL); ASSERT_TRUE(mFGSurfaceControl->isValid()); fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); // Synchronization surface mSyncSurfaceControl = mComposerClient->createSurface( String8("Sync Test Surface"), 1, 1, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mSyncSurfaceControl != NULL); ASSERT_TRUE(mSyncSurfaceControl->isValid()); fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); SurfaceComposerClient::openGlobalTransaction(); mComposerClient->setDisplayLayerStack(display, 0); ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2)); ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX-1)); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT_MAX-1)); ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2, displayHeight-2)); ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(true); } virtual void TearDown() { mComposerClient->dispose(); mBGSurfaceControl = 0; mFGSurfaceControl = 0; mSyncSurfaceControl = 0; mComposerClient = 0; } void waitForPostedBuffers() { // Since the sync surface is in synchronous mode (i.e. double buffered) // posting three buffers to it should ensure that at least two // SurfaceFlinger::handlePageFlip calls have been made, which should // guaranteed that a buffer posted to another Surface has been retired. fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); } sp mComposerClient; sp mBGSurfaceControl; sp mFGSurfaceControl; // This surface is used to ensure that the buffers posted to // mFGSurfaceControl have been picked up by SurfaceFlinger. sp mSyncSurfaceControl; }; TEST_F(LayerUpdateTest, LayerMoveWorks) { sp sc; { SCOPED_TRACE("before move"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 0, 12, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should reflect the new position, but not the new color. SCOPED_TRACE("after move, before redraw"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 195, 63, 63); } fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); waitForPostedBuffers(); { // This should reflect the new position and the new color. SCOPED_TRACE("after redraw"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 63, 195, 63); } } TEST_F(LayerUpdateTest, LayerResizeWorks) { sp sc; { SCOPED_TRACE("before resize"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 0, 12, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } ALOGD("resizing"); SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); SurfaceComposerClient::closeGlobalTransaction(true); ALOGD("resized"); { // This should not reflect the new size or color because SurfaceFlinger // has not yet received a buffer of the correct size. SCOPED_TRACE("after resize, before redraw"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 0, 12, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } ALOGD("drawing"); fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); waitForPostedBuffers(); ALOGD("drawn"); { // This should reflect the new size and the new color. SCOPED_TRACE("after redraw"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 195, 63); sc->checkPixel(145, 145, 63, 195, 63); } } TEST_F(LayerUpdateTest, LayerCropWorks) { sp sc; { SCOPED_TRACE("before crop"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); Rect cropRect(16, 16, 32, 32); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should crop the foreground surface. SCOPED_TRACE("after crop"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel( 95, 80, 195, 63, 63); sc->checkPixel( 80, 95, 195, 63, 63); sc->checkPixel( 96, 96, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerFinalCropWorks) { sp sc; { SCOPED_TRACE("before crop"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); Rect cropRect(16, 16, 32, 32); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should crop the foreground surface. SCOPED_TRACE("after crop"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel( 95, 80, 63, 63, 195); sc->checkPixel( 80, 95, 63, 63, 195); sc->checkPixel( 96, 96, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerSetLayerWorks) { sp sc; { SCOPED_TRACE("before setLayer"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should hide the foreground surface beneath the background. SCOPED_TRACE("after setLayer"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerShowHideWorks) { sp sc; { SCOPED_TRACE("before hide"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide()); SurfaceComposerClient::closeGlobalTransaction(true); { // This should hide the foreground surface. SCOPED_TRACE("after hide, before show"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(true); { // This should show the foreground surface. SCOPED_TRACE("after show"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerSetAlphaWorks) { sp sc; { SCOPED_TRACE("before setAlpha"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should set foreground to be 75% opaque. SCOPED_TRACE("after setAlpha"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 162, 63, 96); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerSetLayerStackWorks) { sp sc; { SCOPED_TRACE("before setLayerStack"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should hide the foreground surface since it goes to a different // layer stack. SCOPED_TRACE("after setLayerStack"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerSetFlagsWorks) { sp sc; { SCOPED_TRACE("before setFlags"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags( layer_state_t::eLayerHidden, layer_state_t::eLayerHidden)); SurfaceComposerClient::closeGlobalTransaction(true); { // This should hide the foreground surface SCOPED_TRACE("after setFlags"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 75, 75, 63, 63, 195); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, LayerSetMatrixWorks) { sp sc; { SCOPED_TRACE("before setMatrix"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 91, 96, 195, 63, 63); sc->checkPixel( 96, 101, 195, 63, 63); sc->checkPixel(145, 145, 63, 63, 195); } SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2)); SurfaceComposerClient::closeGlobalTransaction(true); { SCOPED_TRACE("after setMatrix"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 24, 24, 63, 63, 195); sc->checkPixel( 91, 96, 195, 63, 63); sc->checkPixel( 96, 91, 63, 63, 195); sc->checkPixel(145, 145, 63, 63, 195); } } TEST_F(LayerUpdateTest, DeferredTransactionTest) { sp sc; { SCOPED_TRACE("before anything"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 32, 32, 63, 63, 195); sc->checkPixel( 96, 96, 195, 63, 63); sc->checkPixel(160, 160, 63, 63, 195); } // set up two deferred transactions on different frames SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75)); mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(), mSyncSurfaceControl->getSurface()->getNextFrameNumber()); SurfaceComposerClient::closeGlobalTransaction(true); SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128)); mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(), mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1); SurfaceComposerClient::closeGlobalTransaction(true); { SCOPED_TRACE("before any trigger"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 32, 32, 63, 63, 195); sc->checkPixel( 96, 96, 195, 63, 63); sc->checkPixel(160, 160, 63, 63, 195); } // should trigger the first deferred transaction, but not the second one fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); { SCOPED_TRACE("after first trigger"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 32, 32, 63, 63, 195); sc->checkPixel( 96, 96, 162, 63, 96); sc->checkPixel(160, 160, 63, 63, 195); } // should show up immediately since it's not deferred SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0)); SurfaceComposerClient::closeGlobalTransaction(true); // trigger the second deferred transaction fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); { SCOPED_TRACE("after second trigger"); ScreenCapture::captureScreen(&sc); sc->checkPixel( 32, 32, 63, 63, 195); sc->checkPixel( 96, 96, 63, 63, 195); sc->checkPixel(160, 160, 195, 63, 63); } } } services/surfaceflinger/tests/vsync/0040755 0000000 0000000 00000000000 13077405420 016740 5ustar000000000 0000000 services/surfaceflinger/tests/vsync/Android.mk0100644 0000000 0000000 00000000407 13077405420 020647 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ vsync.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder \ libui \ libgui LOCAL_MODULE:= test-vsync-events LOCAL_MODULE_TAGS := tests include $(BUILD_EXECUTABLE) services/surfaceflinger/tests/vsync/vsync.cpp0100644 0000000 0000000 00000004722 13077405420 020610 0ustar000000000 0000000 /* * Copyright (C) 2010 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 #include #include using namespace android; int receiver(int fd, int events, void* data) { DisplayEventReceiver* q = (DisplayEventReceiver*)data; ssize_t n; DisplayEventReceiver::Event buffer[1]; static nsecs_t oldTimeStamp = 0; while ((n = q->getEvents(buffer, 1)) > 0) { for (int i=0 ; i loop = new Looper(false); loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver, &myDisplayEvent); myDisplayEvent.setVsyncRate(1); do { //printf("about to poll...\n"); int32_t ret = loop->pollOnce(-1); switch (ret) { case ALOOPER_POLL_WAKE: //("ALOOPER_POLL_WAKE\n"); break; case ALOOPER_POLL_CALLBACK: //("ALOOPER_POLL_CALLBACK\n"); break; case ALOOPER_POLL_TIMEOUT: printf("ALOOPER_POLL_TIMEOUT\n"); break; case ALOOPER_POLL_ERROR: printf("ALOOPER_POLL_TIMEOUT\n"); break; default: printf("ugh? poll returned %d\n", ret); break; } } while (1); return 0; } services/surfaceflinger/tests/waitforvsync/0040755 0000000 0000000 00000000000 13077405420 020334 5ustar000000000 0000000 services/surfaceflinger/tests/waitforvsync/Android.mk0100644 0000000 0000000 00000000336 13077405420 022244 0ustar000000000 0000000 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ waitforvsync.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ LOCAL_MODULE:= test-waitforvsync LOCAL_MODULE_TAGS := tests include $(BUILD_EXECUTABLE) services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp0100644 0000000 0000000 00000002411 13077405420 023571 0ustar000000000 0000000 /* * 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 #include #include #include #include #include #include #include #include #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif int main(int argc, char** argv) { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd >= 0) { do { uint32_t crt = 0; int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt); if (err < 0) { printf("FBIO_WAITFORVSYNC error: %s\n", strerror(errno)); break; } } while(1); close(fd); } return 0; } vulkan/0040755 0000000 0000000 00000000000 13077405420 011112 5ustar000000000 0000000 vulkan/.clang-format0100644 0000000 0000000 00000000046 13077405420 013462 0ustar000000000 0000000 BasedOnStyle: Chromium IndentWidth: 4 vulkan/Android.mk0100644 0000000 0000000 00000000104 13077405420 013013 0ustar000000000 0000000 include $(call all-named-subdir-makefiles, libvulkan nulldrv tools) vulkan/README.md0100644 0000000 0000000 00000003110 13077405420 012361 0ustar000000000 0000000 # frameworks/native/vulkan This subdirectory contains Android's Vulkan loader, as well as some Vulkan-related tools useful to platform developers. ## Coding Style We follow the [Chromium coding style](https://www.chromium.org/developers/coding-style) for naming and formatting, except with four-space indentation instead of two spaces. In general, any C++ features supported by the prebuilt platform toolchain are allowed. Use "clang-format -style=file" to format all C/C++ code, except code imported verbatim from elsewhere. Setting up git-clang-format in your environment is recommended. ## Code Generation We generate several parts of the loader and tools from a Vulkan API description file, stored in `api/vulkan.api`. Code generation must be done manually because the generator tools aren't part of the platform toolchain (yet?). Files named `foo_gen.*` are generated from the API file and a template file named `foo.tmpl`. To run the generator: ### One-time setup - Install [golang](https://golang.org/), if you don't have it already. - Create a directory (e.g. `$HOME/lib/go`) for local go sources and binaries and add it to `$GOPATH`. - `$ git clone https://android.googlesource.com/platform/tools/gpu $GOPATH/src/android.googlesource.com/platform/tools/gpu` - `$ go get android.googlesource.com/platform/tools/gpu/api/...` - You should now have `$GOPATH/bin/apic`. You might want to add `$GOPATH/bin` to your `$PATH`. ### Generating code To generate `libvulkan/*_gen.*`, - `$ cd libvulkan` - `$ apic template ../api/vulkan.api code-generator.tmpl` Similar for `nulldrv/null_driver_gen.*`. vulkan/api/0040755 0000000 0000000 00000000000 13077405420 011663 5ustar000000000 0000000 vulkan/api/platform.api0100644 0000000 0000000 00000003441 13077405420 014201 0ustar000000000 0000000 // Copyright (c) 2015 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and/or associated documentation files (the // "Materials"), to deal in the Materials without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Materials, and to // permit persons to whom the Materials are furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Materials. // // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. // Platform types, as defined or included in vk_platform.h type u64 size_t // VK_USE_PLATFORM_XLIB_KHR @internal class Display {} @internal class Window {} @internal type u64 VisualID // VK_USE_PLATFORM_XCB_KHR @internal class xcb_connection_t {} @internal type u32 xcb_window_t @internal type u32 xcb_visualid_t // VK_USE_PLATFORM_WAYLAND_KHR @internal class wl_display {} @internal class wl_surface {} // VK_USE_PLATFORM_MIR_KHR @internal class MirConnection {} @internal class MirSurface {} // VK_USE_PLATFORM_ANDROID_KHR @internal class ANativeWindow {} @internal type void* buffer_handle_t // VK_USE_PLATFORM_WIN32_KHR @internal type void* HINSTANCE @internal type void* HWND vulkan/api/templates/0040755 0000000 0000000 00000000000 13077405420 013661 5ustar000000000 0000000 vulkan/api/templates/asciidoc.tmpl0100644 0000000 0000000 00000012043 13077405420 016332 0ustar000000000 0000000 {{Include "vulkan_common.tmpl"}} {{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}} {{$ | Macro "AsciiDoc.Main"}} {{/* ------------------------------------------------------------------------------- AsciiDoc generation main entry point. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Main"}} {{$docPath := Global "AsciiDocPath"}} {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}} {{range $e := $.Enums}} {{if not $e.IsBitfield}} {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}} {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}} {{else}} {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}} {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}} {{end}} {{end}} {{/* Generate AsciiDoc files for API commands (protos). */}} {{range $f := (AllCommands $)}} {{if not (GetAnnotation $f "pfn")}} {{$filename := print $docPath "protos/" $f.Name ".txt"}} {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}} {{end}} {{end}} {{/* Generate AsciiDoc files for API structs. */}} {{range $c := $.Classes}} {{if not (GetAnnotation $c "internal")}} {{$filename := print $docPath "structs/" $c.Name ".txt"}} {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}} {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the AsciiDoc contents for the specified API enum. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Enum"}} {{AssertType $ "Enum"}} {{Macro "Docs" $.Docs}} typedef enum { {{range $i, $e := $.Entries}} {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}} {{end}} ¶ {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} {{$first := Macro "EnumFirstEntry" $}} {{$last := Macro "EnumLastEntry" $}} {{$name}}_BEGIN_RANGE = {{$first}}, {{$name}}_END_RANGE = {{$last}}, {{$name}}_NUM = ({{$last}} - {{$first}} + 1), {{$name}}_MAX_ENUM = 0x7FFFFFFF } {{Macro "EnumName" $}}; {{end}} {{/* ------------------------------------------------------------------------------- Emits the AsciiDoc contents for the specified API bitfield. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Flag"}} {{AssertType $ "Enum"}} {{Macro "Docs" $.Docs}} typedef VkFlags {{Macro "EnumName" $}}; {{if $.Entries}} typedef enum { {{range $e := $.Entries}} {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}} {{end}} } {{Macro "EnumName" $ | TrimRight "s"}}Bits; {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the AsciiDoc contents for the specified API class. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Struct"}} {{AssertType $ "Class"}} {{Macro "Docs" $.Docs}} typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} { {{range $f := $.Fields}} {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}} {{end}} } {{Macro "StructName" $}}; {{end}} {{/* ------------------------------------------------------------------------------- Emits the AsciiDoc contents for the specified API function. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Proto"}} {{AssertType $ "Function"}} {{Macro "Docs" $.Docs}} {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); {{end}} {{/* ------------------------------------------------------------------------------- Wraps the specified Code in AsciiDoc source tags then writes to the specified File. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Write"}} {{AssertType $.Code "string"}} {{AssertType $.File "string"}} {{$code := $.Code | Format (Global "clang-format")}} {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}} {{end}} {{/* ------------------------------------------------------------------------------- Emits an AsciiDoc source header. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Header"}} [source,{basebackend@docbook:c++:cpp}] ------------------------------------------------------------------------------ {{end}} {{/* ------------------------------------------------------------------------------- Emits an AsciiDoc source footer. ------------------------------------------------------------------------------- */}} {{define "AsciiDoc.Footer"}} ------------------------------------------------------------------------------ {{end}} vulkan/api/templates/vk_xml.tmpl0100644 0000000 0000000 00000044177 13077405420 016071 0ustar000000000 0000000 {{Include "vulkan_common.tmpl"}} {{Macro "DefineGlobals" $}} {{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}} {{/* ------------------------------------------------------------------------------- Entry point ------------------------------------------------------------------------------- */}} {{define "vk.xml"}} »« Copyright (c) 2015 The Khronos Group Inc. ¶ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and/or associated documentation files (the "Materials"), to deal in the Materials without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials, and to permit persons to whom the Materials are furnished to do so, subject to the following conditions: ¶ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Materials. ¶ THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ¶ ------------------------------------------------------------------------ ¶ This file, vk.xml, is the Vulkan API Registry.» » #include "vk_platform.h"#define VK_MAKE_VERSION(major, minor, patch) \ «((major << 22) | (minor << 12) | patch)» ¶ // Vulkan API version supported by this file«« #define VK_API_VERSION VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) ¶ »»«« #if (_MSC_VER >= 1800 || __cplusplus >= 201103L) #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } #else #define VK_NONDISP_HANDLE_OPERATOR_BOOL() «#endif »»»««« #define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; »»»««« #if defined(__cplusplus) »»#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) »// The bool operator only works if there are no implicit conversions from an obj to // a bool-compatible type, which can then be used to unintentionally violate type safety. // C++11 and above supports the "explicit" keyword on conversion operators to stop this // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating // the object handle as a bool in expressions like: // if (obj) vkDestroy(obj); #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ explicit obj(uint64_t x) : handle(x) { } \ obj(decltype(nullptr)) : handle(0) { } «#else» #define VK_NONDISP_HANDLE_OPERATOR_BOOL() #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ obj(uint64_t x) : handle(x) { } «#endif #define VK_DEFINE_NONDISP_HANDLE(obj) \» struct obj { \ obj() { } \ VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ obj& operator =(uint64_t x) { handle = x; return *this; } \ bool operator==(const obj& other) const { return handle == other.handle; } \ bool operator!=(const obj& other) const { return handle != other.handle; } \ bool operator!() const { return !handle; } \ VK_NONDISP_HANDLE_OPERATOR_BOOL() \ uint64_t handle; \ }; ««#else »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;« #endif »» #if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800) || __cplusplus >= 201103L) »#define VK_NULL_HANDLE nullptr «#else »#define VK_NULL_HANDLE 0 «#endif »» {{range $e := $.Enums}} {{if $e.IsBitfield}} {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}} typedef VkFlags {{$e.Name}};§ {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}} {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}} {{end}} {{end}} {{end}} ¶ {{range $i, $p := $.Pseudonyms}} {{ if (GetAnnotation $p "dispatchHandle")}} {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}} VK_DEFINE_HANDLE({{$p.Name}}) {{else}} {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}} VK_DEFINE_HANDLE({{$p.Name}}) {{end}} {{else if (GetAnnotation $p "nonDispatchHandle")}} {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}} VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) {{else}} {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}} VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) {{end}} {{end}} {{end}} ¶ {{range $e := SortBy $.Enums "EnumName"}} {{if and $e.Entries (not (GetAnnotation $e "internal"))}} {{if $e.IsBitfield}} {{else}} {{end}} {{end}} {{end}} ¶ typedef void* (VKAPI *PFN_vkAllocFunction)(« void* pUserData, size_t size, size_t alignment, VkSystemAllocType allocType);» typedef void (VKAPI *PFN_vkFreeFunction)(« void* pUserData, void* pMem);» ¶ typedef void (VKAPI *PFN_vkVoidFunction)(void); {{range $c := $.Classes}} {{if not (GetAnnotation $c "internal")}} {{Macro "Struct" $c}} {{end}} {{end}} «» {{range $d := $.Definitions}} {{if HasPrefix $d.Name "VK_"}} {{Macro "XML.Docs" $d.Docs}} {{end}} {{end}} «« ¶ {{range $e := $.Enums}} {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}} {{Macro "XML.Enum" $e}} {{end}} {{end}} ¶ {{range $e := $.Enums}} {{if $e.IsBitfield}} {{Macro "XML.Bitfield" $e}} {{end}} {{end}} ¶ » {{range $f := AllCommands $}} {{if not (GetAnnotation $f "pfn")}} {{Macro "XML.Function" $f}} {{end}} {{end}} « » » « » « » « » {{range $f := AllCommands $}} {{if not (GetAnnotation $f "pfn")}} {{end}} {{end}} «» « « « {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified bitfield. ------------------------------------------------------------------------------- */}} {{define "XML.Bitfield"}} {{AssertType $ "Enum"}} {{if $.Entries}} » {{range $e := $.Entries}} {{$pos := Bitpos $e.Value}} {{end}} « {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified enum. ------------------------------------------------------------------------------- */}} {{define "XML.Enum"}} {{AssertType $ "Enum"}} » {{range $i, $e := $.Entries}} {{end}} {{if $lu := GetAnnotation $ "lastUnused"}} {{end}} « {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified class. ------------------------------------------------------------------------------- */}} {{define "Struct"}} {{AssertType $ "Class"}} » {{range $f := $.Fields}} {{Node "XML.Type" $f}} {{$f.Name}}{{Macro "XML.ArrayPostfix" $f}}{{Macro "XML.Docs" $f.Docs}} {{end}} « {{end}} {{/* ------------------------------------------------------------------------------- Emits either 'struct' or 'union' for the specified class. ------------------------------------------------------------------------------- */}} {{define "StructType"}} {{AssertType $ "Class"}} {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the C function pointer typedef declaration for the specified command. ------------------------------------------------------------------------------- */}} {{define "XML.Function"}} {{AssertType $ "Function"}} {{$ts := GetAnnotation $ "threadSafety"}} » {{Node "XML.Type" $.Return}} {{$.Name}} {{range $p := $.CallParameters}} {{Node "XML.Type" $p}} {{$p.Name}}{{Macro "ArrayPostfix" $p}} {{end}} « {{end}} {{/* ------------------------------------------------------------------------------- Emits the XML translation for the specified documentation block (string array). ------------------------------------------------------------------------------- */}} {{define "XML.Docs"}} {{if $}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the C translation for the specified type. ------------------------------------------------------------------------------- */}} {{define "XML.Type.Class" }}{{Macro "StructName" $.Type}}{{end}} {{define "XML.Type.Pseudonym" }}{{$.Type.Name}}{{end}} {{define "XML.Type.Enum" }}{{$.Type.Name}}{{end}} {{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}} {{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}} {{define "XML.Type.Slice" }}{{Node "XML.Type" $.Type.To}}*{{end}} {{define "XML.Type#s8" }}int8_t{{end}} {{define "XML.Type#u8" }}uint8_t{{end}} {{define "XML.Type#s16" }}int16_t{{end}} {{define "XML.Type#u16" }}uint16_t{{end}} {{define "XML.Type#s32" }}int32_t{{end}} {{define "XML.Type#u32" }}uint32_t{{end}} {{define "XML.Type#f32" }}float{{end}} {{define "XML.Type#s64" }}int64_t{{end}} {{define "XML.Type#u64" }}uint64_t{{end}} {{define "XML.Type#f64" }}double{{end}} {{define "XML.Type#char" }}char{{end}} {{define "XML.Type#void" }}void{{end}} {{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}} {{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}} {{/* ------------------------------------------------------------------------------- Emits a C type and name for the given parameter ------------------------------------------------------------------------------- */}} {{define "XML.Parameter"}} {{AssertType $ "Parameter"}} {{Macro "ParameterType" $}} {{$.Name}}{{Macro "ArrayPostfix" $}} {{end}} {{/* ------------------------------------------------------------------------------- Emits a comma-separated list of C type-name paired parameters for the given command. ------------------------------------------------------------------------------- */}} {{define "XML.Parameters"}} {{AssertType $ "Function"}} {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}} {{if not $.CallParameters}}void{{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the fixed-size-array postfix for pseudonym types annotated with @array ------------------------------------------------------------------------------- */}} {{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}} {{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}} {{define "XML.ArrayPostfix_Default"}}{{end}} {{/* ------------------------------------------------------------------------------- Emits the value of the given constant, or the tagged name if existant. ------------------------------------------------------------------------------- */}} {{define "XML.NamedValue.Definition"}}{{$.Node.Name}}{{end}} {{define "XML.NamedValue.EnumEntry"}}{{$.Node.Name}}{{end}} {{define "XML.NamedValue_Default"}}{{$.Node}}{{end}} vulkan/api/templates/vulkan_common.tmpl0100644 0000000 0000000 00000016541 13077405420 017433 0ustar000000000 0000000 {{$clang_style := "{BasedOnStyle: Google, AccessModifierOffset: -4, ColumnLimit: 200, ContinuationIndentWidth: 8, IndentWidth: 4, AlignOperands: true, CommentPragmas: '.*'}"}} {{Global "clang-format" (Strings "clang-format" "-style" $clang_style)}} {{/* ------------------------------------------------------------------------------- Emits the C translation for the specified type. ------------------------------------------------------------------------------- */}} {{define "Type.Class" }}{{if GetAnnotation $.Type "internal"}}struct {{end}}{{Macro "StructName" $.Type}}{{end}} {{define "Type.Pseudonym" }}{{$.Type.Name}}{{end}} {{define "Type.Enum" }}{{$.Type.Name}}{{end}} {{define "Type.StaticArray"}}{{Node "Type" $.Type.ValueType}}{{end}} {{define "Type.Pointer" }}{{if $.Type.Const}}{{Node "ConstType" $.Type.To}}{{else}}{{Node "Type" $.Type.To}}{{end}}*{{end}} {{define "Type.Slice" }}{{Log "%T %+v" $.Node $.Node}}{{Node "Type" $.Type.To}}*{{end}} {{define "Type#bool" }}bool{{end}} {{define "Type#int" }}int{{end}} {{define "Type#uint" }}unsigned int{{end}} {{define "Type#s8" }}int8_t{{end}} {{define "Type#u8" }}uint8_t{{end}} {{define "Type#s16" }}int16_t{{end}} {{define "Type#u16" }}uint16_t{{end}} {{define "Type#s32" }}int32_t{{end}} {{define "Type#u32" }}uint32_t{{end}} {{define "Type#f32" }}float{{end}} {{define "Type#s64" }}int64_t{{end}} {{define "Type#u64" }}uint64_t{{end}} {{define "Type#f64" }}double{{end}} {{define "Type#void" }}void{{end}} {{define "Type#char" }}char{{end}} {{define "ConstType_Default"}}const {{Node "Type" $.Type}}{{end}} {{define "ConstType.Pointer"}}{{Node "Type" $.Type}} const{{end}} {{/* ------------------------------------------------------------------------------- Emits the C translation for the specified documentation block (string array). ------------------------------------------------------------------------------- */}} {{define "Docs"}} {{if $}}// {{$ | JoinWith "\n// "}}{{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the name of a bitfield entry. ------------------------------------------------------------------------------- */}} {{define "BitfieldEntryName"}} {{AssertType $ "EnumEntry"}} {{Macro "EnumEntry" $}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the name of an enum type. ------------------------------------------------------------------------------- */}} {{define "EnumName"}}{{AssertType $ "Enum"}}{{$.Name}}{{end}} {{/* ------------------------------------------------------------------------------- Emits the name of an enum entry. ------------------------------------------------------------------------------- */}} {{define "EnumEntry"}} {{AssertType $.Owner "Enum"}} {{AssertType $.Name "string"}} {{$.Name}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the name of the first entry of an enum. ------------------------------------------------------------------------------- */}} {{define "EnumFirstEntry"}} {{AssertType $ "Enum"}} {{range $i, $e := $.Entries}} {{if not $i}}{{$e.Name}}{{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the name of the last entry of an enum. ------------------------------------------------------------------------------- */}}{{define "EnumLastEntry"}} {{AssertType $ "Enum"}} {{range $i, $e := $.Entries}} {{if not (HasMore $i $.Entries)}}{{$e.Name}}{{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the name of a struct (class) type. ------------------------------------------------------------------------------- */}} {{define "StructName"}}{{AssertType $ "Class"}}{{$.Name}}{{end}} {{/* ------------------------------------------------------------------------------- Emits the name of a function. ------------------------------------------------------------------------------- */}} {{define "FunctionName"}}{{AssertType $ "Function"}}{{$.Name}}{{end}} {{/* ------------------------------------------------------------------------------- Emits the fixed-size-array postfix for pseudonym types annotated with @array ------------------------------------------------------------------------------- */}} {{define "ArrayPostfix"}}{{Node "ArrayPostfix" $}}{{end}} {{define "ArrayPostfix.StaticArray"}}[{{$.Type.Size}}]{{end}} {{define "ArrayPostfix_Default"}}{{end}} {{/* ------------------------------------------------------------------------------- Emits a C type and name for the given parameter ------------------------------------------------------------------------------- */}} {{define "Parameter"}} {{AssertType $ "Parameter"}} {{if GetAnnotation $ "readonly"}}const {{end}}{{Macro "ParameterType" $}} {{$.Name}}{{Macro "ArrayPostfix" $}} {{end}} {{/* ------------------------------------------------------------------------------- Emits a C name for the given parameter ------------------------------------------------------------------------------- */}} {{define "ParameterName"}} {{AssertType $ "Parameter"}} {{$.Name}} {{end}} {{/* ------------------------------------------------------------------------------- Emits a C type for the given parameter ------------------------------------------------------------------------------- */}} {{define "ParameterType"}}{{AssertType $ "Parameter"}}{{Node "Type" $}}{{end}} {{/* ------------------------------------------------------------------------------- Emits a comma-separated list of C type-name paired parameters for the given command. ------------------------------------------------------------------------------- */}} {{define "Parameters"}} {{AssertType $ "Function"}} {{ForEach $.CallParameters "Parameter" | JoinWith ", "}} {{if not $.CallParameters}}void{{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the C function pointer name for the specified command. ------------------------------------------------------------------------------- */}} {{define "FunctionPtrName"}} {{AssertType $ "Function"}} PFN_{{$.Name}} {{end}} {{/* ------------------------------------------------------------------------------- Parses const variables as text Globals. ------------------------------------------------------------------------------- */}} {{define "DefineGlobals"}} {{AssertType $ "API"}} {{range $d := $.Definitions}} {{Global $d.Name $d.Expression}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Given a function, return "Global", "Instance", or "Device" depending on which dispatch table the function belongs to. ------------------------------------------------------------------------------- */}} {{define "Vtbl#VkInstance" }}Instance{{end}} {{define "Vtbl#VkPhysicalDevice"}}Instance{{end}} {{define "Vtbl#VkDevice" }}Device{{end}} {{define "Vtbl#VkQueue" }}Device{{end}} {{define "Vtbl#VkCommandBuffer" }}Device{{end}} {{define "Vtbl_Default" }}Global{{end}} {{define "Vtbl"}} {{AssertType $ "Function"}} {{if gt (len $.CallParameters) 0}} {{Node "Vtbl" (index $.CallParameters 0)}} {{else}}Global {{end}} {{end}} vulkan/api/templates/vulkan_h.tmpl0100644 0000000 0000000 00000023545 13077405420 016374 0ustar000000000 0000000 {{Include "vulkan_common.tmpl"}} {{Macro "DefineGlobals" $}} {{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}} {{/* ------------------------------------------------------------------------------- Entry point ------------------------------------------------------------------------------- */}} {{define "vulkan.h"}} #ifndef __vulkan_h_ #define __vulkan_h_ 1 ¶ #ifdef __cplusplus extern "C" { #endif ¶ /* ** Copyright (c) 2015-2016 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ ¶ /* ** This header is generated from the Khronos Vulkan API Registry. ** */ ¶ #define VK_VERSION_1_0 1 #include "vk_platform.h" ¶ #define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) ¶ // Vulkan API version supported by this file #define VK_API_VERSION \ VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) ¶ #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) ¶ #if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) #define VK_NULL_HANDLE nullptr #else #define VK_NULL_HANDLE 0 #endif ¶ #define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; ¶ #if defined(__cplusplus) #if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) // The bool operator only works if there are no implicit conversions from an obj to // a bool-compatible type, which can then be used to unintentionally violate type safety. // C++11 and above supports the "explicit" keyword on conversion operators to stop this // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating // the object handle as a bool in expressions like: // if (obj) vkDestroy(obj); #define VK_NONDISP_HANDLE_OPERATOR_BOOL() \ explicit operator bool() const { return handle != 0; } #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ explicit obj(uint64_t x) : handle(x) { } \ obj(decltype(nullptr)) : handle(0) { } #else #define VK_NONDISP_HANDLE_OPERATOR_BOOL() #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ obj(uint64_t x) : handle(x) { } #endif #define VK_DEFINE_NONDISP_HANDLE(obj) \ struct obj { \ obj() : handle(0) { } \ VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ obj& operator=(uint64_t x) { \ handle = x; \ return *this; \ } \ bool operator==(const obj& other) const { return handle == other.handle; } \ bool operator!=(const obj& other) const { return handle != other.handle; } \ bool operator!() const { return !handle; } \ VK_NONDISP_HANDLE_OPERATOR_BOOL() \ uint64_t handle; \ }; #else #define VK_DEFINE_NONDISP_HANDLE(obj) \ typedef struct obj##_T { uint64_t handle; } obj; #endif ¶ #define VK_LOD_CLAMP_NONE 1000.0f #define VK_REMAINING_MIP_LEVELS (~0U) #define VK_REMAINING_ARRAY_LAYERS (~0U) #define VK_WHOLE_SIZE (~0ULL) #define VK_ATTACHMENT_UNUSED (~0U) define VK_QUEUE_FAMILY_IGNORED (~0U) define VK_SUBPASS_EXTERNAL (~0U) {{range $d := $.Definitions}} {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}} {{end}} ¶ {{range $i, $p := $.Pseudonyms}} {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}}) {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) {{end}} {{end}} ¶ // ------------------------------------------------------------------------------------------------ // Enumerations ¶ {{range $e := $.Enums}} {{if not $e.IsBitfield}} {{Macro "Enum" $e}} {{end}} {{end}} ¶ // ------------------------------------------------------------------------------------------------ // Flags ¶ {{range $e := $.Enums}} {{if $e.IsBitfield}} {{Macro "Bitfield" $e}} {{end}} {{end}} ¶ // ------------------------------------------------------------------------------------------------ // Vulkan structures ¶ {{/* Function pointers */}} {{range $f := AllCommands $}} {{if GetAnnotation $f "pfn"}} {{Macro "FunctionTypedef" $f}} {{end}} {{end}} ¶ {{range $c := $.Classes}} {{if not (GetAnnotation $c "internal")}} {{Macro "Struct" $c}} {{end}} {{end}} ¶ // ------------------------------------------------------------------------------------------------ // API functions ¶ {{range $f := AllCommands $}} {{if not (GetAnnotation $f "pfn")}} {{Macro "FunctionTypedef" $f}} {{end}} {{end}} ¶ #ifdef VK_NO_PROTOTYPES ¶ {{range $f := AllCommands $}} {{if not (GetAnnotation $f "pfn")}} {{Macro "FunctionDecl" $f}} {{end}} {{end}} ¶ #endif ¶ #ifdef __cplusplus } #endif ¶ #endif {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified bitfield. ------------------------------------------------------------------------------- */}} {{define "Bitfield"}} {{AssertType $ "Enum"}} {{Macro "Docs" $.Docs}} typedef VkFlags {{Macro "EnumName" $}}; {{if $.Entries}} typedef enum { {{range $b := $.Entries}} {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}} {{end}} } {{Macro "EnumName" $ | TrimRight "s"}}Bits; {{end}} ¶ {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified enum. ------------------------------------------------------------------------------- */}} {{define "Enum"}} {{AssertType $ "Enum"}} {{Macro "Docs" $.Docs}} typedef enum { {{range $i, $e := $.Entries}} {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}} {{end}} ¶ {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} {{if GetAnnotation $ "enumMaxOnly"}} VK_MAX_ENUM({{$name | SplitOn "VK_"}}) {{else}} {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}} {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}} VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}}) {{end}} } {{Macro "EnumName" $}}; ¶ {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified class. ------------------------------------------------------------------------------- */}} {{define "Struct"}} {{AssertType $ "Class"}} {{Macro "Docs" $.Docs}} typedef {{Macro "StructType" $}} { {{ForEach $.Fields "Field" | JoinWith "\n"}} } {{Macro "StructName" $}}; ¶ {{end}} {{/* ------------------------------------------------------------------------------- Emits the C declaration for the specified class field. ------------------------------------------------------------------------------- */}} {{define "Field"}} {{AssertType $ "Field"}} {{Node "Type" $}} {{$.Name}}§ {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}} {{end}} {{/* ------------------------------------------------------------------------------- Emits either 'struct' or 'union' for the specified class. ------------------------------------------------------------------------------- */}} {{define "StructType"}} {{AssertType $ "Class"}} {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits the C function pointer typedef declaration for the specified command. ------------------------------------------------------------------------------- */}} {{define "FunctionTypedef"}} {{AssertType $ "Function"}} typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}}); {{end}} {{/* ------------------------------------------------------------------------------- Emits the C function declaration for the specified command. ------------------------------------------------------------------------------- */}} {{define "FunctionDecl"}} {{AssertType $ "Function"}} {{if not (GetAnnotation $ "fptr")}} {{Macro "Docs" $.Docs}} {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); {{end}} {{end}} vulkan/api/vulkan.api0100644 0000000 0000000 00000776433 13077405420 013677 0ustar000000000 0000000 // Copyright (c) 2015 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and/or associated documentation files (the // "Materials"), to deal in the Materials without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Materials, and to // permit persons to whom the Materials are furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Materials. // // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. import platform "platform.api" /////////////// // Constants // /////////////// // API version (major.minor.patch) define VERSION_MAJOR 1 define VERSION_MINOR 0 define VERSION_PATCH 13 // API limits define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 define VK_UUID_SIZE 16 define VK_MAX_EXTENSION_NAME_SIZE 256 define VK_MAX_DESCRIPTION_SIZE 256 define VK_MAX_MEMORY_TYPES 32 define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types. // API keywords define VK_TRUE 1 define VK_FALSE 0 // API keyword, but needs special handling by some templates define NULL_HANDLE 0 @extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION 25 @extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" @extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 @extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" @extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION 21 @extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" @extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 @extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" @extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 @extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME "VK_KHR_xlib_surface" @extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 @extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME "VK_KHR_xcb_surface" @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface" @extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 @extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME "VK_KHR_mir_surface" @extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 @extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface" @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface" @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 5 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer" @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report" @extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1 @extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader" @extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 @extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge" @extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 @extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME "VK_IMG_filter_cubic" @extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 @extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order" @extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3 @extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker" ///////////// // Types // ///////////// type u32 VkBool32 type u32 VkFlags type u64 VkDeviceSize type u32 VkSampleMask /// Dispatchable handle types. @dispatchHandle type u64 VkInstance @dispatchHandle type u64 VkPhysicalDevice @dispatchHandle type u64 VkDevice @dispatchHandle type u64 VkQueue @dispatchHandle type u64 VkCommandBuffer /// Non dispatchable handle types. @nonDispatchHandle type u64 VkDeviceMemory @nonDispatchHandle type u64 VkCommandPool @nonDispatchHandle type u64 VkBuffer @nonDispatchHandle type u64 VkBufferView @nonDispatchHandle type u64 VkImage @nonDispatchHandle type u64 VkImageView @nonDispatchHandle type u64 VkShaderModule @nonDispatchHandle type u64 VkPipeline @nonDispatchHandle type u64 VkPipelineLayout @nonDispatchHandle type u64 VkSampler @nonDispatchHandle type u64 VkDescriptorSet @nonDispatchHandle type u64 VkDescriptorSetLayout @nonDispatchHandle type u64 VkDescriptorPool @nonDispatchHandle type u64 VkFence @nonDispatchHandle type u64 VkSemaphore @nonDispatchHandle type u64 VkEvent @nonDispatchHandle type u64 VkQueryPool @nonDispatchHandle type u64 VkFramebuffer @nonDispatchHandle type u64 VkRenderPass @nonDispatchHandle type u64 VkPipelineCache @extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR @extension("VK_KHR_swapchain") @nonDispatchHandle type u64 VkSwapchainKHR @extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayKHR @extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayModeKHR @extension("VK_EXT_debug_report") @nonDispatchHandle type u64 VkDebugReportCallbackEXT ///////////// // Enums // ///////////// enum VkImageLayout { VK_IMAGE_LAYOUT_UNDEFINED = 0x00000000, /// Implicit layout an image is when its contents are undefined due to various reasons (e.g. right after creation) VK_IMAGE_LAYOUT_GENERAL = 0x00000001, /// General layout when image can be used for any kind of access VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 0x00000002, /// Optimal layout when image is only used for color attachment read/write VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 0x00000003, /// Optimal layout when image is only used for depth/stencil attachment read/write VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 0x00000004, /// Optimal layout when image is used for read only depth/stencil attachment and shader access VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 0x00000005, /// Optimal layout when image is used for read only shader access VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 0x00000006, /// Optimal layout when image is used only as source of transfer operations VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU //@extension("VK_KHR_swapchain") VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, } enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0x00000000, VK_ATTACHMENT_LOAD_OP_CLEAR = 0x00000001, VK_ATTACHMENT_LOAD_OP_DONT_CARE = 0x00000002, } enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0x00000000, VK_ATTACHMENT_STORE_OP_DONT_CARE = 0x00000001, } enum VkImageType { VK_IMAGE_TYPE_1D = 0x00000000, VK_IMAGE_TYPE_2D = 0x00000001, VK_IMAGE_TYPE_3D = 0x00000002, } enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0x00000000, VK_IMAGE_TILING_LINEAR = 0x00000001, } enum VkImageViewType { VK_IMAGE_VIEW_TYPE_1D = 0x00000000, VK_IMAGE_VIEW_TYPE_2D = 0x00000001, VK_IMAGE_VIEW_TYPE_3D = 0x00000002, VK_IMAGE_VIEW_TYPE_CUBE = 0x00000003, VK_IMAGE_VIEW_TYPE_1D_ARRAY = 0x00000004, VK_IMAGE_VIEW_TYPE_2D_ARRAY = 0x00000005, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 0x00000006, } enum VkCommandBufferLevel { VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0x00000000, VK_COMMAND_BUFFER_LEVEL_SECONDARY = 0x00000001, } enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_IDENTITY = 0x00000000, VK_COMPONENT_SWIZZLE_ZERO = 0x00000001, VK_COMPONENT_SWIZZLE_ONE = 0x00000002, VK_COMPONENT_SWIZZLE_R = 0x00000003, VK_COMPONENT_SWIZZLE_G = 0x00000004, VK_COMPONENT_SWIZZLE_B = 0x00000005, VK_COMPONENT_SWIZZLE_A = 0x00000006, } enum VkDescriptorType { VK_DESCRIPTOR_TYPE_SAMPLER = 0x00000000, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 0x00000001, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 0x00000002, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 0x00000003, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 0x00000004, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 0x00000005, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 0x00000006, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 0x00000007, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 0x00000008, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 0x00000009, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 0x0000000a, } enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0x00000000, VK_QUERY_TYPE_PIPELINE_STATISTICS = 0x00000001, /// Optional VK_QUERY_TYPE_TIMESTAMP = 0x00000002, } enum VkBorderColor { VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0x00000000, VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 0x00000001, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 0x00000002, VK_BORDER_COLOR_INT_OPAQUE_BLACK = 0x00000003, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 0x00000004, VK_BORDER_COLOR_INT_OPAQUE_WHITE = 0x00000005, } enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0x00000000, VK_PIPELINE_BIND_POINT_COMPUTE = 0x00000001, } enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0x00000000, VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 0x00000001, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 0x00000002, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 0x00000003, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 0x00000004, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 0x00000005, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 0x00000006, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 0x00000007, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 0x00000008, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 0x00000009, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 0x0000000a, } enum VkSharingMode { VK_SHARING_MODE_EXCLUSIVE = 0x00000000, VK_SHARING_MODE_CONCURRENT = 0x00000001, } enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0x00000000, VK_INDEX_TYPE_UINT32 = 0x00000001, } enum VkFilter { VK_FILTER_NEAREST = 0x00000000, VK_FILTER_LINEAR = 0x00000001, //@extension("VK_IMG_filter_cubic") VK_FILTER_CUBIC_IMG = 1000015000, } enum VkSamplerMipmapMode { VK_SAMPLER_MIPMAP_MODE_NEAREST = 0x00000001, /// Choose nearest mip level VK_SAMPLER_MIPMAP_MODE_LINEAR = 0x00000002, /// Linear filter between mip levels } enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_REPEAT = 0x00000000, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 0x00000001, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 0x00000002, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 0x00000003, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 0x00000004, } enum VkCompareOp { VK_COMPARE_OP_NEVER = 0x00000000, VK_COMPARE_OP_LESS = 0x00000001, VK_COMPARE_OP_EQUAL = 0x00000002, VK_COMPARE_OP_LESS_OR_EQUAL = 0x00000003, VK_COMPARE_OP_GREATER = 0x00000004, VK_COMPARE_OP_NOT_EQUAL = 0x00000005, VK_COMPARE_OP_GREATER_OR_EQUAL = 0x00000006, VK_COMPARE_OP_ALWAYS = 0x00000007, } enum VkPolygonMode { VK_POLYGON_MODE_FILL = 0x00000000, VK_POLYGON_MODE_LINE = 0x00000001, VK_POLYGON_MODE_POINT = 0x00000002, } enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0x00000000, VK_FRONT_FACE_CLOCKWISE = 0x00000001, } enum VkBlendFactor { VK_BLEND_FACTOR_ZERO = 0x00000000, VK_BLEND_FACTOR_ONE = 0x00000001, VK_BLEND_FACTOR_SRC_COLOR = 0x00000002, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 0x00000003, VK_BLEND_FACTOR_DST_COLOR = 0x00000004, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 0x00000005, VK_BLEND_FACTOR_SRC_ALPHA = 0x00000006, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 0x00000007, VK_BLEND_FACTOR_DST_ALPHA = 0x00000008, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 0x00000009, VK_BLEND_FACTOR_CONSTANT_COLOR = 0x0000000a, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 0x0000000b, VK_BLEND_FACTOR_CONSTANT_ALPHA = 0x0000000c, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 0x0000000d, VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 0x0000000e, VK_BLEND_FACTOR_SRC1_COLOR = 0x0000000f, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 0x00000010, VK_BLEND_FACTOR_SRC1_ALPHA = 0x00000011, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 0x00000012, } enum VkBlendOp { VK_BLEND_OP_ADD = 0x00000000, VK_BLEND_OP_SUBTRACT = 0x00000001, VK_BLEND_OP_REVERSE_SUBTRACT = 0x00000002, VK_BLEND_OP_MIN = 0x00000003, VK_BLEND_OP_MAX = 0x00000004, } enum VkStencilOp { VK_STENCIL_OP_KEEP = 0x00000000, VK_STENCIL_OP_ZERO = 0x00000001, VK_STENCIL_OP_REPLACE = 0x00000002, VK_STENCIL_OP_INCREMENT_AND_CLAMP = 0x00000003, VK_STENCIL_OP_DECREMENT_AND_CLAMP = 0x00000004, VK_STENCIL_OP_INVERT = 0x00000005, VK_STENCIL_OP_INCREMENT_AND_WRAP = 0x00000006, VK_STENCIL_OP_DECREMENT_AND_WRAP = 0x00000007, } enum VkLogicOp { VK_LOGIC_OP_CLEAR = 0x00000000, VK_LOGIC_OP_AND = 0x00000001, VK_LOGIC_OP_AND_REVERSE = 0x00000002, VK_LOGIC_OP_COPY = 0x00000003, VK_LOGIC_OP_AND_INVERTED = 0x00000004, VK_LOGIC_OP_NO_OP = 0x00000005, VK_LOGIC_OP_XOR = 0x00000006, VK_LOGIC_OP_OR = 0x00000007, VK_LOGIC_OP_NOR = 0x00000008, VK_LOGIC_OP_EQUIVALENT = 0x00000009, VK_LOGIC_OP_INVERT = 0x0000000a, VK_LOGIC_OP_OR_REVERSE = 0x0000000b, VK_LOGIC_OP_COPY_INVERTED = 0x0000000c, VK_LOGIC_OP_OR_INVERTED = 0x0000000d, VK_LOGIC_OP_NAND = 0x0000000e, VK_LOGIC_OP_SET = 0x0000000f, } enum VkSystemAllocationScope { VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0x00000000, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 0x00000001, VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 0x00000002, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 0x00000003, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 0x00000004, } enum VkInternalAllocationType { VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0x00000000, } enum VkPhysicalDeviceType { VK_PHYSICAL_DEVICE_TYPE_OTHER = 0x00000000, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 0x00000001, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 0x00000002, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 0x00000003, VK_PHYSICAL_DEVICE_TYPE_CPU = 0x00000004, } enum VkVertexInputRate { VK_VERTEX_INPUT_RATE_VERTEX = 0x00000000, VK_VERTEX_INPUT_RATE_INSTANCE = 0x00000001, } /// Vulkan format definitions enum VkFormat { VK_FORMAT_UNDEFINED = 0, VK_FORMAT_R4G4_UNORM_PACK8 = 1, VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, VK_FORMAT_R8_UNORM = 9, VK_FORMAT_R8_SNORM = 10, VK_FORMAT_R8_USCALED = 11, VK_FORMAT_R8_SSCALED = 12, VK_FORMAT_R8_UINT = 13, VK_FORMAT_R8_SINT = 14, VK_FORMAT_R8_SRGB = 15, VK_FORMAT_R8G8_UNORM = 16, VK_FORMAT_R8G8_SNORM = 17, VK_FORMAT_R8G8_USCALED = 18, VK_FORMAT_R8G8_SSCALED = 19, VK_FORMAT_R8G8_UINT = 20, VK_FORMAT_R8G8_SINT = 21, VK_FORMAT_R8G8_SRGB = 22, VK_FORMAT_R8G8B8_UNORM = 23, VK_FORMAT_R8G8B8_SNORM = 24, VK_FORMAT_R8G8B8_USCALED = 25, VK_FORMAT_R8G8B8_SSCALED = 26, VK_FORMAT_R8G8B8_UINT = 27, VK_FORMAT_R8G8B8_SINT = 28, VK_FORMAT_R8G8B8_SRGB = 29, VK_FORMAT_B8G8R8_UNORM = 30, VK_FORMAT_B8G8R8_SNORM = 31, VK_FORMAT_B8G8R8_USCALED = 32, VK_FORMAT_B8G8R8_SSCALED = 33, VK_FORMAT_B8G8R8_UINT = 34, VK_FORMAT_B8G8R8_SINT = 35, VK_FORMAT_B8G8R8_SRGB = 36, VK_FORMAT_R8G8B8A8_UNORM = 37, VK_FORMAT_R8G8B8A8_SNORM = 38, VK_FORMAT_R8G8B8A8_USCALED = 39, VK_FORMAT_R8G8B8A8_SSCALED = 40, VK_FORMAT_R8G8B8A8_UINT = 41, VK_FORMAT_R8G8B8A8_SINT = 42, VK_FORMAT_R8G8B8A8_SRGB = 43, VK_FORMAT_B8G8R8A8_UNORM = 44, VK_FORMAT_B8G8R8A8_SNORM = 45, VK_FORMAT_B8G8R8A8_USCALED = 46, VK_FORMAT_B8G8R8A8_SSCALED = 47, VK_FORMAT_B8G8R8A8_UINT = 48, VK_FORMAT_B8G8R8A8_SINT = 49, VK_FORMAT_B8G8R8A8_SRGB = 50, VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, VK_FORMAT_R16_UNORM = 70, VK_FORMAT_R16_SNORM = 71, VK_FORMAT_R16_USCALED = 72, VK_FORMAT_R16_SSCALED = 73, VK_FORMAT_R16_UINT = 74, VK_FORMAT_R16_SINT = 75, VK_FORMAT_R16_SFLOAT = 76, VK_FORMAT_R16G16_UNORM = 77, VK_FORMAT_R16G16_SNORM = 78, VK_FORMAT_R16G16_USCALED = 79, VK_FORMAT_R16G16_SSCALED = 80, VK_FORMAT_R16G16_UINT = 81, VK_FORMAT_R16G16_SINT = 82, VK_FORMAT_R16G16_SFLOAT = 83, VK_FORMAT_R16G16B16_UNORM = 84, VK_FORMAT_R16G16B16_SNORM = 85, VK_FORMAT_R16G16B16_USCALED = 86, VK_FORMAT_R16G16B16_SSCALED = 87, VK_FORMAT_R16G16B16_UINT = 88, VK_FORMAT_R16G16B16_SINT = 89, VK_FORMAT_R16G16B16_SFLOAT = 90, VK_FORMAT_R16G16B16A16_UNORM = 91, VK_FORMAT_R16G16B16A16_SNORM = 92, VK_FORMAT_R16G16B16A16_USCALED = 93, VK_FORMAT_R16G16B16A16_SSCALED = 94, VK_FORMAT_R16G16B16A16_UINT = 95, VK_FORMAT_R16G16B16A16_SINT = 96, VK_FORMAT_R16G16B16A16_SFLOAT = 97, VK_FORMAT_R32_UINT = 98, VK_FORMAT_R32_SINT = 99, VK_FORMAT_R32_SFLOAT = 100, VK_FORMAT_R32G32_UINT = 101, VK_FORMAT_R32G32_SINT = 102, VK_FORMAT_R32G32_SFLOAT = 103, VK_FORMAT_R32G32B32_UINT = 104, VK_FORMAT_R32G32B32_SINT = 105, VK_FORMAT_R32G32B32_SFLOAT = 106, VK_FORMAT_R32G32B32A32_UINT = 107, VK_FORMAT_R32G32B32A32_SINT = 108, VK_FORMAT_R32G32B32A32_SFLOAT = 109, VK_FORMAT_R64_UINT = 110, VK_FORMAT_R64_SINT = 111, VK_FORMAT_R64_SFLOAT = 112, VK_FORMAT_R64G64_UINT = 113, VK_FORMAT_R64G64_SINT = 114, VK_FORMAT_R64G64_SFLOAT = 115, VK_FORMAT_R64G64B64_UINT = 116, VK_FORMAT_R64G64B64_SINT = 117, VK_FORMAT_R64G64B64_SFLOAT = 118, VK_FORMAT_R64G64B64A64_UINT = 119, VK_FORMAT_R64G64B64A64_SINT = 120, VK_FORMAT_R64G64B64A64_SFLOAT = 121, VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, VK_FORMAT_D16_UNORM = 124, VK_FORMAT_X8_D24_UNORM_PACK32 = 125, VK_FORMAT_D32_SFLOAT = 126, VK_FORMAT_S8_UINT = 127, VK_FORMAT_D16_UNORM_S8_UINT = 128, VK_FORMAT_D24_UNORM_S8_UINT = 129, VK_FORMAT_D32_SFLOAT_S8_UINT = 130, VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, VK_FORMAT_BC2_UNORM_BLOCK = 135, VK_FORMAT_BC2_SRGB_BLOCK = 136, VK_FORMAT_BC3_UNORM_BLOCK = 137, VK_FORMAT_BC3_SRGB_BLOCK = 138, VK_FORMAT_BC4_UNORM_BLOCK = 139, VK_FORMAT_BC4_SNORM_BLOCK = 140, VK_FORMAT_BC5_UNORM_BLOCK = 141, VK_FORMAT_BC5_SNORM_BLOCK = 142, VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, VK_FORMAT_BC7_UNORM_BLOCK = 145, VK_FORMAT_BC7_SRGB_BLOCK = 146, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, } /// Structure type enumerant enum VkStructureType { VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, //@extension("VK_KHR_swapchain") VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, //@extension("VK_KHR_display") VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, //@extension("VK_KHR_display_swapchain") VK_STRUCTURE_TYPE_DISPLAY_DISPLAY_PRESENT_INFO_KHR = 1000003000, //@extension("VK_KHR_xlib_surface") VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, //@extension("VK_KHR_xcb_surface") VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, //@extension("VK_KHR_wayland_surface") VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, //@extension("VK_KHR_mir_surface") VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, //@extension("VK_KHR_android_surface") VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, //@extension("VK_KHR_win32_surface") VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, //@extension("VK_ANDROID_native_buffer") VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID = 1000010000, //@extension("VK_EXT_debug_report") VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, //@extension("VK_AMD_rasterization_order") VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, //@extension("VK_EXT_debug_marker") VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, //@extension("VK_EXT_debug_marker") VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, //@extension("VK_EXT_debug_marker") VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, } enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0x00000000, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 0x00000001, } enum VkPipelineCacheHeaderVersion { VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, } @lastUnused(-11) /// Error and return codes enum VkResult { // Return codes for successful operation execution (positive values) VK_SUCCESS = 0, VK_NOT_READY = 1, VK_TIMEOUT = 2, VK_EVENT_SET = 3, VK_EVENT_RESET = 4, VK_INCOMPLETE = 5, //@extension("VK_KHR_swapchain") VK_SUBOPTIMAL_KHR = 1000001003, // Error codes (negative values) VK_ERROR_OUT_OF_HOST_MEMORY = 0xFFFFFFFF, // -1 VK_ERROR_OUT_OF_DEVICE_MEMORY = 0xFFFFFFFE, // -2 VK_ERROR_INITIALIZATION_FAILED = 0xFFFFFFFD, // -3 VK_ERROR_DEVICE_LOST = 0xFFFFFFFC, // -4 VK_ERROR_MEMORY_MAP_FAILED = 0xFFFFFFFB, // -5 VK_ERROR_LAYER_NOT_PRESENT = 0xFFFFFFFA, // -6 VK_ERROR_EXTENSION_NOT_PRESENT = 0xFFFFFFF9, // -7 VK_ERROR_FEATURE_NOT_PRESENT = 0xFFFFFFF8, // -8 VK_ERROR_INCOMPATIBLE_DRIVER = 0xFFFFFFF7, // -9 VK_ERROR_TOO_MANY_OBJECTS = 0xFFFFFFF6, // -10 VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11 //@extension("VK_KHR_surface") VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000 //@extension("VK_KHR_surface") VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000008001 //@extension("VK_KHR_swapchain") VK_ERROR_OUT_OF_DATE_KHR = 0xC4653214, // -1000001004 //@extension("VK_KHR_display_swapchain") VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = 0xC4652A47, // -1000003001 //@extension("VK_EXT_debug_report") VK_ERROR_VALIDATION_FAILED_EXT = 0xC4650B07, // -1000011001 //@extension("VK_NV_glsl_shader") VK_ERROR_INVALID_SHADER_NV = 0xC4650720, // -1000012000 } enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT = 0x00000000, VK_DYNAMIC_STATE_SCISSOR = 0x00000001, VK_DYNAMIC_STATE_LINE_WIDTH = 0x00000002, VK_DYNAMIC_STATE_DEPTH_BIAS = 0x00000003, VK_DYNAMIC_STATE_BLEND_CONSTANTS = 0x00000004, VK_DYNAMIC_STATE_DEPTH_BOUNDS = 0x00000005, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 0x00000006, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 0x00000007, VK_DYNAMIC_STATE_STENCIL_REFERENCE = 0x00000008, } @extension("VK_KHR_surface") enum VkPresentModeKHR { VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000, VK_PRESENT_MODE_MAILBOX_KHR = 0x00000001, VK_PRESENT_MODE_FIFO_KHR = 0x00000002, VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003, } @extension("VK_KHR_surface") enum VkColorSpaceKHR { VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000, } @extension("VK_EXT_debug_report") enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, } @extension("VK_EXT_debug_report") enum VkDebugReportErrorEXT { VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, } @extension("VK_AMD_rasterization_order") enum VkRasterizationOrderAMD { VK_RASTERIZATION_ORDER_STRICT_AMD = 0, VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, } ///////////////// // Bitfields // ///////////////// /// Queue capabilities type VkFlags VkQueueFlags bitfield VkQueueFlagBits { VK_QUEUE_GRAPHICS_BIT = 0x00000001, /// Queue supports graphics operations VK_QUEUE_COMPUTE_BIT = 0x00000002, /// Queue supports compute operations VK_QUEUE_TRANSFER_BIT = 0x00000004, /// Queue supports transfer operations VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, /// Queue supports sparse resource memory management operations } /// Memory properties passed into vkAllocMemory(). type VkFlags VkMemoryPropertyFlags bitfield VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, } /// Memory heap flags type VkFlags VkMemoryHeapFlags bitfield VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, } /// Access flags type VkFlags VkAccessFlags bitfield VkAccessFlagBits { VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, VK_ACCESS_INDEX_READ_BIT = 0x00000002, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, VK_ACCESS_SHADER_READ_BIT = 0x00000020, VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, VK_ACCESS_HOST_READ_BIT = 0x00002000, VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, } /// Buffer usage flags type VkFlags VkBufferUsageFlags bitfield VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, /// Can be used as TBO VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, /// Can be used as IBO VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, /// Can be used as UBO VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, /// Can be used as SSBO VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, /// Can be used as source of fixed function index fetch (index buffer) VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, /// Can be used as source of fixed function vertex fetch (VBO) VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, /// Can be the source of indirect parameters (e.g. indirect buffer, parameter buffer) } /// Buffer creation flags type VkFlags VkBufferCreateFlags bitfield VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Buffer should support sparse backing VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Buffer should support sparse backing with partial residency VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers } /// Shader stage flags type VkFlags VkShaderStageFlags bitfield VkShaderStageFlagBits { VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, } /// Descriptor pool create flags type VkFlags VkDescriptorPoolCreateFlags bitfield VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, } /// Descriptor pool reset flags type VkFlags VkDescriptorPoolResetFlags //bitfield VkDescriptorPoolResetFlagBits { //} /// Image usage flags type VkFlags VkImageUsageFlags bitfield VkImageUsageFlagBits { VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, /// Can be sampled from (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types) VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, /// Can be used as storage image (STORAGE_IMAGE descriptor type) VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, /// Can be used as framebuffer color attachment VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, /// Can be used as framebuffer depth/stencil attachment VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, /// Image data not needed outside of rendering VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, /// Can be used as framebuffer input attachment } /// Image creation flags type VkFlags VkImageCreateFlags bitfield VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Image should support sparse backing VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Image should support sparse backing with partial residency VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Image should support constent data access to physical memory blocks mapped into multiple locations of sparse images VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image } /// Image view creation flags type VkFlags VkImageViewCreateFlags //bitfield VkImageViewCreateFlagBits { //} /// Pipeline creation flags type VkFlags VkPipelineCreateFlags bitfield VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, } /// Color component flags type VkFlags VkColorComponentFlags bitfield VkColorComponentFlagBits { VK_COLOR_COMPONENT_R_BIT = 0x00000001, VK_COLOR_COMPONENT_G_BIT = 0x00000002, VK_COLOR_COMPONENT_B_BIT = 0x00000004, VK_COLOR_COMPONENT_A_BIT = 0x00000008, } /// Fence creation flags type VkFlags VkFenceCreateFlags bitfield VkFenceCreateFlagBits { VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, } /// Semaphore creation flags type VkFlags VkSemaphoreCreateFlags //bitfield VkSemaphoreCreateFlagBits { //} /// Format capability flags type VkFlags VkFormatFeatureFlags bitfield VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, /// Format can be used for sampled images (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types) VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, /// Format can be used for storage images (STORAGE_IMAGE descriptor type) VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, /// Format supports atomic operations in case it's used for storage images VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, /// Format can be used for uniform texel buffers (TBOs) VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, /// Format can be used for storage texel buffers (IBOs) VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, /// Format supports atomic operations in case it's used for storage texel buffers VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, /// Format can be used for vertex buffers (VBOs) VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, /// Format can be used for color attachment images VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, /// Format supports blending in case it's used for color attachment images VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, /// Format can be used for depth/stencil attachment images VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, /// Format can be used as the source image of blits with vkCommandBlitImage VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, //@extension("VK_IMG_filter_cubic") VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, } /// Query control flags type VkFlags VkQueryControlFlags bitfield VkQueryControlFlagBits { VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, } /// Query result flags type VkFlags VkQueryResultFlags bitfield VkQueryResultFlagBits { VK_QUERY_RESULT_64_BIT = 0x00000001, /// Results of the queries are written to the destination buffer as 64-bit values VK_QUERY_RESULT_WAIT_BIT = 0x00000002, /// Results of the queries are waited on before proceeding with the result copy VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, /// Besides the results of the query, the availability of the results is also written VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, /// Copy the partial results of the query even if the final results aren't available } /// Shader module creation flags type VkFlags VkShaderModuleCreateFlags //bitfield VkShaderModuleCreateFlagBits { //} /// Event creation flags type VkFlags VkEventCreateFlags //bitfield VkEventCreateFlagBits { //} /// Command buffer usage flags type VkFlags VkCommandBufferUsageFlags bitfield VkCommandBufferUsageFlagBits { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, } /// Pipeline statistics flags type VkFlags VkQueryPipelineStatisticFlags bitfield VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, /// Optional VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, /// Optional VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, /// Optional VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, /// Optional VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, /// Optional VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, /// Optional VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, /// Optional VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, /// Optional VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, /// Optional VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, /// Optional VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, /// Optional } /// Memory mapping flags type VkFlags VkMemoryMapFlags //bitfield VkMemoryMapFlagBits { //} /// Bitfield of image aspects type VkFlags VkImageAspectFlags bitfield VkImageAspectFlagBits { VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, } /// Sparse memory bind flags type VkFlags VkSparseMemoryBindFlags bitfield VkSparseMemoryBindFlagBits { VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, } /// Sparse image memory requirements flags type VkFlags VkSparseImageFormatFlags bitfield VkSparseImageFormatFlagBits { VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, /// Image uses a single miptail region for all array slices VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, /// Image requires mip levels to be an exact multiple of the sparse iamge block size for non-mip-tail levels. VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, /// Image uses a non-standard sparse block size } /// Pipeline stages type VkFlags VkPipelineStageFlags bitfield VkPipelineStageFlagBits { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, /// Before subsequent commands are processed VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, /// Draw/DispatchIndirect command fetch VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, /// Vertex/index fetch VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, /// Vertex shading VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, /// Tessellation control shading VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, /// Tessellation evaluation shading VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, /// Geometry shading VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, /// Fragment shading VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, /// Early fragment (depth/stencil) tests VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, /// Late fragment (depth/stencil) tests VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, /// Color attachment writes VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, /// Compute shading VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, /// Transfer/copy operations VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, /// Indicates host (CPU) is a source/sink of the dependency VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, /// All stages of the graphics pipeline VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, /// All graphics, compute, copy, and transition commands } /// Render pass attachment description flags type VkFlags VkAttachmentDescriptionFlags bitfield VkAttachmentDescriptionFlagBits { VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, /// The attachment may alias physical memory of another attachment in the same renderpass } /// Subpass description flags type VkFlags VkSubpassDescriptionFlags bitfield VkSubpassDescriptionFlagBits { } /// Command pool creation flags type VkFlags VkCommandPoolCreateFlags bitfield VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, /// Command buffers have a short lifetime VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, /// Command buffers may release their memory individually } /// Command pool reset flags type VkFlags VkCommandPoolResetFlags bitfield VkCommandPoolResetFlagBits { VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the pool } type VkFlags VkCommandBufferResetFlags bitfield VkCommandBufferResetFlagBits { VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the buffer } type VkFlags VkSampleCountFlags bitfield VkSampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT = 0x00000001, VK_SAMPLE_COUNT_2_BIT = 0x00000002, VK_SAMPLE_COUNT_4_BIT = 0x00000004, VK_SAMPLE_COUNT_8_BIT = 0x00000008, VK_SAMPLE_COUNT_16_BIT = 0x00000010, VK_SAMPLE_COUNT_32_BIT = 0x00000020, VK_SAMPLE_COUNT_64_BIT = 0x00000040, } type VkFlags VkStencilFaceFlags bitfield VkStencilFaceFlagBits { VK_STENCIL_FACE_FRONT_BIT = 0x00000001, /// Front face VK_STENCIL_FACE_BACK_BIT = 0x00000002, /// Back face VK_STENCIL_FRONT_AND_BACK = 0x00000003, } /// Instance creation flags type VkFlags VkInstanceCreateFlags //bitfield VkInstanceCreateFlagBits { //} /// Device creation flags type VkFlags VkDeviceCreateFlags //bitfield VkDeviceCreateFlagBits { //} /// Device queue creation flags type VkFlags VkDeviceQueueCreateFlags //bitfield VkDeviceQueueCreateFlagBits { //} /// Query pool creation flags type VkFlags VkQueryPoolCreateFlags //bitfield VkQueryPoolCreateFlagBits { //} /// Buffer view creation flags type VkFlags VkBufferViewCreateFlags //bitfield VkBufferViewCreateFlagBits { //} /// Pipeline cache creation flags type VkFlags VkPipelineCacheCreateFlags //bitfield VkPipelineCacheCreateFlagBits { //} /// Pipeline shader stage creation flags type VkFlags VkPipelineShaderStageCreateFlags //bitfield VkPipelineShaderStageCreateFlagBits { //} /// Descriptor set layout creation flags type VkFlags VkDescriptorSetLayoutCreateFlags //bitfield VkDescriptorSetLayoutCreateFlagBits { //} /// Pipeline vertex input state creation flags type VkFlags VkPipelineVertexInputStateCreateFlags //bitfield VkPipelineVertexInputStateCreateFlagBits { //} /// Pipeline input assembly state creation flags type VkFlags VkPipelineInputAssemblyStateCreateFlags //bitfield VkPipelineInputAssemblyStateCreateFlagBits { //} /// Tessellation state creation flags type VkFlags VkPipelineTessellationStateCreateFlags //bitfield VkPipelineTessellationStateCreateFlagBits { //} /// Viewport state creation flags type VkFlags VkPipelineViewportStateCreateFlags //bitfield VkPipelineViewportStateCreateFlagBits { //} /// Rasterization state creation flags type VkFlags VkPipelineRasterizationStateCreateFlags //bitfield VkPipelineRasterizationStateCreateFlagBits { //} /// Multisample state creation flags type VkFlags VkPipelineMultisampleStateCreateFlags //bitfield VkPipelineMultisampleStateCreateFlagBits { //} /// Color blend state creation flags type VkFlags VkPipelineColorBlendStateCreateFlags //bitfield VkPipelineColorBlendStateCreateFlagBits { //} /// Depth/stencil state creation flags type VkFlags VkPipelineDepthStencilStateCreateFlags //bitfield VkPipelineDepthStencilStateCreateFlagBits { //} /// Dynamic state creation flags type VkFlags VkPipelineDynamicStateCreateFlags //bitfield VkPipelineDynamicStateCreateFlagBits { //} /// Pipeline layout creation flags type VkFlags VkPipelineLayoutCreateFlags //bitfield VkPipelineLayoutCreateFlagBits { //} /// Sampler creation flags type VkFlags VkSamplerCreateFlags //bitfield VkSamplerCreateFlagBits { //} /// Render pass creation flags type VkFlags VkRenderPassCreateFlags //bitfield VkRenderPassCreateFlagBits { //} /// Framebuffer creation flags type VkFlags VkFramebufferCreateFlags //bitfield VkFramebufferCreateFlagBits { //} /// Dependency flags type VkFlags VkDependencyFlags bitfield VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, } /// Cull mode flags type VkFlags VkCullModeFlags bitfield VkCullModeFlagBits { VK_CULL_MODE_NONE = 0x00000000, VK_CULL_MODE_FRONT_BIT = 0x00000001, VK_CULL_MODE_BACK_BIT = 0x00000002, VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, } @extension("VK_KHR_surface") type VkFlags VkSurfaceTransformFlagsKHR @extension("VK_KHR_surface") bitfield VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, } @extension("VK_KHR_surface") type VkFlags VkCompositeAlphaFlagsKHR @extension("VK_KHR_surface") bitfield VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, } @extension("VK_KHR_swapchain") type VkFlags VkSwapchainCreateFlagsKHR //@extension("VK_KHR_swapchain") //bitfield VkSwapchainCreateFlagBitsKHR { //} @extension("VK_KHR_display") type VkFlags VkDisplayPlaneAlphaFlagsKHR @extension("VK_KHR_display") bitfield VkDisplayPlaneAlphaFlagBitsKHR { VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, } @extension("VK_KHR_display") type VkFlags VkDisplaySurfaceCreateFlagsKHR //@extension("VK_KHR_display") //bitfield VkDisplaySurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_display") type VkFlags VkDisplayModeCreateFlagsKHR //@extension("VK_KHR_display") //bitfield VkDisplayModeCreateFlagBitsKHR { //} @extension("VK_KHR_xlib_surface") type VkFlags VkXlibSurfaceCreateFlagsKHR //@extension("VK_KHR_xlib_surface") //bitfield VkXlibSurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_xcb_surface") type VkFlags VkXcbSurfaceCreateFlagsKHR //@extension("VK_KHR_xcb_surface") //bitfield VkXcbSurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_wayland_surface") type VkFlags VkWaylandSurfaceCreateFlagsKHR //@extension("VK_KHR_wayland_surface") //bitfield VkWaylandSurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_mir_surface") type VkFlags VkMirSurfaceCreateFlagsKHR //@extension("VK_KHR_mir_surface") //bitfield VkMirSurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_android_surface") type VkFlags VkAndroidSurfaceCreateFlagsKHR //@extension("VK_KHR_android_surface") //bitfield VkAndroidSurfaceCreateFlagBitsKHR { //} @extension("VK_KHR_win32_surface") type VkFlags VkWin32SurfaceCreateFlagsKHR //@extension("VK_KHR_win32_surface") //bitfield VkWin32SurfaceCreateFlagBitsKHR { //} @extension("VK_EXT_debug_report") type VkFlags VkDebugReportFlagsEXT @extension("VK_EXT_debug_report") bitfield VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, } ////////////////// // Structures // ////////////////// class VkOffset2D { s32 x s32 y } class VkOffset3D { s32 x s32 y s32 z } class VkExtent2D { u32 width u32 height } class VkExtent3D { u32 width u32 height u32 depth } class VkViewport { f32 x f32 y f32 width f32 height f32 minDepth f32 maxDepth } class VkRect2D { VkOffset2D offset VkExtent2D extent } class VkClearRect { VkRect2D rect u32 baseArrayLayer u32 layerCount } class VkComponentMapping { VkComponentSwizzle r VkComponentSwizzle g VkComponentSwizzle b VkComponentSwizzle a } class VkPhysicalDeviceProperties { u32 apiVersion u32 driverVersion u32 vendorID u32 deviceID VkPhysicalDeviceType deviceType char[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] deviceName u8[VK_UUID_SIZE] pipelineCacheUUID VkPhysicalDeviceLimits limits VkPhysicalDeviceSparseProperties sparseProperties } class VkExtensionProperties { char[VK_MAX_EXTENSION_NAME_SIZE] extensionName /// extension name u32 specVersion /// version of the extension specification implemented } class VkLayerProperties { char[VK_MAX_EXTENSION_NAME_SIZE] layerName /// layer name u32 specVersion /// version of the layer specification implemented u32 implementationVersion /// build or release version of the layer's library char[VK_MAX_DESCRIPTION_SIZE] description /// Free-form description of the layer } class VkSubmitInfo { VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_SUBMIT_INFO const void* pNext /// Next structure in chain u32 waitSemaphoreCount const VkSemaphore* pWaitSemaphores const VkPipelineStageFlags* pWaitDstStageMask u32 commandBufferCount const VkCommandBuffer* pCommandBuffers u32 signalSemaphoreCount const VkSemaphore* pSignalSemaphores } class VkApplicationInfo { VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_APPLICATION_INFO const void* pNext /// Next structure in chain const char* pApplicationName u32 applicationVersion const char* pEngineName u32 engineVersion u32 apiVersion } class VkAllocationCallbacks { void* pUserData PFN_vkAllocationFunction pfnAllocation PFN_vkReallocationFunction pfnReallocation PFN_vkFreeFunction pfnFree PFN_vkInternalAllocationNotification pfnInternalAllocation PFN_vkInternalFreeNotification pfnInternalFree } class VkDeviceQueueCreateInfo { VkStructureType sStype /// Should be VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO const void* pNext /// Pointer to next structure VkDeviceQueueCreateFlags flags u32 queueFamilyIndex u32 queueCount const f32* pQueuePriorities } class VkDeviceCreateInfo { VkStructureType sType /// Should be VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO const void* pNext /// Pointer to next structure VkDeviceCreateFlags flags u32 queueCreateInfoCount const VkDeviceQueueCreateInfo* pQueueCreateInfos u32 enabledLayerCount const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled u32 enabledExtensionCount const char* const* ppEnabledExtensionNames const VkPhysicalDeviceFeatures* pEnabledFeatures } class VkInstanceCreateInfo { VkStructureType sType /// Should be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO const void* pNext /// Pointer to next structure VkInstanceCreateFlags flags const VkApplicationInfo* pApplicationInfo u32 enabledLayerCount const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled u32 enabledExtensionCount const char* const* ppEnabledExtensionNames /// Extension names to be enabled } class VkQueueFamilyProperties { VkQueueFlags queueFlags /// Queue flags u32 queueCount u32 timestampValidBits VkExtent3D minImageTransferGranularity } class VkPhysicalDeviceMemoryProperties { u32 memoryTypeCount VkMemoryType[VK_MAX_MEMORY_TYPES] memoryTypes u32 memoryHeapCount VkMemoryHeap[VK_MAX_MEMORY_HEAPS] memoryHeaps } class VkMemoryAllocateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO const void* pNext /// Pointer to next structure VkDeviceSize allocationSize /// Size of memory allocation u32 memoryTypeIndex /// Index of the of the memory type to allocate from } class VkMemoryRequirements { VkDeviceSize size /// Specified in bytes VkDeviceSize alignment /// Specified in bytes u32 memoryTypeBits /// Bitfield of the allowed memory type indices into memoryTypes[] for this object } class VkSparseImageFormatProperties { VkImageAspectFlagBits aspectMask VkExtent3D imageGranularity VkSparseImageFormatFlags flags } class VkSparseImageMemoryRequirements { VkSparseImageFormatProperties formatProperties u32 imageMipTailFirstLod VkDeviceSize imageMipTailSize /// Specified in bytes, must be a multiple of image block size / alignment VkDeviceSize imageMipTailOffset /// Specified in bytes, must be a multiple of image block size / alignment VkDeviceSize imageMipTailStride /// Specified in bytes, must be a multiple of image block size / alignment } class VkMemoryType { VkMemoryPropertyFlags propertyFlags /// Memory properties of this memory type u32 heapIndex /// Index of the memory heap allocations of this memory type are taken from } class VkMemoryHeap { VkDeviceSize size /// Available memory in the heap VkMemoryHeapFlags flags /// Flags for the heap } class VkMappedMemoryRange { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE const void* pNext /// Pointer to next structure VkDeviceMemory memory /// Mapped memory object VkDeviceSize offset /// Offset within the mapped memory the range starts from VkDeviceSize size /// Size of the range within the mapped memory } class VkFormatProperties { VkFormatFeatureFlags linearTilingFeatures /// Format features in case of linear tiling VkFormatFeatureFlags optimalTilingFeatures /// Format features in case of optimal tiling VkFormatFeatureFlags bufferFeatures /// Format features supported by buffers } class VkImageFormatProperties { VkExtent3D maxExtent /// max image dimensions for this resource type u32 maxMipLevels /// max number of mipmap levels for this resource type u32 maxArrayLayers /// max array layers for this resource type VkSampleCountFlags sampleCounts /// supported sample counts for this resource type VkDeviceSize maxResourceSize /// max size (in bytes) of this resource type } class VkDescriptorImageInfo { VkSampler sampler VkImageView imageView VkImageLayout imageLayout } class VkDescriptorBufferInfo { VkBuffer buffer /// Buffer used for this descriptor when the descriptor is UNIFORM_BUFFER[_DYNAMIC] VkDeviceSize offset /// Base offset from buffer start in bytes to update in the descriptor set. VkDeviceSize range /// Size in bytes of the buffer resource for this descriptor update. } class VkWriteDescriptorSet { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET const void* pNext /// Pointer to next structure VkDescriptorSet dstSet /// Destination descriptor set u32 dstBinding /// Binding within the destination descriptor set to write u32 dstArrayElement /// Array element within the destination binding to write u32 descriptorCount /// Number of descriptors to write (determines the size of the array pointed by ) VkDescriptorType descriptorType /// Descriptor type to write (determines which fields of the array pointed by are going to be used) const VkDescriptorImageInfo* pImageInfo const VkDescriptorBufferInfo* pBufferInfo const VkBufferView* pTexelBufferView } class VkCopyDescriptorSet { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET const void* pNext /// Pointer to next structure VkDescriptorSet srcSet /// Source descriptor set u32 srcBinding /// Binding within the source descriptor set to copy from u32 srcArrayElement /// Array element within the source binding to copy from VkDescriptorSet dstSet /// Destination descriptor set u32 dstBinding /// Binding within the destination descriptor set to copy to u32 dstArrayElement /// Array element within the destination binding to copy to u32 descriptorCount /// Number of descriptors to copy } class VkBufferCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO const void* pNext /// Pointer to next structure. VkBufferCreateFlags flags /// Buffer creation flags VkDeviceSize size /// Specified in bytes VkBufferUsageFlags usage /// Buffer usage flags VkSharingMode sharingMode u32 queueFamilyIndexCount const u32* pQueueFamilyIndices } class VkBufferViewCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO const void* pNext /// Pointer to next structure. VkBufferViewCreateFlags flags VkBuffer buffer VkFormat format /// Optionally specifies format of elements VkDeviceSize offset /// Specified in bytes VkDeviceSize range /// View size specified in bytes } class VkImageSubresource { VkImageAspectFlagBits aspectMask u32 mipLevel u32 arrayLayer } class VkImageSubresourceRange { VkImageAspectFlags aspectMask u32 baseMipLevel u32 levelCount u32 baseArrayLayer u32 layerCount } class VkMemoryBarrier { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_BARRIER const void* pNext /// Pointer to next structure. VkAccessFlags srcAccessMask VkAccessFlags dstAccessMask } class VkBufferMemoryBarrier { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER const void* pNext /// Pointer to next structure. VkAccessFlags srcAccessMask VkAccessFlags dstAccessMask u32 srcQueueFamilyIndex /// Queue family to transition ownership from u32 dstQueueFamilyIndex /// Queue family to transition ownership to VkBuffer buffer /// Buffer to sync VkDeviceSize offset /// Offset within the buffer to sync VkDeviceSize size /// Amount of bytes to sync } class VkImageMemoryBarrier { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER const void* pNext /// Pointer to next structure. VkAccessFlags srcAccessMask VkAccessFlags dstAccessMask VkImageLayout oldLayout /// Current layout of the image VkImageLayout newLayout /// New layout to transition the image to u32 srcQueueFamilyIndex /// Queue family to transition ownership from u32 dstQueueFamilyIndex /// Queue family to transition ownership to VkImage image /// Image to sync VkImageSubresourceRange subresourceRange /// Subresource range to sync } class VkImageCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO const void* pNext /// Pointer to next structure. VkImageCreateFlags flags /// Image creation flags VkImageType imageType VkFormat format VkExtent3D extent u32 mipLevels u32 arrayLayers VkSampleCountFlagBits samples VkImageTiling tiling VkImageUsageFlags usage /// Image usage flags VkSharingMode sharingMode /// Cross-queue-family sharing mode u32 queueFamilyIndexCount /// Number of queue families to share across const u32* pQueueFamilyIndices /// Array of queue family indices to share across VkImageLayout initialLayout /// Initial image layout for all subresources } class VkSubresourceLayout { VkDeviceSize offset /// Specified in bytes VkDeviceSize size /// Specified in bytes VkDeviceSize rowPitch /// Specified in bytes VkDeviceSize arrayPitch /// Specified in bytes VkDeviceSize depthPitch /// Specified in bytes } class VkImageViewCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO const void* pNext /// Pointer to next structure VkImageViewCreateFlags flags VkImage image VkImageViewType viewType VkFormat format VkComponentMapping components VkImageSubresourceRange subresourceRange } class VkBufferCopy { VkDeviceSize srcOffset /// Specified in bytes VkDeviceSize dstOffset /// Specified in bytes VkDeviceSize size /// Specified in bytes } class VkSparseMemoryBind { VkDeviceSize resourceOffset /// Specified in bytes VkDeviceSize size /// Specified in bytes VkDeviceMemory memory VkDeviceSize memoryOffset /// Specified in bytes VkSparseMemoryBindFlags flags } class VkSparseImageMemoryBind { VkImageSubresource subresource VkOffset3D offset VkExtent3D extent VkDeviceMemory memory VkDeviceSize memoryOffset /// Specified in bytes VkSparseMemoryBindFlags flags } class VkSparseBufferMemoryBindInfo { VkBuffer buffer u32 bindCount const VkSparseMemoryBind* pBinds } class VkSparseImageOpaqueMemoryBindInfo { VkImage image u32 bindCount const VkSparseMemoryBind* pBinds } class VkSparseImageMemoryBindInfo { VkImage image u32 bindCount const VkSparseMemoryBind* pBinds } class VkBindSparseInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BIND_SPARSE_INFO const void* pNext u32 waitSemaphoreCount const VkSemaphore* pWaitSemaphores u32 numBufferBinds const VkSparseBufferMemoryBindInfo* pBufferBinds u32 numImageOpaqueBinds const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds u32 numImageBinds const VkSparseImageMemoryBindInfo* pImageBinds u32 signalSemaphoreCount const VkSemaphore* pSignalSemaphores } class VkImageSubresourceLayers { VkImageAspectFlags aspectMask u32 mipLevel u32 baseArrayLayer u32 layerCount } class VkImageCopy { VkImageSubresourceLayers srcSubresource VkOffset3D srcOffset /// Specified in pixels for both compressed and uncompressed images VkImageSubresourceLayers dstSubresource VkOffset3D dstOffset /// Specified in pixels for both compressed and uncompressed images VkExtent3D extent /// Specified in pixels for both compressed and uncompressed images } class VkImageBlit { VkImageSubresourceLayers srcSubresource VkOffset3D[2] srcOffsets VkImageSubresourceLayers dstSubresource VkOffset3D[2] dstOffsets } class VkBufferImageCopy { VkDeviceSize bufferOffset /// Specified in bytes u32 bufferRowLength /// Specified in texels u32 bufferImageHeight VkImageSubresourceLayers imageSubresource VkOffset3D imageOffset /// Specified in pixels for both compressed and uncompressed images VkExtent3D imageExtent /// Specified in pixels for both compressed and uncompressed images } class VkImageResolve { VkImageSubresourceLayers srcSubresource VkOffset3D srcOffset VkImageSubresourceLayers dstSubresource VkOffset3D dstOffset VkExtent3D extent } class VkShaderModuleCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO const void* pNext /// Pointer to next structure VkShaderModuleCreateFlags flags /// Reserved platform.size_t codeSize /// Specified in bytes const u32* pCode /// Binary code of size codeSize } class VkDescriptorSetLayoutBinding { u32 binding VkDescriptorType descriptorType /// Type of the descriptors in this binding u32 descriptorCount /// Number of descriptors in this binding VkShaderStageFlags stageFlags /// Shader stages this binding is visible to const VkSampler* pImmutableSamplers /// Immutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains number of elements) } class VkDescriptorSetLayoutCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO const void* pNext /// Pointer to next structure VkDescriptorSetLayoutCreateFlags flags u32 bindingCount /// Number of bindings in the descriptor set layout const VkDescriptorSetLayoutBinding* pBindings /// Array of descriptor set layout bindings } class VkDescriptorPoolSize { VkDescriptorType type u32 descriptorCount } class VkDescriptorPoolCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO const void* pNext /// Pointer to next structure VkDescriptorPoolCreateFlags flags u32 maxSets u32 poolSizeCount const VkDescriptorPoolSize* pPoolSizes } class VkDescriptorSetAllocateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO const void* pNext /// Pointer to next structure VkDescriptorPool descriptorPool u32 setCount const VkDescriptorSetLayout* pSetLayouts } class VkSpecializationMapEntry { u32 constantID /// The SpecConstant ID specified in the BIL u32 offset /// Offset of the value in the data block platform.size_t size /// Size in bytes of the SpecConstant } class VkSpecializationInfo { u32 mapEntryCount /// Number of entries in the map const VkSpecializationMapEntry* pMapEntries /// Array of map entries platform.size_t dataSize /// Size in bytes of pData const void* pData /// Pointer to SpecConstant data } class VkPipelineShaderStageCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineShaderStageCreateFlags flags VkShaderStageFlagBits stage VkShaderModule module const char* pName const VkSpecializationInfo* pSpecializationInfo } class VkComputePipelineCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineCreateFlags flags /// Pipeline creation flags VkPipelineShaderStageCreateInfo stage VkPipelineLayout layout /// Interface layout of the pipeline VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of } class VkVertexInputBindingDescription { u32 binding /// Vertex buffer binding id u32 stride /// Distance between vertices in bytes (0 = no advancement) VkVertexInputRate inputRate /// Rate at which binding is incremented } class VkVertexInputAttributeDescription { u32 location /// location of the shader vertex attrib u32 binding /// Vertex buffer binding id VkFormat format /// format of source data u32 offset /// Offset of first element in bytes from base of vertex } class VkPipelineVertexInputStateCreateInfo { VkStructureType sType /// Should be VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineVertexInputStateCreateFlags flags u32 vertexBindingDescriptionCount /// number of bindings const VkVertexInputBindingDescription* pVertexBindingDescriptions u32 vertexAttributeDescriptionCount /// number of attributes const VkVertexInputAttributeDescription* pVertexAttributeDescriptions } class VkPipelineInputAssemblyStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineInputAssemblyStateCreateFlags flags VkPrimitiveTopology topology VkBool32 primitiveRestartEnable } class VkPipelineTessellationStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineTessellationStateCreateFlags flags u32 patchControlPoints } class VkPipelineViewportStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineViewportStateCreateFlags flags u32 viewportCount const VkViewport* pViewports u32 scissorCount const VkRect2D* pScissors } class VkPipelineRasterizationStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineRasterizationStateCreateFlags flags VkBool32 depthClampEnable VkBool32 rasterizerDiscardEnable VkPolygonMode polygonMode /// optional (GL45) VkCullModeFlags cullMode VkFrontFace frontFace VkBool32 depthBiasEnable f32 depthBiasConstantFactor f32 depthBiasClamp f32 depthBiasSlopeFactor f32 lineWidth } class VkPipelineMultisampleStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineMultisampleStateCreateFlags flags VkSampleCountFlagBits rasterizationSamples /// Number of samples used for rasterization VkBool32 sampleShadingEnable /// optional (GL45) f32 minSampleShading /// optional (GL45) const VkSampleMask* pSampleMask VkBool32 alphaToCoverageEnable VkBool32 alphaToOneEnable } class VkPipelineColorBlendAttachmentState { VkBool32 blendEnable VkBlendFactor srcColorBlendFactor VkBlendFactor dstColorBlendFactor VkBlendOp colorBlendOp VkBlendFactor srcAlphaBlendFactor VkBlendFactor dstAlphaBlendFactor VkBlendOp alphaBlendOp VkColorComponentFlags colorWriteMask } class VkPipelineColorBlendStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineColorBlendStateCreateFlags flags VkBool32 logicOpEnable VkLogicOp logicOp u32 attachmentCount /// # of pAttachments const VkPipelineColorBlendAttachmentState* pAttachments f32[4] blendConstants } class VkStencilOpState { VkStencilOp failOp VkStencilOp passOp VkStencilOp depthFailOp VkCompareOp compareOp u32 compareMask u32 writeMask u32 reference } class VkPipelineDepthStencilStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineDepthStencilStateCreateFlags flags VkBool32 depthTestEnable VkBool32 depthWriteEnable VkCompareOp depthCompareOp VkBool32 depthBoundsTestEnable /// optional (depth_bounds_test) VkBool32 stencilTestEnable VkStencilOpState front VkStencilOpState back f32 minDepthBounds f32 maxDepthBounds } class VkPipelineDynamicStateCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineDynamicStateCreateFlags flags u32 dynamicStateCount const VkDynamicState* pDynamicStates } class VkGraphicsPipelineCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineCreateFlags flags /// Pipeline creation flags u32 stageCount const VkPipelineShaderStageCreateInfo* pStages /// One entry for each active shader stage const VkPipelineVertexInputStateCreateInfo* pVertexInputState const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState const VkPipelineTessellationStateCreateInfo* pTessellationState const VkPipelineViewportStateCreateInfo* pViewportState const VkPipelineRasterizationStateCreateInfo* pRasterizationState const VkPipelineMultisampleStateCreateInfo* pMultisampleState const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState const VkPipelineColorBlendStateCreateInfo* pColorBlendState const VkPipelineDynamicStateCreateInfo* pDynamicState VkPipelineLayout layout /// Interface layout of the pipeline VkRenderPass renderPass u32 subpass VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of } class VkPipelineCacheCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineCacheCreateFlags flags platform.size_t initialDataSize /// Size of initial data to populate cache, in bytes const void* pInitialData /// Initial data to populate cache } class VkPushConstantRange { VkShaderStageFlags stageFlags /// Which stages use the range u32 offset /// Start of the range, in bytes u32 size /// Length of the range, in bytes } class VkPipelineLayoutCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO const void* pNext /// Pointer to next structure VkPipelineLayoutCreateFlags flags u32 descriptorSetCount /// Number of descriptor sets interfaced by the pipeline const VkDescriptorSetLayout* pSetLayouts /// Array of number of descriptor set layout objects defining the layout of the u32 pushConstantRangeCount /// Number of push-constant ranges used by the pipeline const VkPushConstantRange* pPushConstantRanges /// Array of pushConstantRangeCount number of ranges used by various shader stages } class VkSamplerCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO const void* pNext /// Pointer to next structure VkSamplerCreateFlags flags VkFilter magFilter /// Filter mode for magnification VkFilter minFilter /// Filter mode for minifiation VkSamplerMipmapMode mipmapMode /// Mipmap selection mode VkSamplerAddressMode addressModeU VkSamplerAddressMode addressModeV VkSamplerAddressMode addressModeW f32 mipLodBias VkBool32 anisotropyEnable f32 maxAnisotropy VkBool32 compareEnable VkCompareOp compareOp f32 minLod f32 maxLod VkBorderColor borderColor VkBool32 unnormalizedCoordinates } class VkCommandPoolCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO const void* pNext /// Pointer to next structure VkCommandPoolCreateFlags flags /// Command pool creation flags u32 queueFamilyIndex } class VkCommandBufferAllocateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO const void* pNext /// Pointer to next structure VkCommandPool commandPool VkCommandBufferLevel level u32 commandBufferCount } class VkCommandBufferInheritanceInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO const void* pNext /// Pointer to next structure VkRenderPass renderPass /// Render pass for secondary command buffers u32 subpass VkFramebuffer framebuffer /// Framebuffer for secondary command buffers VkBool32 occlusionQueryEnable VkQueryControlFlags queryFlags VkQueryPipelineStatisticFlags pipelineStatistics } class VkCommandBufferBeginInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO const void* pNext /// Pointer to next structure VkCommandBufferUsageFlags flags /// Command buffer usage flags const VkCommandBufferInheritanceInfo* pInheritanceInfo } class VkRenderPassBeginInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO const void* pNext /// Pointer to next structure VkRenderPass renderPass VkFramebuffer framebuffer VkRect2D renderArea u32 clearValueCount const VkClearValue* pClearValues } @union /// Union allowing specification of floating point, integer, or unsigned integer color data. Actual value selected is based on image/attachment being cleared. class VkClearColorValue { f32[4] float32 s32[4] int32 u32[4] uint32 } class VkClearDepthStencilValue { f32 depth u32 stencil } @union /// Union allowing specification of color, depth, and stencil color values. Actual value selected is based on attachment being cleared. class VkClearValue { VkClearColorValue color VkClearDepthStencilValue depthStencil } class VkClearAttachment { VkImageAspectFlags aspectMask u32 colorAttachment VkClearValue clearValue } class VkAttachmentDescription { VkAttachmentDescriptionFlags flags VkFormat format VkSampleCountFlagBits samples VkAttachmentLoadOp loadOp /// Load op for color or depth data VkAttachmentStoreOp storeOp /// Store op for color or depth data VkAttachmentLoadOp stencilLoadOp /// Load op for stencil data VkAttachmentStoreOp stencilStoreOp /// Store op for stencil data VkImageLayout initialLayout VkImageLayout finalLayout } class VkAttachmentReference { u32 attachment VkImageLayout layout } class VkSubpassDescription { VkSubpassDescriptionFlags flags VkPipelineBindPoint pipelineBindPoint /// Must be VK_PIPELINE_BIND_POINT_GRAPHICS for now u32 inputAttachmentCount const VkAttachmentReference* pInputAttachments u32 colorAttachmentCount const VkAttachmentReference* pColorAttachments const VkAttachmentReference* pResolveAttachments const VkAttachmentReference* pDepthStencilAttachment u32 preserveAttachmentCount const u32* pPreserveAttachments } class VkSubpassDependency { u32 srcSubpass u32 dstSubpass VkPipelineStageFlags srcStageMask VkPipelineStageFlags dstStageMask VkAccessFlags srcAccessMask VkAccessFlags dstAccessMask VkDependencyFlags dependencyFlags } class VkRenderPassCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO const void* pNext /// Pointer to next structure VkRenderPassCreateFlags flags u32 attachmentCount const VkAttachmentDescription* pAttachments u32 subpassCount const VkSubpassDescription* pSubpasses u32 dependencyCount const VkSubpassDependency* pDependencies } class VkEventCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_EVENT_CREATE_INFO const void* pNext /// Pointer to next structure VkEventCreateFlags flags /// Event creation flags } class VkFenceCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FENCE_CREATE_INFO const void* pNext /// Pointer to next structure VkFenceCreateFlags flags /// Fence creation flags } class VkPhysicalDeviceFeatures { VkBool32 robustBufferAccess /// out of bounds buffer accesses are well defined VkBool32 fullDrawIndexUint32 /// full 32-bit range of indices for indexed draw calls VkBool32 imageCubeArray /// image views which are arrays of cube maps VkBool32 independentBlend /// blending operations are controlled per-attachment VkBool32 geometryShader /// geometry stage VkBool32 tessellationShader /// tessellation control and evaluation stage VkBool32 sampleRateShading /// per-sample shading and interpolation VkBool32 dualSrcBlend /// blend operations which take two sources VkBool32 logicOp /// logic operations VkBool32 multiDrawIndirect /// multi draw indirect VkBool32 drawIndirectFirstInstance VkBool32 depthClamp /// depth clamping VkBool32 depthBiasClamp /// depth bias clamping VkBool32 fillModeNonSolid /// point and wireframe fill modes VkBool32 depthBounds /// depth bounds test VkBool32 wideLines /// lines with width greater than 1 VkBool32 largePoints /// points with size greater than 1 VkBool32 alphaToOne /// The fragment alpha channel can be forced to maximum representable alpha value VkBool32 multiViewport VkBool32 samplerAnisotropy VkBool32 textureCompressionETC2 /// ETC texture compression formats VkBool32 textureCompressionASTC_LDR /// ASTC LDR texture compression formats VkBool32 textureCompressionBC /// BC1-7 texture compressed formats VkBool32 occlusionQueryPrecise VkBool32 pipelineStatisticsQuery /// pipeline statistics query VkBool32 vertexPipelineStoresAndAtomics VkBool32 fragmentStoresAndAtomics VkBool32 shaderTessellationAndGeometryPointSize VkBool32 shaderImageGatherExtended /// texture gather with run-time values and independent offsets VkBool32 shaderStorageImageExtendedFormats /// the extended set of formats can be used for storage images VkBool32 shaderStorageImageMultisample /// multisample images can be used for storage images VkBool32 shaderStorageImageReadWithoutFormat VkBool32 shaderStorageImageWriteWithoutFormat VkBool32 shaderUniformBufferArrayDynamicIndexing /// arrays of uniform buffers can be accessed with dynamically uniform indices VkBool32 shaderSampledImageArrayDynamicIndexing /// arrays of sampled images can be accessed with dynamically uniform indices VkBool32 shaderStorageBufferArrayDynamicIndexing /// arrays of storage buffers can be accessed with dynamically uniform indices VkBool32 shaderStorageImageArrayDynamicIndexing /// arrays of storage images can be accessed with dynamically uniform indices VkBool32 shaderClipDistance /// clip distance in shaders VkBool32 shaderCullDistance /// cull distance in shaders VkBool32 shaderFloat64 /// 64-bit floats (doubles) in shaders VkBool32 shaderInt64 /// 64-bit integers in shaders VkBool32 shaderInt16 /// 16-bit integers in shaders VkBool32 shaderResourceResidency /// shader can use texture operations that return resource residency information (requires sparseNonResident support) VkBool32 shaderResourceMinLod /// shader can use texture operations that specify minimum resource LOD VkBool32 sparseBinding /// Sparse resources support: Resource memory can be managed at opaque page level rather than object level VkBool32 sparseResidencyBuffer /// Sparse resources support: GPU can access partially resident buffers VkBool32 sparseResidencyImage2D /// Sparse resources support: GPU can access partially resident 2D (non-MSAA non-DepthStencil) images VkBool32 sparseResidencyImage3D /// Sparse resources support: GPU can access partially resident 3D images VkBool32 sparseResidency2Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 2 samples VkBool32 sparseResidency4Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 4 samples VkBool32 sparseResidency8Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 8 samples VkBool32 sparseResidency16Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 16 samples VkBool32 sparseResidencyAliased /// Sparse resources support: GPU can correctly access data aliased into multiple locations (opt-in) VkBool32 variableMultisampleRate VkBool32 inheritedQueries } class VkPhysicalDeviceLimits { /// resource maximum sizes u32 maxImageDimension1D /// max 1D image dimension u32 maxImageDimension2D /// max 2D image dimension u32 maxImageDimension3D /// max 3D image dimension u32 maxImageDimensionCube /// max cubemap image dimension u32 maxImageArrayLayers /// max layers for image arrays u32 maxTexelBufferElements u32 maxUniformBufferRange /// max uniform buffer size (bytes) u32 maxStorageBufferRange /// max storage buffer size (bytes) u32 maxPushConstantsSize /// max size of the push constants pool (bytes) /// memory limits u32 maxMemoryAllocationCount /// max number of device memory allocations supported u32 maxSamplerAllocationCount VkDeviceSize bufferImageGranularity /// Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage VkDeviceSize sparseAddressSpaceSize /// Total address space available for sparse allocations (bytes) /// descriptor set limits u32 maxBoundDescriptorSets /// max number of descriptors sets that can be bound to a pipeline u32 maxPerStageDescriptorSamplers /// max num of samplers allowed per-stage in a descriptor set u32 maxPerStageDescriptorUniformBuffers /// max num of uniform buffers allowed per-stage in a descriptor set u32 maxPerStageDescriptorStorageBuffers /// max num of storage buffers allowed per-stage in a descriptor set u32 maxPerStageDescriptorSampledImages /// max num of sampled images allowed per-stage in a descriptor set u32 maxPerStageDescriptorStorageImages /// max num of storage images allowed per-stage in a descriptor set u32 maxPerStageDescriptorInputAttachments u32 maxPerStageResources u32 maxDescriptorSetSamplers /// max num of samplers allowed in all stages in a descriptor set u32 maxDescriptorSetUniformBuffers /// max num of uniform buffers allowed in all stages in a descriptor set u32 maxDescriptorSetUniformBuffersDynamic /// max num of dynamic uniform buffers allowed in all stages in a descriptor set u32 maxDescriptorSetStorageBuffers /// max num of storage buffers allowed in all stages in a descriptor set u32 maxDescriptorSetStorageBuffersDynamic /// max num of dynamic storage buffers allowed in all stages in a descriptor set u32 maxDescriptorSetSampledImages /// max num of sampled images allowed in all stages in a descriptor set u32 maxDescriptorSetStorageImages /// max num of storage images allowed in all stages in a descriptor set u32 maxDescriptorSetInputAttachments /// vertex stage limits u32 maxVertexInputAttributes /// max num of vertex input attribute slots u32 maxVertexInputBindings /// max num of vertex input binding slots u32 maxVertexInputAttributeOffset /// max vertex input attribute offset added to vertex buffer offset u32 maxVertexInputBindingStride /// max vertex input binding stride u32 maxVertexOutputComponents /// max num of output components written by vertex shader /// tessellation control stage limits u32 maxTessellationGenerationLevel /// max level supported by tess primitive generator u32 maxTessellationPatchSize /// max patch size (vertices) u32 maxTessellationControlPerVertexInputComponents /// max num of input components per-vertex in TCS u32 maxTessellationControlPerVertexOutputComponents /// max num of output components per-vertex in TCS u32 maxTessellationControlPerPatchOutputComponents /// max num of output components per-patch in TCS u32 maxTessellationControlTotalOutputComponents /// max total num of per-vertex and per-patch output components in TCS u32 maxTessellationEvaluationInputComponents /// max num of input components per vertex in TES u32 maxTessellationEvaluationOutputComponents /// max num of output components per vertex in TES /// geometry stage limits u32 maxGeometryShaderInvocations /// max invocation count supported in geometry shader u32 maxGeometryInputComponents /// max num of input components read in geometry stage u32 maxGeometryOutputComponents /// max num of output components written in geometry stage u32 maxGeometryOutputVertices /// max num of vertices that can be emitted in geometry stage u32 maxGeometryTotalOutputComponents /// max total num of components (all vertices) written in geometry stage /// fragment stage limits u32 maxFragmentInputComponents /// max num of input compontents read in fragment stage u32 maxFragmentOutputAttachments /// max num of output attachments written in fragment stage u32 maxFragmentDualSrcAttachments /// max num of output attachments written when using dual source blending u32 maxFragmentCombinedOutputResources /// max total num of storage buffers, storage images and output buffers /// compute stage limits u32 maxComputeSharedMemorySize /// max total storage size of work group local storage (bytes) u32[3] maxComputeWorkGroupCount /// max num of compute work groups that may be dispatched by a single command (x,y,z) u32 maxComputeWorkGroupInvocations /// max total compute invocations in a single local work group u32[3] maxComputeWorkGroupSize /// max local size of a compute work group (x,y,z) u32 subPixelPrecisionBits /// num bits of subpixel precision in screen x and y u32 subTexelPrecisionBits /// num bits of subtexel precision u32 mipmapPrecisionBits /// num bits of mipmap precision u32 maxDrawIndexedIndexValue /// max index value for indexed draw calls (for 32-bit indices) u32 maxDrawIndirectCount f32 maxSamplerLodBias /// max absolute sampler level of detail bias f32 maxSamplerAnisotropy /// max degree of sampler anisotropy u32 maxViewports /// max number of active viewports u32[2] maxViewportDimensions /// max viewport dimensions (x,y) f32[2] viewportBoundsRange /// viewport bounds range (min,max) u32 viewportSubPixelBits /// num bits of subpixel precision for viewport platform.size_t minMemoryMapAlignment /// min required alignment of pointers returned by MapMemory (bytes) VkDeviceSize minTexelBufferOffsetAlignment /// min required alignment for texel buffer offsets (bytes) VkDeviceSize minUniformBufferOffsetAlignment /// min required alignment for uniform buffer sizes and offsets (bytes) VkDeviceSize minStorageBufferOffsetAlignment /// min required alignment for storage buffer offsets (bytes) s32 minTexelOffset /// min texel offset for OpTextureSampleOffset u32 maxTexelOffset /// max texel offset for OpTextureSampleOffset s32 minTexelGatherOffset /// min texel offset for OpTextureGatherOffset u32 maxTexelGatherOffset /// max texel offset for OpTextureGatherOffset f32 minInterpolationOffset /// furthest negative offset for interpolateAtOffset f32 maxInterpolationOffset /// furthest positive offset for interpolateAtOffset u32 subPixelInterpolationOffsetBits /// num of subpixel bits for interpolateAtOffset u32 maxFramebufferWidth /// max width for a framebuffer u32 maxFramebufferHeight /// max height for a framebuffer u32 maxFramebufferLayers /// max layer count for a layered framebuffer VkSampleCountFlags framebufferColorSampleCounts VkSampleCountFlags framebufferDepthSampleCounts VkSampleCountFlags framebufferStencilSampleCounts VkSampleCountFlags framebufferNoAttachmentSampleCounts u32 maxColorAttachments /// max num of framebuffer color attachments VkSampleCountFlags sampledImageColorSampleCounts VkSampleCountFlags sampledImageIntegerSampleCounts VkSampleCountFlags sampledImageDepthSampleCounts VkSampleCountFlags sampledImageStencilSampleCounts VkSampleCountFlags storageImageSampleCounts u32 maxSampleMaskWords /// max num of sample mask words VkBool32 timestampComputeAndGraphics f32 timestampPeriod u32 maxClipDistances /// max number of clip distances u32 maxCullDistances /// max number of cull distances u32 maxCombinedClipAndCullDistances /// max combined number of user clipping u32 discreteQueuePriorities f32[2] pointSizeRange /// range (min,max) of supported point sizes f32[2] lineWidthRange /// range (min,max) of supported line widths f32 pointSizeGranularity /// granularity of supported point sizes f32 lineWidthGranularity /// granularity of supported line widths VkBool32 strictLines VkBool32 standardSampleLocations VkDeviceSize optimalBufferCopyOffsetAlignment VkDeviceSize optimalBufferCopyRowPitchAlignment VkDeviceSize nonCoherentAtomSize } class VkPhysicalDeviceSparseProperties { VkBool32 residencyStandard2DBlockShape /// Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard block shapes (based on pixel format) VkBool32 residencyStandard2DMultisampleBlockShape /// Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard block shapes (based on pixel format) VkBool32 residencyStandard3DBlockShape /// Sparse resources support: GPU will access all 3D sparse resources using the standard block shapes (based on pixel format) VkBool32 residencyAlignedMipSize /// Sparse resources support: Images with mip-level dimensions that are NOT a multiple of the block size will be placed in the mip tail VkBool32 residencyNonResidentStrict /// Sparse resources support: GPU can safely access non-resident regions of a resource, all reads return as if data is 0, writes are discarded } class VkSemaphoreCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO const void* pNext /// Pointer to next structure VkSemaphoreCreateFlags flags /// Semaphore creation flags } class VkQueryPoolCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO const void* pNext /// Pointer to next structure VkQueryPoolCreateFlags flags VkQueryType queryType u32 queryCount VkQueryPipelineStatisticFlags pipelineStatistics /// Optional } class VkFramebufferCreateInfo { VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO const void* pNext /// Pointer to next structure VkFramebufferCreateFlags flags VkRenderPass renderPass u32 attachmentCount const VkImageView* pAttachments u32 width u32 height u32 layers } class VkDrawIndirectCommand { u32 vertexCount u32 instanceCount u32 firstVertex u32 firstInstance } class VkDrawIndexedIndirectCommand { u32 indexCount u32 instanceCount u32 firstIndex s32 vertexOffset u32 firstInstance } class VkDispatchIndirectCommand { u32 x u32 y u32 z } @extension("VK_KHR_surface") class VkSurfaceCapabilitiesKHR { u32 minImageCount u32 maxImageCount VkExtent2D currentExtent VkExtent2D minImageExtent VkExtent2D maxImageExtent u32 maxImageArrayLayers VkSurfaceTransformFlagsKHR supportedTransforms VkSurfaceTransformFlagBitsKHR currentTransform VkCompositeAlphaFlagsKHR supportedCompositeAlpha VkImageUsageFlags supportedUsageFlags } @extension("VK_KHR_surface") class VkSurfaceFormatKHR { VkFormat format VkColorSpaceKHR colorSpace } @extension("VK_KHR_swapchain") class VkSwapchainCreateInfoKHR { VkStructureType sType const void* pNext VkSwapchainCreateFlagsKHR flags VkSurfaceKHR surface u32 minImageCount VkFormat imageFormat VkColorSpaceKHR imageColorSpace VkExtent2D imageExtent u32 imageArrayLayers VkImageUsageFlags imageUsage VkSharingMode sharingMode u32 queueFamilyIndexCount const u32* pQueueFamilyIndices VkSurfaceTransformFlagBitsKHR preTransform VkCompositeAlphaFlagBitsKHR compositeAlpha VkPresentModeKHR presentMode VkBool32 clipped VkSwapchainKHR oldSwapchain } @extension("VK_KHR_swapchain") class VkPresentInfoKHR { VkStructureType sType const void* pNext u32 waitSemaphoreCount const VkSemaphore* pWaitSemaphores u32 swapchainCount const VkSwapchainKHR* pSwapchains const u32* pImageIndices VkResult* pResults } @extension("VK_KHR_display") class VkDisplayPropertiesKHR { VkDisplayKHR display const char* displayName VkExtent2D physicalDimensions VkExtent2D physicalResolution VkSurfaceTransformFlagsKHR supportedTransforms VkBool32 planeReorderPossible VkBool32 persistentContent } @extension("VK_KHR_display") class VkDisplayModeParametersKHR { VkExtent2D visibleRegion u32 refreshRate } @extension("VK_KHR_display") class VkDisplayModePropertiesKHR { VkDisplayModeKHR displayMode VkDisplayModeParametersKHR parameters } @extension("VK_KHR_display") class VkDisplayModeCreateInfoKHR { VkStructureType sType const void* pNext VkDisplayModeCreateFlagsKHR flags VkDisplayModeParametersKHR parameters } @extension("VK_KHR_display") class VkDisplayPlanePropertiesKHR { VkDisplayKHR currentDisplay u32 currentStackIndex } @extension("VK_KHR_display") class VkDisplayPlaneCapabilitiesKHR { VkDisplayPlaneAlphaFlagsKHR supportedAlpha VkOffset2D minSrcPosition VkOffset2D maxSrcPosition VkExtent2D minSrcExtent VkExtent2D maxSrcExtent VkOffset2D minDstPosition VkOffset2D maxDstPosition VkExtent2D minDstExtent VkExtent2D maxDstExtent } @extension("VK_KHR_display") class VkDisplaySurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkDisplaySurfaceCreateFlagsKHR flags VkDisplayModeKHR displayMode u32 planeIndex u32 planeStackIndex VkSurfaceTransformFlagBitsKHR transform f32 globalAlpha VkDisplayPlaneAlphaFlagBitsKHR alphaMode VkExtent2D imageExtent } @extension("VK_KHR_display_swapchain") class VkDisplayPresentInfoKHR { VkStructureType sType const void* pNext VkRect2D srcRect VkRect2D dstRect VkBool32 persistent } @extension("VK_KHR_xlib_surface") class VkXlibSurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkXlibSurfaceCreateFlagsKHR flags platform.Display* dpy platform.Window window } @extension("VK_KHR_xcb_surface") class VkXcbSurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkXcbSurfaceCreateFlagsKHR flags platform.xcb_connection_t* connection platform.xcb_window_t window } @extension("VK_KHR_wayland_surface") class VkWaylandSurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkWaylandSurfaceCreateFlagsKHR flags platform.wl_display* display platform.wl_surface* surface } @extension("VK_KHR_mir_surface") class VkMirSurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkMirSurfaceCreateFlagsKHR flags platform.MirConnection* connection platform.MirSurface* mirSurface } @extension("VK_KHR_android_surface") class VkAndroidSurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkAndroidSurfaceCreateFlagsKHR flags platform.ANativeWindow* window } @extension("VK_KHR_win32_surface") class VkWin32SurfaceCreateInfoKHR { VkStructureType sType const void* pNext VkWin32SurfaceCreateFlagsKHR flags platform.HINSTANCE hinstance platform.HWND hwnd } @extension("VK_ANDROID_native_buffer") class VkNativeBufferANDROID { VkStructureType sType const void* pNext platform.buffer_handle_t handle int stride int format int usage } @extension("VK_EXT_debug_report") class VkDebugReportCallbackCreateInfoEXT { VkStructureType sType const void* pNext VkDebugReportFlagsEXT flags PFN_vkDebugReportCallbackEXT pfnCallback void* pUserData } @extension("VK_AMD_rasterization_order") class VkPipelineRasterizationStateRasterizationOrderAMD { VkStructureType sType const void* pNext VkRasterizationOrderAMD rasterizationOrder } @extension("VK_EXT_debug_marker") class VkDebugMarkerObjectNameInfoEXT { VkStructureType sType const void* pNext VkDebugReportObjectTypeEXT objectType u64 object const char* pObjectName } @extension("VK_EXT_debug_marker") class VkDebugMarkerObjectTagInfoEXT { VkStructureType sType const void* pNext VkDebugReportObjectTypeEXT objectType u64 object u64 tagName platform.size_t tagSize const void* pTag } @extension("VK_EXT_debug_marker") class VkDebugMarkerMarkerInfoEXT { VkStructureType sType const void* pNext const char* pMarkerName f32[4] color } //////////////// // Commands // //////////////// // Function pointers. TODO: add support for function pointers. @external type void* PFN_vkVoidFunction @pfn cmd void vkVoidFunction() { } @external type void* PFN_vkAllocationFunction @pfn cmd void* vkAllocationFunction( void* pUserData, platform.size_t size, platform.size_t alignment, VkSystemAllocationScope allocationScope) { return ? } @external type void* PFN_vkReallocationFunction @pfn cmd void* vkReallocationFunction( void* pUserData, void* pOriginal, platform.size_t size, platform.size_t alignment, VkSystemAllocationScope allocationScope) { return ? } @external type void* PFN_vkFreeFunction @pfn cmd void vkFreeFunction( void* pUserData, void* pMemory) { } @external type void* PFN_vkInternalAllocationNotification @pfn cmd void vkInternalAllocationNotification( void* pUserData, platform.size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) { } @external type void* PFN_vkInternalFreeNotification @pfn cmd void vkInternalFreeNotification( void* pUserData, platform.size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) { } // Global functions @threadSafety("system") cmd VkResult vkCreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) instance := ? pInstance[0] = instance State.Instances[instance] = new!InstanceObject() layers := pCreateInfo.ppEnabledLayerNames[0:pCreateInfo.enabledLayerCount] extensions := pCreateInfo.ppEnabledExtensionNames[0:pCreateInfo.enabledExtensionCount] return ? } @threadSafety("system") cmd void vkDestroyInstance( VkInstance instance, const VkAllocationCallbacks* pAllocator) { instanceObject := GetInstance(instance) State.Instances[instance] = null } @threadSafety("system") cmd VkResult vkEnumeratePhysicalDevices( VkInstance instance, u32* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) { instanceObject := GetInstance(instance) physicalDeviceCount := as!u32(?) pPhysicalDeviceCount[0] = physicalDeviceCount physicalDevices := pPhysicalDevices[0:physicalDeviceCount] for i in (0 .. physicalDeviceCount) { physicalDevice := ? physicalDevices[i] = physicalDevice if !(physicalDevice in State.PhysicalDevices) { State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) } } return ? } cmd PFN_vkVoidFunction vkGetDeviceProcAddr( VkDevice device, const char* pName) { if device != NULL_HANDLE { device := GetDevice(device) } return ? } cmd PFN_vkVoidFunction vkGetInstanceProcAddr( VkInstance instance, const char* pName) { if instance != NULL_HANDLE { instanceObject := GetInstance(instance) } return ? } cmd void vkGetPhysicalDeviceProperties( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) properties := ? pProperties[0] = properties } cmd void vkGetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice physicalDevice, u32* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) // TODO: Figure out how to express fetch-count-or-properties // This version fails 'apic validate' with 'fence not allowed in // *semantic.Branch'. Other attempts have failed with the same or other // errors. // if pQueueFamilyProperties != null { // queuesProperties := pQueueFamilyProperties[0:pCount[0]] // for i in (0 .. pCount[0]) { // queueProperties := as!VkQueueFamilyProperties(?) // queuesProperties[i] = queueProperties // } // } else { // count := ? // pCount[0] = count // } } cmd void vkGetPhysicalDeviceMemoryProperties( VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) memoryProperties := ? pMemoryProperties[0] = memoryProperties } cmd void vkGetPhysicalDeviceFeatures( VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) features := ? pFeatures[0] = features } cmd void vkGetPhysicalDeviceFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) formatProperties := ? pFormatProperties[0] = formatProperties } cmd VkResult vkGetPhysicalDeviceImageFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) imageFormatProperties := ? pImageFormatProperties[0] = imageFormatProperties return ? } // Device functions @threadSafety("system") cmd VkResult vkCreateDevice( VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO) physicalDeviceObject := GetPhysicalDevice(physicalDevice) device := ? pDevice[0] = device State.Devices[device] = new!DeviceObject(physicalDevice: physicalDevice) return ? } @threadSafety("system") cmd void vkDestroyDevice( VkDevice device, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) State.Devices[device] = null } // Extension discovery functions cmd VkResult vkEnumerateInstanceLayerProperties( u32* pPropertyCount, VkLayerProperties* pProperties) { count := as!u32(?) pPropertyCount[0] = count properties := pProperties[0:count] for i in (0 .. count) { property := ? properties[i] = property } return ? } cmd VkResult vkEnumerateInstanceExtensionProperties( const char* pLayerName, u32* pPropertyCount, VkExtensionProperties* pProperties) { count := as!u32(?) pPropertyCount[0] = count properties := pProperties[0:count] for i in (0 .. count) { property := ? properties[i] = property } return ? } cmd VkResult vkEnumerateDeviceLayerProperties( VkPhysicalDevice physicalDevice, u32* pPropertyCount, VkLayerProperties* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) count := as!u32(?) pPropertyCount[0] = count properties := pProperties[0:count] for i in (0 .. count) { property := ? properties[i] = property } return ? } cmd VkResult vkEnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, u32* pPropertyCount, VkExtensionProperties* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) count := as!u32(?) pPropertyCount[0] = count properties := pProperties[0:count] for i in (0 .. count) { property := ? properties[i] = property } return ? } // Queue functions @threadSafety("system") cmd void vkGetDeviceQueue( VkDevice device, u32 queueFamilyIndex, u32 queueIndex, VkQueue* pQueue) { deviceObject := GetDevice(device) queue := ? pQueue[0] = queue if !(queue in State.Queues) { State.Queues[queue] = new!QueueObject(device: device) } } @threadSafety("app") cmd VkResult vkQueueSubmit( VkQueue queue, u32 submitCount, const VkSubmitInfo* pSubmits, VkFence fence) { queueObject := GetQueue(queue) if fence != NULL_HANDLE { fenceObject := GetFence(fence) assert(fenceObject.device == queueObject.device) } // commandBuffers := pcommandBuffers[0:commandBufferCount] // for i in (0 .. commandBufferCount) { // commandBuffer := commandBuffers[i] // commandBufferObject := GetCommandBuffer(commandBuffer) // assert(commandBufferObject.device == queueObject.device) // // validate("QueueCheck", commandBufferObject.queueFlags in queueObject.flags, // "vkQueueSubmit: enqueued commandBuffer requires missing queue capabilities.") // } return ? } @threadSafety("system") cmd VkResult vkQueueWaitIdle( VkQueue queue) { queueObject := GetQueue(queue) return ? } @threadSafety("system") cmd VkResult vkDeviceWaitIdle( VkDevice device) { deviceObject := GetDevice(device) return ? } // Memory functions @threadSafety("system") cmd VkResult vkAllocateMemory( VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory) { assert(pAllocateInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO) deviceObject := GetDevice(device) memory := ? pMemory[0] = memory State.DeviceMemories[memory] = new!DeviceMemoryObject( device: device, allocationSize: pAllocateInfo[0].allocationSize) return ? } @threadSafety("system") cmd void vkFreeMemory( VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) // Check that no objects are still bound before freeing. validate("MemoryCheck", len(memoryObject.boundObjects) == 0, "vkFreeMemory: objects still bound") validate("MemoryCheck", len(memoryObject.boundCommandBuffers) == 0, "vkFreeMemory: commandBuffers still bound") State.DeviceMemories[memory] = null } @threadSafety("app") cmd VkResult vkMapMemory( VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) { deviceObject := GetDevice(device) memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) assert(flags == as!VkMemoryMapFlags(0)) assert((offset + size) <= memoryObject.allocationSize) return ? } @threadSafety("app") cmd void vkUnmapMemory( VkDevice device, VkDeviceMemory memory) { deviceObject := GetDevice(device) memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) } cmd VkResult vkFlushMappedMemoryRanges( VkDevice device, u32 memoryRangeCount const VkMappedMemoryRange* pMemoryRanges) { deviceObject := GetDevice(device) memoryRanges := pMemoryRanges[0:memoryRangeCount] for i in (0 .. memoryRangeCount) { memoryRange := memoryRanges[i] memoryObject := GetDeviceMemory(memoryRange.memory) assert(memoryObject.device == device) assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize) } return ? } cmd VkResult vkInvalidateMappedMemoryRanges( VkDevice device, u32 memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { deviceObject := GetDevice(device) memoryRanges := pMemoryRanges[0:memoryRangeCount] for i in (0 .. memoryRangeCount) { memoryRange := memoryRanges[i] memoryObject := GetDeviceMemory(memoryRange.memory) assert(memoryObject.device == device) assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize) } return ? } // Memory management API functions cmd void vkGetDeviceMemoryCommitment( VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) { deviceObject := GetDevice(device) if memory != NULL_HANDLE { memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) } committedMemoryInBytes := ? pCommittedMemoryInBytes[0] = committedMemoryInBytes } cmd void vkGetBufferMemoryRequirements( VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) { deviceObject := GetDevice(device) bufferObject := GetBuffer(buffer) assert(bufferObject.device == device) } cmd VkResult vkBindBufferMemory( VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) { deviceObject := GetDevice(device) bufferObject := GetBuffer(buffer) assert(bufferObject.device == device) // Unbind buffer from previous memory object, if not VK_NULL_HANDLE. if bufferObject.memory != NULL_HANDLE { memoryObject := GetDeviceMemory(bufferObject.memory) memoryObject.boundObjects[as!u64(buffer)] = null } // Bind buffer to given memory object, if not VK_NULL_HANDLE. if memory != NULL_HANDLE { memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) memoryObject.boundObjects[as!u64(buffer)] = memoryOffset } bufferObject.memory = memory bufferObject.memoryOffset = memoryOffset return ? } cmd void vkGetImageMemoryRequirements( VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) { deviceObject := GetDevice(device) imageObject := GetImage(image) assert(imageObject.device == device) } cmd VkResult vkBindImageMemory( VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) { deviceObject := GetDevice(device) imageObject := GetImage(image) assert(imageObject.device == device) // Unbind image from previous memory object, if not VK_NULL_HANDLE. if imageObject.memory != NULL_HANDLE { memoryObject := GetDeviceMemory(imageObject.memory) memoryObject.boundObjects[as!u64(image)] = null } // Bind image to given memory object, if not VK_NULL_HANDLE. if memory != NULL_HANDLE { memoryObject := GetDeviceMemory(memory) assert(memoryObject.device == device) memoryObject.boundObjects[as!u64(image)] = memoryOffset } imageObject.memory = memory imageObject.memoryOffset = memoryOffset return ? } cmd void vkGetImageSparseMemoryRequirements( VkDevice device, VkImage image, u32* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { deviceObject := GetDevice(device) imageObject := GetImage(image) assert(imageObject.device == device) } cmd void vkGetPhysicalDeviceSparseImageFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, u32* pPropertyCount, VkSparseImageFormatProperties* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) } cmd VkResult vkQueueBindSparse( VkQueue queue, u32 bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence) { queueObject := GetQueue(queue) return ? } // Fence functions @threadSafety("system") cmd VkResult vkCreateFence( VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO) deviceObject := GetDevice(device) fence := ? pFence[0] = fence State.Fences[fence] = new!FenceObject( device: device, signaled: (pCreateInfo.flags == as!VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT))) return ? } @threadSafety("system") cmd void vkDestroyFence( VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) fenceObject := GetFence(fence) assert(fenceObject.device == device) State.Fences[fence] = null } @threadSafety("system") cmd VkResult vkResetFences( VkDevice device, u32 fenceCount, const VkFence* pFences) { deviceObject := GetDevice(device) fences := pFences[0:fenceCount] for i in (0 .. fenceCount) { fence := fences[i] fenceObject := GetFence(fence) assert(fenceObject.device == device) fenceObject.signaled = false } return ? } @threadSafety("system") cmd VkResult vkGetFenceStatus( VkDevice device, VkFence fence) { deviceObject := GetDevice(device) fenceObject := GetFence(fence) assert(fenceObject.device == device) return ? } @threadSafety("system") cmd VkResult vkWaitForFences( VkDevice device, u32 fenceCount, const VkFence* pFences, VkBool32 waitAll, u64 timeout) { /// timeout in nanoseconds deviceObject := GetDevice(device) fences := pFences[0:fenceCount] for i in (0 .. fenceCount) { fence := fences[i] fenceObject := GetFence(fence) assert(fenceObject.device == device) } return ? } // Queue semaphore functions @threadSafety("system") cmd VkResult vkCreateSemaphore( VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) deviceObject := GetDevice(device) semaphore := ? pSemaphore[0] = semaphore State.Semaphores[semaphore] = new!SemaphoreObject(device: device) return ? } @threadSafety("system") cmd void vkDestroySemaphore( VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) semaphoreObject := GetSemaphore(semaphore) assert(semaphoreObject.device == device) State.Semaphores[semaphore] = null } // Event functions @threadSafety("system") cmd VkResult vkCreateEvent( VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_EVENT_CREATE_INFO) deviceObject := GetDevice(device) event := ? pEvent[0] = event State.Events[event] = new!EventObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyEvent( VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) eventObject := GetEvent(event) assert(eventObject.device == device) State.Events[event] = null } @threadSafety("system") cmd VkResult vkGetEventStatus( VkDevice device, VkEvent event) { deviceObject := GetDevice(device) eventObject := GetEvent(event) assert(eventObject.device == device) return ? } @threadSafety("system") cmd VkResult vkSetEvent( VkDevice device, VkEvent event) { deviceObject := GetDevice(device) eventObject := GetEvent(event) assert(eventObject.device == device) return ? } @threadSafety("system") cmd VkResult vkResetEvent( VkDevice device, VkEvent event) { deviceObject := GetDevice(device) eventObject := GetEvent(event) assert(eventObject.device == device) return ? } // Query functions @threadSafety("system") cmd VkResult vkCreateQueryPool( VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO) deviceObject := GetDevice(device) queryPool := ? pQueryPool[0] = queryPool State.QueryPools[queryPool] = new!QueryPoolObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyQueryPool( VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) queryPoolObject := GetQueryPool(queryPool) assert(queryPoolObject.device == device) State.QueryPools[queryPool] = null } @threadSafety("system") cmd VkResult vkGetQueryPoolResults( VkDevice device, VkQueryPool queryPool, u32 firstQuery, u32 queryCount, platform.size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags) { deviceObject := GetDevice(device) queryPoolObject := GetQueryPool(queryPool) assert(queryPoolObject.device == device) data := pData[0:dataSize] return ? } // Buffer functions @threadSafety("system") cmd VkResult vkCreateBuffer( VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO) deviceObject := GetDevice(device) buffer := ? pBuffer[0] = buffer State.Buffers[buffer] = new!BufferObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyBuffer( VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) bufferObject := GetBuffer(buffer) assert(bufferObject.device == device) assert(bufferObject.memory == 0) State.Buffers[buffer] = null } // Buffer view functions @threadSafety("system") cmd VkResult vkCreateBufferView( VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO) deviceObject := GetDevice(device) bufferObject := GetBuffer(pCreateInfo.buffer) assert(bufferObject.device == device) view := ? pView[0] = view State.BufferViews[view] = new!BufferViewObject(device: device, buffer: pCreateInfo.buffer) return ? } @threadSafety("system") cmd void vkDestroyBufferView( VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) bufferViewObject := GetBufferView(bufferView) assert(bufferViewObject.device == device) State.BufferViews[bufferView] = null } // Image functions @threadSafety("system") cmd VkResult vkCreateImage( VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO) deviceObject := GetDevice(device) image := ? pImage[0] = image State.Images[image] = new!ImageObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyImage( VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) imageObject := GetImage(image) assert(imageObject.device == device) assert(imageObject.memory == 0) State.Images[image] = null } cmd void vkGetImageSubresourceLayout( VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { deviceObject := GetDevice(device) imageObject := GetImage(image) assert(imageObject.device == device) } // Image view functions @threadSafety("system") cmd VkResult vkCreateImageView( VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) deviceObject := GetDevice(device) imageObject := GetImage(pCreateInfo.image) assert(imageObject.device == device) view := ? pView[0] = view State.ImageViews[view] = new!ImageViewObject(device: device, image: pCreateInfo.image) return ? } @threadSafety("system") cmd void vkDestroyImageView( VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) imageViewObject := GetImageView(imageView) assert(imageViewObject.device == device) State.ImageViews[imageView] = null } // Shader functions cmd VkResult vkCreateShaderModule( VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO) deviceObject := GetDevice(device) shaderModule := ? pShaderModule[0] = shaderModule State.ShaderModules[shaderModule] = new!ShaderModuleObject(device: device) return ? } cmd void vkDestroyShaderModule( VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) shaderModuleObject := GetShaderModule(shaderModule) assert(shaderModuleObject.device == device) State.ShaderModules[shaderModule] = null } // Pipeline functions cmd VkResult vkCreatePipelineCache( VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO) deviceObject := GetDevice(device) pipelineCache := ? pPipelineCache[0] = pipelineCache State.PipelineCaches[pipelineCache] = new!PipelineCacheObject(device: device) return ? } cmd void vkDestroyPipelineCache( VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) pipelineCacheObject := GetPipelineCache(pipelineCache) assert(pipelineCacheObject.device == device) State.PipelineCaches[pipelineCache] = null } cmd VkResult vkGetPipelineCacheData( VkDevice device, VkPipelineCache pipelineCache, platform.size_t* pDataSize, void* pData) { deviceObject := GetDevice(device) pipelineCacheObject := GetPipelineCache(pipelineCache) assert(pipelineCacheObject.device == device) return ? } cmd VkResult vkMergePipelineCaches( VkDevice device, VkPipelineCache dstCache, u32 srcCacheCount, const VkPipelineCache* pSrcCaches) { deviceObject := GetDevice(device) dstCacheObject := GetPipelineCache(dstCache) assert(dstCacheObject.device == device) srcCaches := pSrcCaches[0:srcCacheCount] for i in (0 .. srcCacheCount) { srcCache := srcCaches[i] srcCacheObject := GetPipelineCache(srcCache) assert(srcCacheObject.device == device) } return ? } cmd VkResult vkCreateGraphicsPipelines( VkDevice device, VkPipelineCache pipelineCache, u32 createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { deviceObject := GetDevice(device) if pipelineCache != NULL_HANDLE { pipelineCacheObject := GetPipelineCache(pipelineCache) assert(pipelineCacheObject.device == device) } createInfos := pCreateInfos[0:createInfoCount] pipelines := pPipelines[0:createInfoCount] for i in (0 .. createInfoCount) { pipeline := ? pipelines[i] = pipeline State.Pipelines[pipeline] = new!PipelineObject(device: device) } return ? } cmd VkResult vkCreateComputePipelines( VkDevice device, VkPipelineCache pipelineCache, u32 createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { deviceObject := GetDevice(device) if pipelineCache != NULL_HANDLE { pipelineCacheObject := GetPipelineCache(pipelineCache) assert(pipelineCacheObject.device == device) } createInfos := pCreateInfos[0:createInfoCount] pipelines := pPipelines[0:createInfoCount] for i in (0 .. createInfoCount) { pipeline := ? pipelines[i] = pipeline State.Pipelines[pipeline] = new!PipelineObject(device: device) } return ? } @threadSafety("system") cmd void vkDestroyPipeline( VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) pipelineObjects := GetPipeline(pipeline) assert(pipelineObjects.device == device) State.Pipelines[pipeline] = null } // Pipeline layout functions @threadSafety("system") cmd VkResult vkCreatePipelineLayout( VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO) deviceObject := GetDevice(device) pipelineLayout := ? pPipelineLayout[0] = pipelineLayout State.PipelineLayouts[pipelineLayout] = new!PipelineLayoutObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyPipelineLayout( VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) pipelineLayoutObjects := GetPipelineLayout(pipelineLayout) assert(pipelineLayoutObjects.device == device) State.PipelineLayouts[pipelineLayout] = null } // Sampler functions @threadSafety("system") cmd VkResult vkCreateSampler( VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO) deviceObject := GetDevice(device) sampler := ? pSampler[0] = sampler State.Samplers[sampler] = new!SamplerObject(device: device) return ? } @threadSafety("system") cmd void vkDestroySampler( VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) samplerObject := GetSampler(sampler) assert(samplerObject.device == device) State.Samplers[sampler] = null } // Descriptor set functions @threadSafety("system") cmd VkResult vkCreateDescriptorSetLayout( VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO) deviceObject := GetDevice(device) setLayout := ? pSetLayout[0] = setLayout State.DescriptorSetLayouts[setLayout] = new!DescriptorSetLayoutObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyDescriptorSetLayout( VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) descriptorSetLayoutObject := GetDescriptorSetLayout(descriptorSetLayout) assert(descriptorSetLayoutObject.device == device) State.DescriptorSetLayouts[descriptorSetLayout] = null } @threadSafety("system") cmd VkResult vkCreateDescriptorPool( VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO) deviceObject := GetDevice(device) descriptorPool := ? pDescriptorPool[0] = descriptorPool State.DescriptorPools[descriptorPool] = new!DescriptorPoolObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyDescriptorPool( VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) descriptorPoolObject := GetDescriptorPool(descriptorPool) assert(descriptorPoolObject.device == device) State.DescriptorPools[descriptorPool] = null } @threadSafety("app") cmd VkResult vkResetDescriptorPool( VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { deviceObject := GetDevice(device) descriptorPoolObject := GetDescriptorPool(descriptorPool) assert(descriptorPoolObject.device == device) return ? } @threadSafety("app") cmd VkResult vkAllocateDescriptorSets( VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets) { deviceObject := GetDevice(device) allocInfo := pAllocateInfo[0] descriptorPoolObject := GetDescriptorPool(allocInfo.descriptorPool) setLayouts := allocInfo.pSetLayouts[0:allocInfo.setCount] for i in (0 .. allocInfo.setCount) { setLayout := setLayouts[i] setLayoutObject := GetDescriptorSetLayout(setLayout) assert(setLayoutObject.device == device) } descriptorSets := pDescriptorSets[0:allocInfo.setCount] for i in (0 .. allocInfo.setCount) { descriptorSet := ? descriptorSets[i] = descriptorSet State.DescriptorSets[descriptorSet] = new!DescriptorSetObject(device: device) } return ? } cmd VkResult vkFreeDescriptorSets( VkDevice device, VkDescriptorPool descriptorPool, u32 descriptorSetCount, const VkDescriptorSet* pDescriptorSets) { deviceObject := GetDevice(device) descriptorPoolObject := GetDescriptorPool(descriptorPool) descriptorSets := pDescriptorSets[0:descriptorSetCount] for i in (0 .. descriptorSetCount) { descriptorSet := descriptorSets[i] descriptorSetObject := GetDescriptorSet(descriptorSet) assert(descriptorSetObject.device == device) State.DescriptorSets[descriptorSet] = null } return ? } cmd void vkUpdateDescriptorSets( VkDevice device, u32 descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, u32 descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies) { deviceObject := GetDevice(device) descriptorWrites := pDescriptorWrites[0:descriptorWriteCount] for i in (0 .. descriptorWriteCount) { descriptorWrite := descriptorWrites[i] descriptorWriteObject := GetDescriptorSet(descriptorWrite.dstSet) assert(descriptorWriteObject.device == device) } descriptorCopies := pDescriptorCopies[0:descriptorCopyCount] for i in (0 .. descriptorCopyCount) { descriptorCopy := descriptorCopies[i] descriptorCopyObject := GetDescriptorSet(descriptorCopy.dstSet) assert(descriptorCopyObject.device == device) } } // Framebuffer functions @threadSafety("system") cmd VkResult vkCreateFramebuffer( VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO) deviceObject := GetDevice(device) framebuffer := ? pFramebuffer[0] = framebuffer State.Framebuffers[framebuffer] = new!FramebufferObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyFramebuffer( VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) framebufferObject := GetFramebuffer(framebuffer) assert(framebufferObject.device == device) State.Framebuffers[framebuffer] = null } // Renderpass functions @threadSafety("system") cmd VkResult vkCreateRenderPass( VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO) deviceObject := GetDevice(device) renderpass := ? pRenderPass[0] = renderpass State.RenderPasses[renderpass] = new!RenderPassObject(device: device) return ? } @threadSafety("system") cmd void vkDestroyRenderPass( VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) renderPassObject := GetRenderPass(renderPass) assert(renderPassObject.device == device) State.RenderPasses[renderPass] = null } cmd void vkGetRenderAreaGranularity( VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) { deviceObject := GetDevice(device) renderPassObject := GetRenderPass(renderPass) granularity := ? pGranularity[0] = granularity } // Command pool functions cmd VkResult vkCreateCommandPool( VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO) deviceObject := GetDevice(device) commandPool := ? pCommandPool[0] = commandPool State.CommandPools[commandPool] = new!CommandPoolObject(device: device) return ? } cmd void vkDestroyCommandPool( VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) commandPoolObject := GetCommandPool(commandPool) assert(commandPoolObject.device == device) State.CommandPools[commandPool] = null } cmd VkResult vkResetCommandPool( VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { deviceObject := GetDevice(device) commandPoolObject := GetCommandPool(commandPool) assert(commandPoolObject.device == device) return ? } // Command buffer functions macro void bindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) { memoryObject := GetDeviceMemory(memory) memoryObject.boundCommandBuffers[commandBuffer] = commandBuffer commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.boundObjects[as!u64(obj)] = memory } macro void unbindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) { memoryObject := GetDeviceMemory(memory) memoryObject.boundCommandBuffers[commandBuffer] = null commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.boundObjects[as!u64(obj)] = null } @threadSafety("system") cmd VkResult vkAllocateCommandBuffers( VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) { assert(pAllocateInfo[0].sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO) count := pAllocateInfo[0].commandBufferCount commandBuffers := pCommandBuffers[0:count] for i in (0 .. count) { commandBuffer := ? commandBuffers[i] = commandBuffer State.CommandBuffers[commandBuffer] = new!CommandBufferObject(device: device) } return ? } @threadSafety("system") cmd void vkFreeCommandBuffers( VkDevice device, VkCommandPool commandPool, u32 commandBufferCount, const VkCommandBuffer* pCommandBuffers) { deviceObject := GetDevice(device) commandBuffers := pCommandBuffers[0:commandBufferCount] for i in (0 .. commandBufferCount) { commandBufferObject := GetCommandBuffer(commandBuffers[i]) assert(commandBufferObject.device == device) // TODO: iterate over boundObjects and clear memory bindings State.CommandBuffers[commandBuffers[i]] = null } } @threadSafety("app") cmd VkResult vkBeginCommandBuffer( VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo) { assert(pBeginInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO) commandBufferObject := GetCommandBuffer(commandBuffer) // TODO: iterate over boundObjects and clear memory bindings return ? } @threadSafety("app") cmd VkResult vkEndCommandBuffer( VkCommandBuffer commandBuffer) { commandBufferObject := GetCommandBuffer(commandBuffer) return ? } @threadSafety("app") cmd VkResult vkResetCommandBuffer( VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { commandBufferObject := GetCommandBuffer(commandBuffer) // TODO: iterate over boundObjects and clear memory bindings return ? } // Command buffer building functions @threadSafety("app") cmd void vkCmdBindPipeline( VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { commandBufferObject := GetCommandBuffer(commandBuffer) pipelineObject := GetPipeline(pipeline) assert(commandBufferObject.device == pipelineObject.device) queue := switch (pipelineBindPoint) { case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT } commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue) } @threadSafety("app") cmd void vkCmdSetViewport( VkCommandBuffer commandBuffer, u32 firstViewport, u32 viewportCount, const VkViewport* pViewports) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetScissor( VkCommandBuffer commandBuffer, u32 firstScissor, u32 scissorCount, const VkRect2D* pScissors) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetLineWidth( VkCommandBuffer commandBuffer, f32 lineWidth) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetDepthBias( VkCommandBuffer commandBuffer, f32 depthBiasConstantFactor, f32 depthBiasClamp, f32 depthBiasSlopeFactor) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetBlendConstants( VkCommandBuffer commandBuffer, // TODO(jessehall): apic only supports 'const' on pointer types. Using // an annotation as a quick hack to pass this to the template without // having to modify the AST and semantic model. @readonly f32[4] blendConstants) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetDepthBounds( VkCommandBuffer commandBuffer, f32 minDepthBounds, f32 maxDepthBounds) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetStencilCompareMask( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, u32 compareMask) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetStencilWriteMask( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, u32 writeMask) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetStencilReference( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, u32 reference) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdBindDescriptorSets( VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, u32 firstSet, u32 descriptorSetCount, const VkDescriptorSet* pDescriptorSets, u32 dynamicOffsetCount, const u32* pDynamicOffsets) { commandBufferObject := GetCommandBuffer(commandBuffer) descriptorSets := pDescriptorSets[0:descriptorSetCount] for i in (0 .. descriptorSetCount) { descriptorSet := descriptorSets[i] descriptorSetObject := GetDescriptorSet(descriptorSet) assert(commandBufferObject.device == descriptorSetObject.device) } dynamicOffsets := pDynamicOffsets[0:dynamicOffsetCount] for i in (0 .. dynamicOffsetCount) { dynamicOffset := dynamicOffsets[i] } queue := switch (pipelineBindPoint) { case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT } commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue) } @threadSafety("app") cmd void vkCmdBindIndexBuffer( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { commandBufferObject := GetCommandBuffer(commandBuffer) bufferObject := GetBuffer(buffer) assert(commandBufferObject.device == bufferObject.device) bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdBindVertexBuffers( VkCommandBuffer commandBuffer, u32 firstBinding, u32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) { commandBufferObject := GetCommandBuffer(commandBuffer) // TODO: check if not [firstBinding:firstBinding+bindingCount] buffers := pBuffers[0:bindingCount] offsets := pOffsets[0:bindingCount] for i in (0 .. bindingCount) { buffer := buffers[i] offset := offsets[i] bufferObject := GetBuffer(buffer) assert(commandBufferObject.device == bufferObject.device) bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) } commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdDraw( VkCommandBuffer commandBuffer, u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdDrawIndexed( VkCommandBuffer commandBuffer, u32 indexCount, u32 instanceCount, u32 firstIndex, s32 vertexOffset, u32 firstInstance) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdDrawIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, u32 drawCount, u32 stride) { commandBufferObject := GetCommandBuffer(commandBuffer) bufferObject := GetBuffer(buffer) assert(commandBufferObject.device == bufferObject.device) bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdDrawIndexedIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, u32 drawCount, u32 stride) { commandBufferObject := GetCommandBuffer(commandBuffer) bufferObject := GetBuffer(buffer) assert(commandBufferObject.device == bufferObject.device) bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdDispatch( VkCommandBuffer commandBuffer, u32 x, u32 y, u32 z) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT) } @threadSafety("app") cmd void vkCmdDispatchIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { commandBufferObject := GetCommandBuffer(commandBuffer) bufferObject := GetBuffer(buffer) assert(commandBufferObject.device == bufferObject.device) bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT) } @threadSafety("app") cmd void vkCmdCopyBuffer( VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, u32 regionCount, const VkBufferCopy* pRegions) { commandBufferObject := GetCommandBuffer(commandBuffer) srcBufferObject := GetBuffer(srcBuffer) dstBufferObject := GetBuffer(dstBuffer) assert(commandBufferObject.device == srcBufferObject.device) assert(commandBufferObject.device == dstBufferObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory) bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdCopyImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, u32 regionCount, const VkImageCopy* pRegions) { commandBufferObject := GetCommandBuffer(commandBuffer) srcImageObject := GetImage(srcImage) dstImageObject := GetImage(dstImage) assert(commandBufferObject.device == srcImageObject.device) assert(commandBufferObject.device == dstImageObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdBlitImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, u32 regionCount, const VkImageBlit* pRegions, VkFilter filter) { commandBufferObject := GetCommandBuffer(commandBuffer) srcImageObject := GetImage(srcImage) dstImageObject := GetImage(dstImage) assert(commandBufferObject.device == srcImageObject.device) assert(commandBufferObject.device == dstImageObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdCopyBufferToImage( VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, u32 regionCount, const VkBufferImageCopy* pRegions) { commandBufferObject := GetCommandBuffer(commandBuffer) srcBufferObject := GetBuffer(srcBuffer) dstImageObject := GetImage(dstImage) assert(commandBufferObject.device == srcBufferObject.device) assert(commandBufferObject.device == dstImageObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory) bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdCopyImageToBuffer( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, u32 regionCount, const VkBufferImageCopy* pRegions) { commandBufferObject := GetCommandBuffer(commandBuffer) srcImageObject := GetImage(srcImage) dstBufferObject := GetBuffer(dstBuffer) assert(commandBufferObject.device == srcImageObject.device) assert(commandBufferObject.device == dstBufferObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdUpdateBuffer( VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const u32* pData) { commandBufferObject := GetCommandBuffer(commandBuffer) dstBufferObject := GetBuffer(dstBuffer) assert(commandBufferObject.device == dstBufferObject.device) data := pData[0:dataSize] bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdFillBuffer( VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, u32 data) { commandBufferObject := GetCommandBuffer(commandBuffer) dstBufferObject := GetBuffer(dstBuffer) assert(commandBufferObject.device == dstBufferObject.device) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) } @threadSafety("app") cmd void vkCmdClearColorImage( VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, u32 rangeCount, const VkImageSubresourceRange* pRanges) { commandBufferObject := GetCommandBuffer(commandBuffer) imageObject := GetImage(image) assert(commandBufferObject.device == imageObject.device) ranges := pRanges[0:rangeCount] for i in (0 .. rangeCount) { range := ranges[i] } bindCommandBuffer(commandBuffer, image, imageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdClearDepthStencilImage( VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, u32 rangeCount, const VkImageSubresourceRange* pRanges) { commandBufferObject := GetCommandBuffer(commandBuffer) imageObject := GetImage(image) assert(commandBufferObject.device == imageObject.device) ranges := pRanges[0:rangeCount] for i in (0 .. rangeCount) { range := ranges[i] } bindCommandBuffer(commandBuffer, image, imageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdClearAttachments( VkCommandBuffer commandBuffer, u32 attachmentCount, const VkClearAttachment* pAttachments, u32 rectCount, const VkClearRect* pRects) { commandBufferObject := GetCommandBuffer(commandBuffer) rects := pRects[0:rectCount] for i in (0 .. rectCount) { rect := rects[i] } commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdResolveImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, u32 regionCount, const VkImageResolve* pRegions) { commandBufferObject := GetCommandBuffer(commandBuffer) srcImageObject := GetImage(srcImage) dstImageObject := GetImage(dstImage) assert(commandBufferObject.device == srcImageObject.device) assert(commandBufferObject.device == dstImageObject.device) regions := pRegions[0:regionCount] for i in (0 .. regionCount) { region := regions[i] } bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } @threadSafety("app") cmd void vkCmdSetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { commandBufferObject := GetCommandBuffer(commandBuffer) eventObject := GetEvent(event) assert(commandBufferObject.device == eventObject.device) } @threadSafety("app") cmd void vkCmdResetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { commandBufferObject := GetCommandBuffer(commandBuffer) eventObject := GetEvent(event) assert(commandBufferObject.device == eventObject.device) } @threadSafety("app") cmd void vkCmdWaitEvents( VkCommandBuffer commandBuffer, u32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, u32 memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, u32 bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, u32 imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { commandBufferObject := GetCommandBuffer(commandBuffer) events := pEvents[0:eventCount] for i in (0 .. eventCount) { event := events[i] eventObject := GetEvent(event) assert(commandBufferObject.device == eventObject.device) } memoryBarriers := pMemoryBarriers[0:memoryBarrierCount] for i in (0 .. memoryBarrierCount) { memoryBarrier := memoryBarriers[i] } bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount] for i in (0 .. bufferMemoryBarrierCount) { bufferMemoryBarrier := bufferMemoryBarriers[i] bufferObject := GetBuffer(bufferMemoryBarrier.buffer) assert(bufferObject.device == commandBufferObject.device) } imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount] for i in (0 .. imageMemoryBarrierCount) { imageMemoryBarrier := imageMemoryBarriers[i] imageObject := GetImage(imageMemoryBarrier.image) assert(imageObject.device == commandBufferObject.device) } } @threadSafety("app") cmd void vkCmdPipelineBarrier( VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, u32 memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, u32 bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, u32 imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { commandBufferObject := GetCommandBuffer(commandBuffer) memoryBarriers := pMemoryBarriers[0:memoryBarrierCount] for i in (0 .. memoryBarrierCount) { memoryBarrier := memoryBarriers[i] } bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount] for i in (0 .. bufferMemoryBarrierCount) { bufferMemoryBarrier := bufferMemoryBarriers[i] bufferObject := GetBuffer(bufferMemoryBarrier.buffer) assert(bufferObject.device == commandBufferObject.device) } imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount] for i in (0 .. imageMemoryBarrierCount) { imageMemoryBarrier := imageMemoryBarriers[i] imageObject := GetImage(imageMemoryBarrier.image) assert(imageObject.device == commandBufferObject.device) } } @threadSafety("app") cmd void vkCmdBeginQuery( VkCommandBuffer commandBuffer, VkQueryPool queryPool, u32 query, VkQueryControlFlags flags) { commandBufferObject := GetCommandBuffer(commandBuffer) queryPoolObject := GetQueryPool(queryPool) assert(commandBufferObject.device == queryPoolObject.device) } @threadSafety("app") cmd void vkCmdEndQuery( VkCommandBuffer commandBuffer, VkQueryPool queryPool, u32 query) { commandBufferObject := GetCommandBuffer(commandBuffer) queryPoolObject := GetQueryPool(queryPool) assert(commandBufferObject.device == queryPoolObject.device) } @threadSafety("app") cmd void vkCmdResetQueryPool( VkCommandBuffer commandBuffer, VkQueryPool queryPool, u32 firstQuery, u32 queryCount) { commandBufferObject := GetCommandBuffer(commandBuffer) queryPoolObject := GetQueryPool(queryPool) assert(commandBufferObject.device == queryPoolObject.device) } @threadSafety("app") cmd void vkCmdWriteTimestamp( VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, u32 query) { commandBufferObject := GetCommandBuffer(commandBuffer) queryPoolObject := GetQueryPool(queryPool) assert(commandBufferObject.device == queryPoolObject.device) } @threadSafety("app") cmd void vkCmdCopyQueryPoolResults( VkCommandBuffer commandBuffer, VkQueryPool queryPool, u32 firstQuery, u32 queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { commandBufferObject := GetCommandBuffer(commandBuffer) queryPoolObject := GetQueryPool(queryPool) dstBufferObject := GetBuffer(dstBuffer) assert(commandBufferObject.device == queryPoolObject.device) assert(commandBufferObject.device == dstBufferObject.device) } cmd void vkCmdPushConstants( VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, u32 offset, u32 size, const void* pValues) { commandBufferObject := GetCommandBuffer(commandBuffer) layoutObject := GetPipelineLayout(layout) assert(commandBufferObject.device == layoutObject.device) } @threadSafety("app") cmd void vkCmdBeginRenderPass( VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { commandBufferObject := GetCommandBuffer(commandBuffer) renderPassObject := GetRenderPass(pRenderPassBegin.renderPass) framebufferObject := GetFramebuffer(pRenderPassBegin.framebuffer) assert(commandBufferObject.device == renderPassObject.device) assert(commandBufferObject.device == framebufferObject.device) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } cmd void vkCmdNextSubpass( VkCommandBuffer commandBuffer, VkSubpassContents contents) { commandBufferObject := GetCommandBuffer(commandBuffer) } @threadSafety("app") cmd void vkCmdEndRenderPass( VkCommandBuffer commandBuffer) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) } cmd void vkCmdExecuteCommands( VkCommandBuffer commandBuffer, u32 commandBufferCount, const VkCommandBuffer* pCommandBuffers) { commandBufferObject := GetCommandBuffer(commandBuffer) commandBuffers := pCommandBuffers[0:commandBufferCount] for i in (0 .. commandBufferCount) { secondaryCommandBuffer := commandBuffers[i] secondaryCommandBufferObject := GetCommandBuffer(secondaryCommandBuffer) assert(commandBufferObject.device == secondaryCommandBufferObject.device) } } @extension("VK_KHR_surface") cmd void vkDestroySurfaceKHR( VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { instanceObject := GetInstance(instance) surfaceObject := GetSurface(surface) assert(surfaceObject.instance == instance) State.Surfaces[surface] = null } @extension("VK_KHR_surface") cmd VkResult vkGetPhysicalDeviceSurfaceSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_surface") cmd VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) surfaceCapabilities := ? pSurfaceCapabilities[0] = surfaceCapabilities return ? } @extension("VK_KHR_surface") cmd VkResult vkGetPhysicalDeviceSurfaceFormatsKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, u32* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) count := as!u32(?) pSurfaceFormatCount[0] = count surfaceFormats := pSurfaceFormats[0:count] for i in (0 .. count) { surfaceFormat := ? surfaceFormats[i] = surfaceFormat } return ? } @extension("VK_KHR_surface") cmd VkResult vkGetPhysicalDeviceSurfacePresentModesKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, u32* pPresentModeCount, VkPresentModeKHR* pPresentModes) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) count := as!u32(?) pPresentModeCount[0] = count presentModes := pPresentModes[0:count] for i in (0 .. count) { presentMode := ? presentModes[i] = presentMode } return ? } @extension("VK_KHR_swapchain") cmd VkResult vkCreateSwapchainKHR( VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR) deviceObject := GetDevice(device) swapchain := ? pSwapchain[0] = swapchain State.Swapchains[swapchain] = new!SwapchainObject(device: device) return ? } @extension("VK_KHR_swapchain") cmd void vkDestroySwapchainKHR( VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { deviceObject := GetDevice(device) swapchainObject := GetSwapchain(swapchain) assert(swapchainObject.device == device) State.Swapchains[swapchain] = null } @extension("VK_KHR_swapchain") cmd VkResult vkGetSwapchainImagesKHR( VkDevice device, VkSwapchainKHR swapchain, u32* pSwapchainImageCount, VkImage* pSwapchainImages) { deviceObject := GetDevice(device) count := as!u32(?) pSwapchainImageCount[0] = count swapchainImages := pSwapchainImages[0:count] for i in (0 .. count) { swapchainImage := ? swapchainImages[i] = swapchainImage State.Images[swapchainImage] = new!ImageObject(device: device) } return ? } @extension("VK_KHR_swapchain") cmd VkResult vkAcquireNextImageKHR( VkDevice device, VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore, VkFence fence, u32* pImageIndex) { deviceObject := GetDevice(device) swapchainObject := GetSwapchain(swapchain) imageIndex := ? pImageIndex[0] = imageIndex return ? } @extension("VK_KHR_swapchain") cmd VkResult vkQueuePresentKHR( VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { queueObject := GetQueue(queue) presentInfo := ? pPresentInfo[0] = presentInfo return ? } @extension("VK_KHR_display") cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR( VkPhysicalDevice physicalDevice, u32* pPropertyCount, VkDisplayPropertiesKHR* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR( VkPhysicalDevice physicalDevice, u32* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkGetDisplayPlaneSupportedDisplaysKHR( VkPhysicalDevice physicalDevice, u32 planeIndex, u32* pDisplayCount, VkDisplayKHR* pDisplays) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkGetDisplayModePropertiesKHR( VkPhysicalDevice physicalDevice, VkDisplayKHR display, u32* pPropertyCount, VkDisplayModePropertiesKHR* pProperties) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkCreateDisplayModeKHR( VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkGetDisplayPlaneCapabilitiesKHR( VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, u32 planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_display") cmd VkResult vkCreateDisplayPlaneSurfaceKHR( VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { return ? } @extension("VK_KHR_display_swapchain") cmd VkResult vkCreateSharedSwapchainsKHR( VkDevice device, u32 swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains) { return ? } @extension("VK_KHR_xlib_surface") cmd VkResult vkCreateXlibSurfaceKHR( VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_xlib_surface") cmd VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex, platform.Display* dpy, platform.VisualID visualID) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_xcb_surface") cmd VkResult vkCreateXcbSurfaceKHR( VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_xcb_surface") cmd VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex, platform.xcb_connection_t* connection, platform.xcb_visualid_t visual_id) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_wayland_surface") cmd VkResult vkCreateWaylandSurfaceKHR( VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_wayland_surface") cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex, platform.wl_display* display) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_mir_surface") cmd VkResult vkCreateMirSurfaceKHR( VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_mir_surface") cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex, platform.MirConnection* connection) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_KHR_android_surface") cmd VkResult vkCreateAndroidSurfaceKHR( VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_win32_surface") cmd VkResult vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { instanceObject := GetInstance(instance) return ? } @extension("VK_KHR_win32_surface") cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR( VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { physicalDeviceObject := GetPhysicalDevice(physicalDevice) return ? } @extension("VK_ANDROID_native_buffer") cmd VkResult vkGetSwapchainGrallocUsageANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage) { return ? } @extension("VK_ANDROID_native_buffer") cmd VkResult vkAcquireImageANDROID( VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence) { return ? } @extension("VK_ANDROID_native_buffer") cmd VkResult vkQueueSignalReleaseImageANDROID( VkQueue queue, u32 waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd) { return ? } @extension("VK_EXT_debug_report") @external type void* PFN_vkDebugReportCallbackEXT @extension("VK_EXT_debug_report") @pfn cmd VkBool32 vkDebugReportCallbackEXT( VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, u64 object, platform.size_t location, s32 messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) { return ? } @extension("VK_EXT_debug_report") cmd VkResult vkCreateDebugReportCallbackEXT( VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) { return ? } @extension("VK_EXT_debug_report") cmd void vkDestroyDebugReportCallbackEXT( VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { } @extension("VK_EXT_debug_report") cmd void vkDebugReportMessageEXT( VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, u64 object, platform.size_t location, s32 messageCode, const char* pLayerPrefix, const char* pMessage) { } @extension("VK_EXT_debug_marker") cmd VkResult vkDebugMarkerSetObjectTagEXT( VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo) { return ? } @extension("VK_EXT_debug_marker") cmd VkResult vkDebugMarkerSetObjectNameEXT( VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo) { return ? } @extension("VK_EXT_debug_marker") cmd void vkCmdDebugMarkerBeginEXT( VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo) { } @extension("VK_EXT_debug_marker") cmd void vkCmdDebugMarkerEndEXT( VkCommandBuffer commandBuffer) { } @extension("VK_EXT_debug_marker") cmd void vkCmdDebugMarkerInsertEXT( VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo) { } //////////////// // Validation // //////////////// extern void validate(string layerName, bool condition, string message) ///////////////////////////// // Internal State Tracking // ///////////////////////////// StateObject State @internal class StateObject { // Dispatchable objects. map!(VkInstance, ref!InstanceObject) Instances map!(VkPhysicalDevice, ref!PhysicalDeviceObject) PhysicalDevices map!(VkDevice, ref!DeviceObject) Devices map!(VkQueue, ref!QueueObject) Queues map!(VkCommandBuffer, ref!CommandBufferObject) CommandBuffers // Non-dispatchable objects. map!(VkDeviceMemory, ref!DeviceMemoryObject) DeviceMemories map!(VkBuffer, ref!BufferObject) Buffers map!(VkBufferView, ref!BufferViewObject) BufferViews map!(VkImage, ref!ImageObject) Images map!(VkImageView, ref!ImageViewObject) ImageViews map!(VkShaderModule, ref!ShaderModuleObject) ShaderModules map!(VkPipeline, ref!PipelineObject) Pipelines map!(VkPipelineLayout, ref!PipelineLayoutObject) PipelineLayouts map!(VkSampler, ref!SamplerObject) Samplers map!(VkDescriptorSet, ref!DescriptorSetObject) DescriptorSets map!(VkDescriptorSetLayout, ref!DescriptorSetLayoutObject) DescriptorSetLayouts map!(VkDescriptorPool, ref!DescriptorPoolObject) DescriptorPools map!(VkFence, ref!FenceObject) Fences map!(VkSemaphore, ref!SemaphoreObject) Semaphores map!(VkEvent, ref!EventObject) Events map!(VkQueryPool, ref!QueryPoolObject) QueryPools map!(VkFramebuffer, ref!FramebufferObject) Framebuffers map!(VkRenderPass, ref!RenderPassObject) RenderPasses map!(VkPipelineCache, ref!PipelineCacheObject) PipelineCaches map!(VkCommandPool, ref!CommandPoolObject) CommandPools map!(VkSurfaceKHR, ref!SurfaceObject) Surfaces map!(VkSwapchainKHR, ref!SwapchainObject) Swapchains } @internal class InstanceObject { } @internal class PhysicalDeviceObject { VkInstance instance } @internal class DeviceObject { VkPhysicalDevice physicalDevice } @internal class QueueObject { VkDevice device VkQueueFlags flags } @internal class CommandBufferObject { VkDevice device map!(u64, VkDeviceMemory) boundObjects VkQueueFlags queueFlags } @internal class DeviceMemoryObject { VkDevice device VkDeviceSize allocationSize map!(u64, VkDeviceSize) boundObjects map!(VkCommandBuffer, VkCommandBuffer) boundCommandBuffers } @internal class BufferObject { VkDevice device VkDeviceMemory memory VkDeviceSize memoryOffset } @internal class BufferViewObject { VkDevice device VkBuffer buffer } @internal class ImageObject { VkDevice device VkDeviceMemory memory VkDeviceSize memoryOffset } @internal class ImageViewObject { VkDevice device VkImage image } @internal class ShaderObject { VkDevice device } @internal class ShaderModuleObject { VkDevice device } @internal class PipelineObject { VkDevice device } @internal class PipelineLayoutObject { VkDevice device } @internal class SamplerObject { VkDevice device } @internal class DescriptorSetObject { VkDevice device } @internal class DescriptorSetLayoutObject { VkDevice device } @internal class DescriptorPoolObject { VkDevice device } @internal class FenceObject { VkDevice device bool signaled } @internal class SemaphoreObject { VkDevice device } @internal class EventObject { VkDevice device } @internal class QueryPoolObject { VkDevice device } @internal class FramebufferObject { VkDevice device } @internal class RenderPassObject { VkDevice device } @internal class PipelineCacheObject { VkDevice device } @internal class CommandPoolObject { VkDevice device } @internal class SurfaceObject { VkInstance instance } @internal class SwapchainObject { VkDevice device } macro ref!InstanceObject GetInstance(VkInstance instance) { assert(instance in State.Instances) return State.Instances[instance] } macro ref!PhysicalDeviceObject GetPhysicalDevice(VkPhysicalDevice physicalDevice) { assert(physicalDevice in State.PhysicalDevices) return State.PhysicalDevices[physicalDevice] } macro ref!DeviceObject GetDevice(VkDevice device) { assert(device in State.Devices) return State.Devices[device] } macro ref!QueueObject GetQueue(VkQueue queue) { assert(queue in State.Queues) return State.Queues[queue] } macro ref!CommandBufferObject GetCommandBuffer(VkCommandBuffer commandBuffer) { assert(commandBuffer in State.CommandBuffers) return State.CommandBuffers[commandBuffer] } macro ref!DeviceMemoryObject GetDeviceMemory(VkDeviceMemory memory) { assert(memory in State.DeviceMemories) return State.DeviceMemories[memory] } macro ref!BufferObject GetBuffer(VkBuffer buffer) { assert(buffer in State.Buffers) return State.Buffers[buffer] } macro ref!BufferViewObject GetBufferView(VkBufferView bufferView) { assert(bufferView in State.BufferViews) return State.BufferViews[bufferView] } macro ref!ImageObject GetImage(VkImage image) { assert(image in State.Images) return State.Images[image] } macro ref!ImageViewObject GetImageView(VkImageView imageView) { assert(imageView in State.ImageViews) return State.ImageViews[imageView] } macro ref!ShaderModuleObject GetShaderModule(VkShaderModule shaderModule) { assert(shaderModule in State.ShaderModules) return State.ShaderModules[shaderModule] } macro ref!PipelineObject GetPipeline(VkPipeline pipeline) { assert(pipeline in State.Pipelines) return State.Pipelines[pipeline] } macro ref!PipelineLayoutObject GetPipelineLayout(VkPipelineLayout pipelineLayout) { assert(pipelineLayout in State.PipelineLayouts) return State.PipelineLayouts[pipelineLayout] } macro ref!SamplerObject GetSampler(VkSampler sampler) { assert(sampler in State.Samplers) return State.Samplers[sampler] } macro ref!DescriptorSetObject GetDescriptorSet(VkDescriptorSet descriptorSet) { assert(descriptorSet in State.DescriptorSets) return State.DescriptorSets[descriptorSet] } macro ref!DescriptorSetLayoutObject GetDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) { assert(descriptorSetLayout in State.DescriptorSetLayouts) return State.DescriptorSetLayouts[descriptorSetLayout] } macro ref!DescriptorPoolObject GetDescriptorPool(VkDescriptorPool descriptorPool) { assert(descriptorPool in State.DescriptorPools) return State.DescriptorPools[descriptorPool] } macro ref!FenceObject GetFence(VkFence fence) { assert(fence in State.Fences) return State.Fences[fence] } macro ref!SemaphoreObject GetSemaphore(VkSemaphore semaphore) { assert(semaphore in State.Semaphores) return State.Semaphores[semaphore] } macro ref!EventObject GetEvent(VkEvent event) { assert(event in State.Events) return State.Events[event] } macro ref!QueryPoolObject GetQueryPool(VkQueryPool queryPool) { assert(queryPool in State.QueryPools) return State.QueryPools[queryPool] } macro ref!FramebufferObject GetFramebuffer(VkFramebuffer framebuffer) { assert(framebuffer in State.Framebuffers) return State.Framebuffers[framebuffer] } macro ref!RenderPassObject GetRenderPass(VkRenderPass renderPass) { assert(renderPass in State.RenderPasses) return State.RenderPasses[renderPass] } macro ref!PipelineCacheObject GetPipelineCache(VkPipelineCache pipelineCache) { assert(pipelineCache in State.PipelineCaches) return State.PipelineCaches[pipelineCache] } macro ref!CommandPoolObject GetCommandPool(VkCommandPool commandPool) { assert(commandPool in State.CommandPools) return State.CommandPools[commandPool] } macro ref!SurfaceObject GetSurface(VkSurfaceKHR surface) { assert(surface in State.Surfaces) return State.Surfaces[surface] } macro ref!SwapchainObject GetSwapchain(VkSwapchainKHR swapchain) { assert(swapchain in State.Swapchains) return State.Swapchains[swapchain] } macro VkQueueFlags AddQueueFlag(VkQueueFlags flags, VkQueueFlagBits bit) { return as!VkQueueFlags(as!u32(flags) | as!u32(bit)) } vulkan/doc/0040755 0000000 0000000 00000000000 13077405420 011657 5ustar000000000 0000000 vulkan/doc/implementors_guide/0040755 0000000 0000000 00000000000 13077405420 015552 5ustar000000000 0000000 vulkan/doc/implementors_guide/implementors_guide-docinfo.adoc0100644 0000000 0000000 00000000323 13077405420 023707 0ustar000000000 0000000 vulkan/doc/implementors_guide/implementors_guide.adoc0100644 0000000 0000000 00000031507 13077405420 022300 0ustar000000000 0000000 // asciidoc -b html5 -d book -f implementors_guide.conf implementors_guide.adoc = Vulkan on Android Implementor's Guide = :toc: right :numbered: :revnumber: 5 This document is intended for GPU IHVs writing Vulkan drivers for Android, and OEMs integrating them for specific devices. It describes how a Vulkan driver interacts with the system, how GPU-specific tools should be installed, and Android-specific requirements. == Architecture == The primary interface between Vulkan applications and a device's Vulkan driver is the loader, which is part of AOSP and installed at +/system/lib[64]/libvulkan.so+. The loader provides the core Vulkan API entry points, as well as entry points of a few extensions that are required on Android and always present. In particular, the window system integration (WSI) extensions are exported by the loader and primarily implemented in it rather than the driver. The loader also supports enumerating and loading layers which can expose additional extensions and/or intercept core API calls on their way to the driver. The NDK will include a stub +libvulkan.so+ exporting the same symbols as the loader. Calling the Vulkan functions exported from +libvulkan.so+ will enter trampoline functions in the loader which will dispatch to the appropriate layer or driver based on their first argument. The +vkGet*ProcAddr+ calls will return the function pointers that the trampolines would dispatch to, so calling through these function pointers rather than the exported symbols will be slightly more efficient since it skips the trampoline and dispatch. === Driver Enumeration and Loading === Android expects the GPUs available to the system to be known when the system image is built, so its driver enumeration process isn't as elaborate as on other platforms. The loader will use the existing HAL mechanism for discovering and loading the driver. As of this writing, the preferred paths for 32-bit and 64-bit Vulkan drivers are: /vendor/lib/hw/vulkan..so /vendor/lib64/hw/vulkan..so where ++ is replaced by the value of the system property of that name. See https://android.googlesource.com/platform/hardware/libhardware/+/master/hardware.c[libhardware/hardware.c] for details and supported alternative locations. The Vulkan +hw_module_t+ derivative is currently trivial. If support for multiple drivers is ever added, the HAL module will export a list of strings that can be passed to the module +open+ call. For the time being, only one driver is supported, and the constant string +HWVULKAN_DEVICE_0+ is passed to +open+. The Vulkan +hw_device_t+ derivative corresponds to a single driver, though that driver can support multiple Vulkan physical devices. The +hw_device_t+ structure contains a function pointer for the +vkGetInstanceProcAddr+ function. The loader finds all other driver Vulkan functions by calling that +vkGetInstanceProcAddr+ function. === Layer Discovery and Loading === Android's security model and policies differ significantly from other platforms. In particular, Android does not allow loading external code into a non-debuggable process on production (non-rooted) devices, nor does it allow external code to inspect or control the process's memory/state/etc. This includes a prohibition on saving core dumps, API traces, etc. to disk for later inspection. So only layers delivered as part of the application will be enabled on production devices, and drivers must also not provide functionality that violates these policies. There are three major use cases for layers: 1. Development-time layers: validation layers, shims for tracing/profiling/debugging tools, etc. These shouldn't be installed on the system image of production devices: they would be a waste of space for most users, and they should be updateable without requiring a system update. A developer wishing to use one of these during development has the ability to modify their application package (e.g. adding a file to their native libraries directory). IHV and OEM engineers who are trying to diagnose failures in shipping, unmodifiable apps are assumed to have access to non-production (rooted) builds of the system image. 2. Utility layers, such as a layer that implements a heap for device memory. These layers will almost always expose extensions. Developers choose which layers, and which versions of those layers, to use in their application; different applications that use the same layer may still use different versions. Developers will choose which of these layers to ship in their application package. 3. Injected layers, like framerate, social network, or game launcher overlays, which are provided by the user or some other application without the application's knowledge or consent. These violate Android's security policies and will not be supported. In the normal state the loader will only search in the application's normal library search path (as defined by the system ClassLoader) for layers. It will attempt to load any shared library named +libVkLayer_*.so+ as a layer library. Android does not use manifests to describe layers: because layers must have been deliberately included in the application by the developer, the motivation for manifests on other platforms don't apply. On debuggable devices (+ro.debuggable+ property exists and is non-zero, generally rooted or engineering builds) the loader will also search the directory +/data/local/debug/vulkan+ and attempt to load layer libraries it finds there. This directory doesn't exist by default. On Android N and later, because this location is writable by adb, SELinux policies prevent mapping code located here as executable. So to use layers from here, SELinux enforcement must be disabled: +adb shell setenforce 0+. This mechanism is not intended for application developers, only for IHV and OEM engineers working on test devices that don't have private or sensitive data. Our goal is to allow layers to be ported with only build-environment changes between Android and other platforms. For this to work, layers must properly implement things like +vkGetInstanceLayerProperties+ and +vkGetInstanceExtensionProperties+, even though the LunarG loader doesn't use them (it gets the information from manifests instead). == Window System Integration == The +vk_wsi_swapchin+ and +vk_wsi_device_swapchain+ extensions are primarily be implemented by the platform and live in +libvulkan.so+. The +VkSwapchain+ object and all interaction with +ANativeWindow+ will be handled by the platform and not exposed to drivers. The WSI implementation will rely on a few private interfaces to the driver for this implementation. These will be loaded through the driver's +vkGetDeviceProcAddr+ functions, after passing through any enabled layers. Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling [source,c] ---- VkResult VKAPI vkGetSwapchainGrallocUsageANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage ); ---- The +format+ and +imageUsage+ parameters are taken from the +VkSwapchainCreateInfoKHR+ structure. The driver should fill +*grallocUsage+ with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers. +VkNativeBufferANDROID+ is a +vkCreateImage+ extension structure for creating an image backed by a gralloc buffer. This structure is provided to +vkCreateImage+ in the +VkImageCreateInfo+ structure chain. Calls to +vkCreateImage+ with this structure will happen during the first call to +vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..)+. The WSI implementation will allocate the number of native buffers requested for the swapchain, then create a +VkImage+ for each one. [source,c] ---- typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID const void* pNext; // Buffer handle and stride returned from gralloc alloc() buffer_handle_t handle; int stride; // Gralloc format and usage requested when the buffer was allocated. int format; int usage; } VkNativeBufferANDROID; ---- When creating a gralloc-backed image, the +VkImageCreateInfo+ will have: ---- .imageType = VK_IMAGE_TYPE_2D .format = a VkFormat matching the format requested for the gralloc buffer .extent = the 2D dimensions requested for the gralloc buffer .mipLevels = 1 .arraySize = 1 .samples = 1 .tiling = VK_IMAGE_TILING_OPTIMAL .usage = VkSwapChainCreateInfoWSI::imageUsageFlags .flags = 0 .sharingMode = VkSwapChainCreateInfoWSI::sharingMode .queueFamilyCount = VkSwapChainCreateInfoWSI::queueFamilyCount .pQueueFamilyIndices = VkSwapChainCreateInfoWSI::pQueueFamilyIndices ---- +vkAcquireImageANDROID+ acquires ownership of a swapchain image and imports an externally-signalled native fence into both an existing VkSemaphore object and an existing VkFence object: [source,c] ---- VkResult VKAPI vkAcquireImageANDROID( VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence ); ---- This function is called during +vkAcquireNextImageWSI+ to import a native fence into the +VkSemaphore+ and +VkFence+ objects provided by the application. Both semaphore and fence objects are optional in this call. The driver may also use this opportunity to recognize and handle any external changes to the gralloc buffer state; many drivers won't need to do anything here. This call puts the +VkSemaphore+ and +VkFence+ into the same "pending" state as +vkQueueSignalSemaphore+ and +vkQueueSubmit+ respectively, so queues can wait on the semaphore and the application can wait on the fence. Both objects become signalled when the underlying native fence signals; if the native fence has already signalled, then the semaphore will be in the signalled state when this function returns. The driver takes ownership of the fence fd and is responsible for closing it when no longer needed. It must do so even if neither a semaphore or fence object is provided, or even if +vkAcquireImageANDROID+ fails and returns an error. If +fenceFd+ is -1, it is as if the native fence was already signalled. +vkQueueSignalReleaseImageANDROID+ prepares a swapchain image for external use, and creates a native fence and schedules it to be signalled when prior work on the queue has completed. [source,c] ---- VkResult VKAPI vkQueueSignalReleaseImageANDROID( VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd ); ---- This will be called during +vkQueuePresentWSI+ on the provided queue. Effects are similar to +vkQueueSignalSemaphore+, except with a native fence instead of a semaphore. The native fence must: not signal until the +waitSemaphoreCount+ semaphores in +pWaitSemaphores+ have signaled. Unlike +vkQueueSignalSemaphore+, however, this call creates and returns the synchronization object that will be signalled rather than having it provided as input. If the queue is already idle when this function is called, it is allowed but not required to set +*pNativeFenceFd+ to -1. The file descriptor returned in +*pNativeFenceFd+ is owned and will be closed by the caller. Many drivers will be able to ignore the +image+ parameter, but some may need to prepare CPU-side data structures associated with a gralloc buffer for use by external image consumers. Preparing buffer contents for use by external consumers should have been done asynchronously as part of transitioning the image to +VK_IMAGE_LAYOUT_PRESENT_SRC_KHR+. == History == . *2015-07-08* Initial version . *2015-08-16* * Renamed to Implementor's Guide * Wording and formatting changes * Updated based on resolution of Khronos bug 14265 * Deferred support for multiple drivers . *2015-11-04* * Added vkGetSwapchainGrallocUsageANDROID * Replaced vkImportNativeFenceANDROID and vkQueueSignalNativeFenceANDROID with vkAcquireImageANDROID and vkQueueSignalReleaseImageANDROID, to allow drivers to known the ownership state of swapchain images. . *2015-12-03* * Added a VkFence parameter to vkAcquireImageANDROID corresponding to the parameter added to vkAcquireNextImageKHR. . *2016-01-08* * Added waitSemaphoreCount and pWaitSemaphores parameters to vkQueueSignalReleaseImageANDROID. . *2016-06-17* * Updates to reflect final behavior, closed some TBDs now that they've BDed.vulkan/doc/implementors_guide/implementors_guide.conf0100644 0000000 0000000 00000000067 13077405420 022314 0ustar000000000 0000000 [attributes] newline=\n [replacements] \+\/-=± vulkan/doc/implementors_guide/implementors_guide.html0100644 0000000 0000000 00000106402 13077405420 022333 0ustar000000000 0000000 Vulkan on Android Implementor’s Guide

This document is intended for GPU IHVs writing Vulkan drivers for Android, and OEMs integrating them for specific devices. It describes how a Vulkan driver interacts with the system, how GPU-specific tools should be installed, and Android-specific requirements.

1. Architecture

The primary interface between Vulkan applications and a device’s Vulkan driver is the loader, which is part of AOSP and installed at /system/lib[64]/libvulkan.so. The loader provides the core Vulkan API entry points, as well as entry points of a few extensions that are required on Android and always present. In particular, the window system integration (WSI) extensions are exported by the loader and primarily implemented in it rather than the driver. The loader also supports enumerating and loading layers which can expose additional extensions and/or intercept core API calls on their way to the driver.

The NDK will include a stub libvulkan.so exporting the same symbols as the loader. Calling the Vulkan functions exported from libvulkan.so will enter trampoline functions in the loader which will dispatch to the appropriate layer or driver based on their first argument. The vkGet*ProcAddr calls will return the function pointers that the trampolines would dispatch to, so calling through these function pointers rather than the exported symbols will be slightly more efficient since it skips the trampoline and dispatch.

1.1. Driver Enumeration and Loading

Android expects the GPUs available to the system to be known when the system image is built, so its driver enumeration process isn’t as elaborate as on other platforms. The loader will use the existing HAL mechanism for discovering and loading the driver. As of this writing, the preferred paths for 32-bit and 64-bit Vulkan drivers are:

/vendor/lib/hw/vulkan.<ro.product.platform>.so
/vendor/lib64/hw/vulkan.<ro.product.platform>.so

The Vulkan hw_module_t derivative is currently trivial. If support for multiple drivers is ever added, the HAL module will export a list of strings that can be passed to the module open call. For the time being, only one driver is supported, and the constant string HWVULKAN_DEVICE_0 is passed to open.

The Vulkan hw_device_t derivative corresponds to a single driver, though that driver can support multiple Vulkan physical devices. The hw_device_t structure contains a function pointer for the vkGetInstanceProcAddr function. The loader finds all other driver Vulkan functions by calling that vkGetInstanceProcAddr function.

1.2. Layer Discovery and Loading

Android’s security model and policies differ significantly from other platforms. In particular, Android does not allow loading external code into a non-debuggable process on production (non-rooted) devices, nor does it allow external code to inspect or control the process’s memory/state/etc. This includes a prohibition on saving core dumps, API traces, etc. to disk for later inspection. So only layers delivered as part of the application will be enabled on production devices, and drivers must also not provide functionality that violates these policies.

There are three major use cases for layers:

  1. Development-time layers: validation layers, shims for tracing/profiling/debugging tools, etc. These shouldn’t be installed on the system image of production devices: they would be a waste of space for most users, and they should be updateable without requiring a system update. A developer wishing to use one of these during development has the ability to modify their application package (e.g. adding a file to their native libraries directory). IHV and OEM engineers who are trying to diagnose failures in shipping, unmodifiable apps are assumed to have access to non-production (rooted) builds of the system image.

  2. Utility layers, such as a layer that implements a heap for device memory. These layers will almost always expose extensions. Developers choose which layers, and which versions of those layers, to use in their application; different applications that use the same layer may still use different versions. Developers will choose which of these layers to ship in their application package.

  3. Injected layers, like framerate, social network, or game launcher overlays, which are provided by the user or some other application without the application’s knowledge or consent. These violate Android’s security policies and will not be supported.

In the normal state the loader will only search in the application’s normal library search path (as defined by the system ClassLoader) for layers. It will attempt to load any shared library named libVkLayer_*.so as a layer library. Android does not use manifests to describe layers: because layers must have been deliberately included in the application by the developer, the motivation for manifests on other platforms don’t apply.

On debuggable devices (ro.debuggable property exists and is non-zero, generally rooted or engineering builds) the loader will also search the directory /data/local/debug/vulkan and attempt to load layer libraries it finds there. This directory doesn’t exist by default. On Android N and later, because this location is writable by adb, SELinux policies prevent mapping code located here as executable. So to use layers from here, SELinux enforcement must be disabled: adb shell setenforce 0. This mechanism is not intended for application developers, only for IHV and OEM engineers working on test devices that don’t have private or sensitive data.

Our goal is to allow layers to be ported with only build-environment changes between Android and other platforms. For this to work, layers must properly implement things like vkGetInstanceLayerProperties and vkGetInstanceExtensionProperties, even though the LunarG loader doesn’t use them (it gets the information from manifests instead).

2. Window System Integration

The vk_wsi_swapchin and vk_wsi_device_swapchain extensions are primarily be implemented by the platform and live in libvulkan.so. The VkSwapchain object and all interaction with ANativeWindow will be handled by the platform and not exposed to drivers. The WSI implementation will rely on a few private interfaces to the driver for this implementation. These will be loaded through the driver’s vkGetDeviceProcAddr functions, after passing through any enabled layers.

Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling

VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
    VkDevice            device,
    VkFormat            format,
    VkImageUsageFlags   imageUsage,
    int*                grallocUsage
);

The format and imageUsage parameters are taken from the VkSwapchainCreateInfoKHR structure. The driver should fill *grallocUsage with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers.

VkNativeBufferANDROID is a vkCreateImage extension structure for creating an image backed by a gralloc buffer. This structure is provided to vkCreateImage in the VkImageCreateInfo structure chain. Calls to vkCreateImage with this structure will happen during the first call to vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..). The WSI implementation will allocate the number of native buffers requested for the swapchain, then create a VkImage for each one.

typedef struct {
    VkStructureType             sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID
    const void*                 pNext;

    // Buffer handle and stride returned from gralloc alloc()
    buffer_handle_t             handle;
    int                         stride;

    // Gralloc format and usage requested when the buffer was allocated.
    int                         format;
    int                         usage;
} VkNativeBufferANDROID;

When creating a gralloc-backed image, the VkImageCreateInfo will have:

  .imageType           = VK_IMAGE_TYPE_2D
  .format              = a VkFormat matching the format requested for the gralloc buffer
  .extent              = the 2D dimensions requested for the gralloc buffer
  .mipLevels           = 1
  .arraySize           = 1
  .samples             = 1
  .tiling              = VK_IMAGE_TILING_OPTIMAL
  .usage               = VkSwapChainCreateInfoWSI::imageUsageFlags
  .flags               = 0
  .sharingMode         = VkSwapChainCreateInfoWSI::sharingMode
  .queueFamilyCount    = VkSwapChainCreateInfoWSI::queueFamilyCount
  .pQueueFamilyIndices = VkSwapChainCreateInfoWSI::pQueueFamilyIndices

vkAcquireImageANDROID acquires ownership of a swapchain image and imports an externally-signalled native fence into both an existing VkSemaphore object and an existing VkFence object:

VkResult VKAPI vkAcquireImageANDROID(
    VkDevice            device,
    VkImage             image,
    int                 nativeFenceFd,
    VkSemaphore         semaphore,
    VkFence             fence
);

This function is called during vkAcquireNextImageWSI to import a native fence into the VkSemaphore and VkFence objects provided by the application. Both semaphore and fence objects are optional in this call. The driver may also use this opportunity to recognize and handle any external changes to the gralloc buffer state; many drivers won’t need to do anything here. This call puts the VkSemaphore and VkFence into the same "pending" state as vkQueueSignalSemaphore and vkQueueSubmit respectively, so queues can wait on the semaphore and the application can wait on the fence. Both objects become signalled when the underlying native fence signals; if the native fence has already signalled, then the semaphore will be in the signalled state when this function returns. The driver takes ownership of the fence fd and is responsible for closing it when no longer needed. It must do so even if neither a semaphore or fence object is provided, or even if vkAcquireImageANDROID fails and returns an error. If fenceFd is -1, it is as if the native fence was already signalled.

vkQueueSignalReleaseImageANDROID prepares a swapchain image for external use, and creates a native fence and schedules it to be signalled when prior work on the queue has completed.

VkResult VKAPI vkQueueSignalReleaseImageANDROID(
    VkQueue             queue,
    uint32_t            waitSemaphoreCount,
    const VkSemaphore*  pWaitSemaphores,
    VkImage             image,
    int*                pNativeFenceFd
);

This will be called during vkQueuePresentWSI on the provided queue. Effects are similar to vkQueueSignalSemaphore, except with a native fence instead of a semaphore. The native fence must: not signal until the waitSemaphoreCount semaphores in pWaitSemaphores have signaled. Unlike vkQueueSignalSemaphore, however, this call creates and returns the synchronization object that will be signalled rather than having it provided as input. If the queue is already idle when this function is called, it is allowed but not required to set *pNativeFenceFd to -1. The file descriptor returned in *pNativeFenceFd is owned and will be closed by the caller. Many drivers will be able to ignore the image parameter, but some may need to prepare CPU-side data structures associated with a gralloc buffer for use by external image consumers. Preparing buffer contents for use by external consumers should have been done asynchronously as part of transitioning the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

3. History

  1. 2015-07-08 Initial version

  2. 2015-08-16

    • Renamed to Implementor’s Guide

    • Wording and formatting changes

    • Updated based on resolution of Khronos bug 14265

    • Deferred support for multiple drivers

  3. 2015-11-04

    • Added vkGetSwapchainGrallocUsageANDROID

    • Replaced vkImportNativeFenceANDROID and vkQueueSignalNativeFenceANDROID with vkAcquireImageANDROID and vkQueueSignalReleaseImageANDROID, to allow drivers to known the ownership state of swapchain images.

  4. 2015-12-03

    • Added a VkFence parameter to vkAcquireImageANDROID corresponding to the parameter added to vkAcquireNextImageKHR.

  5. 2016-01-08

    • Added waitSemaphoreCount and pWaitSemaphores parameters to vkQueueSignalReleaseImageANDROID.

  6. 2016-06-17

    • Updates to reflect final behavior, closed some TBDs now that they’ve BDed.


vulkan/include/0040755 0000000 0000000 00000000000 13077405420 012535 5ustar000000000 0000000 vulkan/include/hardware/0040755 0000000 0000000 00000000000 13077405420 014332 5ustar000000000 0000000 vulkan/include/hardware/hwvulkan.h0100644 0000000 0000000 00000005047 13077405420 016345 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_HWVULKAN_H #define ANDROID_HWVULKAN_H #include #include __BEGIN_DECLS #define HWVULKAN_HARDWARE_MODULE_ID "vulkan" #define HWVULKAN_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1) #define HWVULKAN_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION_2(0, 1, 0) #define HWVULKAN_DEVICE_0 "vk0" typedef struct hwvulkan_module_t { struct hw_module_t common; } hwvulkan_module_t; /* Dispatchable Vulkan object handles must be pointers, which must point to * instances of hwvulkan_dispatch_t (potentially followed by additional * implementation-defined data). On return from the creation function, the * 'magic' field must contain HWVULKAN_DISPATCH_MAGIC; the loader will overwrite * the 'vtbl' field. * * NOTE: The magic value and the layout of hwvulkan_dispatch_t match the LunarG * loader used on platforms, to avoid pointless annoying differences for * multi-platform drivers. Don't change them without a good reason. If there is * an opportunity to change it, using a magic value that doesn't leave the * upper 32-bits zero on 64-bit platforms would be nice. */ #define HWVULKAN_DISPATCH_MAGIC 0x01CDC0DE typedef union { uintptr_t magic; const void* vtbl; } hwvulkan_dispatch_t; /* A hwvulkan_device_t corresponds to an ICD on other systems. Currently there * can only be one on a system (HWVULKAN_DEVICE_0). It is opened once per * process when the Vulkan API is first used; the hw_device_t::close() function * is never called. Any non-trivial resource allocation should be done when * the VkInstance is created rather than when the hwvulkan_device_t is opened. */ typedef struct hwvulkan_device_t { struct hw_device_t common; PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkCreateInstance CreateInstance; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; } hwvulkan_device_t; __END_DECLS #endif // ANDROID_HWVULKAN_H vulkan/include/vulkan/0040755 0000000 0000000 00000000000 13077405420 014035 5ustar000000000 0000000 vulkan/include/vulkan/vk_android_native_buffer.h0100644 0000000 0000000 00000006402 13077405420 021224 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __VK_ANDROID_NATIVE_BUFFER_H__ #define __VK_ANDROID_NATIVE_BUFFER_H__ #include #include #ifdef __cplusplus extern "C" { #endif #define VK_ANDROID_native_buffer 1 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER 11 #define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 5 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer" #define VK_ANDROID_NATIVE_BUFFER_ENUM(type,id) ((type)(1000000000 + (1000 * (VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER - 1)) + (id))) #define VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 0) typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID const void* pNext; // Buffer handle and stride returned from gralloc alloc() buffer_handle_t handle; int stride; // Gralloc format and usage requested when the buffer was allocated. int format; int usage; } VkNativeBufferANDROID; typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); typedef VkResult (VKAPI_PTR *PFN_vkQueueSignalReleaseImageANDROID)(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsageANDROID( VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage ); VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID( VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence ); VKAPI_ATTR VkResult VKAPI_CALL vkQueueSignalReleaseImageANDROID( VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd ); // -- DEPRECATED -- VKAPI_ATTR VkResult VKAPI_CALL vkImportNativeFenceANDROID( VkDevice device, VkSemaphore semaphore, int nativeFenceFd ); VKAPI_ATTR VkResult VKAPI_CALL vkQueueSignalNativeFenceANDROID( VkQueue queue, int* pNativeFenceFd ); // ---------------- #endif #ifdef __cplusplus } #endif #endif // __VK_ANDROID_NATIVE_BUFFER_H__ vulkan/include/vulkan/vk_layer_interface.h0100644 0000000 0000000 00000005436 13077405420 020047 0ustar000000000 0000000 /* * Copyright (c) 2015-2016 The Khronos Group Inc. * Copyright (c) 2015-2016 Valve Corporation * Copyright (c) 2015-2016 LunarG, Inc. * Copyright (c) 2016 Google Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and/or associated documentation files (the "Materials"), to * deal in the Materials without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Materials, and to permit persons to whom the Materials are * furnished to do so, subject to the following conditions: * * The above copyright notice(s) and this permission notice shall be included in * all copies or substantial portions of the Materials. * * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE * USE OR OTHER DEALINGS IN THE MATERIALS. * */ #pragma once #include // ------------------------------------------------------------------------------------------------ // CreateInstance and CreateDevice support structures typedef enum VkLayerFunction_ { VK_LAYER_FUNCTION_LINK = 0, VK_LAYER_FUNCTION_DATA_CALLBACK = 1 } VkLayerFunction; typedef struct VkLayerInstanceLink_ { struct VkLayerInstanceLink_* pNext; PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; } VkLayerInstanceLink; typedef VkResult(VKAPI_PTR* PFN_vkSetInstanceLoaderData)(VkInstance instance, void* object); typedef VkResult(VKAPI_PTR* PFN_vkSetDeviceLoaderData)(VkDevice device, void* object); typedef struct { VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO const void* pNext; VkLayerFunction function; union { VkLayerInstanceLink* pLayerInfo; PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData; } u; } VkLayerInstanceCreateInfo; typedef struct VkLayerDeviceLink_ { struct VkLayerDeviceLink_* pNext; PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr; } VkLayerDeviceLink; typedef struct { VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO const void* pNext; VkLayerFunction function; union { VkLayerDeviceLink* pLayerInfo; PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData; } u; } VkLayerDeviceCreateInfo; vulkan/include/vulkan/vk_platform.h0100644 0000000 0000000 00000007434 13077405420 016537 0ustar000000000 0000000 // // File: vk_platform.h // /* ** Copyright (c) 2014-2015 The Khronos Group Inc. ** ** 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 VK_PLATFORM_H_ #define VK_PLATFORM_H_ #ifdef __cplusplus extern "C" { #endif // __cplusplus /* *************************************************************************************************** * Platform-specific directives and type declarations *************************************************************************************************** */ /* Platform-specific calling convention macros. * * Platforms should define these so that Vulkan clients call Vulkan commands * with the same calling conventions that the Vulkan implementation expects. * * VKAPI_ATTR - Placed before the return type in function declarations. * Useful for C++11 and GCC/Clang-style function attribute syntax. * VKAPI_CALL - Placed after the return type in function declarations. * Useful for MSVC-style calling convention syntax. * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. * * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); */ #if defined(_WIN32) // On Windows, Vulkan commands use the stdcall convention #define VKAPI_ATTR #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) // Android does not support Vulkan in native code using the "armeabi" ABI. #error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs" #elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__) // On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling // convention, even if the application's native code is compiled with the // armeabi-v7a calling convention. #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) #define VKAPI_CALL #define VKAPI_PTR VKAPI_ATTR #else // On other platforms, use the default calling convention #define VKAPI_ATTR #define VKAPI_CALL #define VKAPI_PTR #endif #include #if !defined(VK_NO_STDINT_H) #if defined(_MSC_VER) && (_MSC_VER < 1600) typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #endif #endif // !defined(VK_NO_STDINT_H) #ifdef __cplusplus } // extern "C" #endif // __cplusplus // Platform-specific headers required by platform window system extensions. // These are enabled prior to #including "vulkan.h". The same enable then // controls inclusion of the extension interfaces in vulkan.h. #ifdef VK_USE_PLATFORM_ANDROID_KHR #include #endif #ifdef VK_USE_PLATFORM_MIR_KHR #include #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR #include #endif #ifdef VK_USE_PLATFORM_WIN32_KHR #include #endif #ifdef VK_USE_PLATFORM_XLIB_KHR #include #endif #ifdef VK_USE_PLATFORM_XCB_KHR #include #endif #endif vulkan/include/vulkan/vulkan.h0100644 0000000 0000000 00000553650 13077405420 015521 0ustar000000000 0000000 #ifndef VULKAN_H_ #define VULKAN_H_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2015-2016 The Khronos Group Inc. ** ** 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. */ /* ** This header is generated from the Khronos Vulkan XML API Registry. ** */ #define VK_VERSION_1_0 1 #include "vk_platform.h" #define VK_MAKE_VERSION(major, minor, patch) \ (((major) << 22) | ((minor) << 12) | (patch)) // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. //#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Vulkan 1.0 version number #define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0) #define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) // Version of this file #define VK_HEADER_VERSION 13 #define VK_NULL_HANDLE 0 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; #if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; #else #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; #endif typedef uint32_t VkFlags; typedef uint32_t VkBool32; typedef uint64_t VkDeviceSize; typedef uint32_t VkSampleMask; VK_DEFINE_HANDLE(VkInstance) VK_DEFINE_HANDLE(VkPhysicalDevice) VK_DEFINE_HANDLE(VkDevice) VK_DEFINE_HANDLE(VkQueue) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) VK_DEFINE_HANDLE(VkCommandBuffer) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) #define VK_LOD_CLAMP_NONE 1000.0f #define VK_REMAINING_MIP_LEVELS (~0U) #define VK_REMAINING_ARRAY_LAYERS (~0U) #define VK_WHOLE_SIZE (~0ULL) #define VK_ATTACHMENT_UNUSED (~0U) #define VK_TRUE 1 #define VK_FALSE 0 #define VK_QUEUE_FAMILY_IGNORED (~0U) #define VK_SUBPASS_EXTERNAL (~0U) #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 #define VK_UUID_SIZE 16 #define VK_MAX_MEMORY_TYPES 32 #define VK_MAX_MEMORY_HEAPS 16 #define VK_MAX_EXTENSION_NAME_SIZE 256 #define VK_MAX_DESCRIPTION_SIZE 256 typedef enum VkPipelineCacheHeaderVersion { VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheHeaderVersion; typedef enum VkResult { VK_SUCCESS = 0, VK_NOT_READY = 1, VK_TIMEOUT = 2, VK_EVENT_SET = 3, VK_EVENT_RESET = 4, VK_INCOMPLETE = 5, VK_ERROR_OUT_OF_HOST_MEMORY = -1, VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, VK_ERROR_INITIALIZATION_FAILED = -3, VK_ERROR_DEVICE_LOST = -4, VK_ERROR_MEMORY_MAP_FAILED = -5, VK_ERROR_LAYER_NOT_PRESENT = -6, VK_ERROR_EXTENSION_NOT_PRESENT = -7, VK_ERROR_FEATURE_NOT_PRESENT = -8, VK_ERROR_INCOMPATIBLE_DRIVER = -9, VK_ERROR_TOO_MANY_OBJECTS = -10, VK_ERROR_FORMAT_NOT_SUPPORTED = -11, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, VK_ERROR_OUT_OF_DATE_KHR = -1000001004, VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, VK_RESULT_BEGIN_RANGE = VK_ERROR_FORMAT_NOT_SUPPORTED, VK_RESULT_END_RANGE = VK_INCOMPLETE, VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FORMAT_NOT_SUPPORTED + 1), VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; typedef enum VkStructureType { VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; typedef enum VkSystemAllocationScope { VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF } VkSystemAllocationScope; typedef enum VkInternalAllocationType { VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF } VkInternalAllocationType; typedef enum VkFormat { VK_FORMAT_UNDEFINED = 0, VK_FORMAT_R4G4_UNORM_PACK8 = 1, VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, VK_FORMAT_R8_UNORM = 9, VK_FORMAT_R8_SNORM = 10, VK_FORMAT_R8_USCALED = 11, VK_FORMAT_R8_SSCALED = 12, VK_FORMAT_R8_UINT = 13, VK_FORMAT_R8_SINT = 14, VK_FORMAT_R8_SRGB = 15, VK_FORMAT_R8G8_UNORM = 16, VK_FORMAT_R8G8_SNORM = 17, VK_FORMAT_R8G8_USCALED = 18, VK_FORMAT_R8G8_SSCALED = 19, VK_FORMAT_R8G8_UINT = 20, VK_FORMAT_R8G8_SINT = 21, VK_FORMAT_R8G8_SRGB = 22, VK_FORMAT_R8G8B8_UNORM = 23, VK_FORMAT_R8G8B8_SNORM = 24, VK_FORMAT_R8G8B8_USCALED = 25, VK_FORMAT_R8G8B8_SSCALED = 26, VK_FORMAT_R8G8B8_UINT = 27, VK_FORMAT_R8G8B8_SINT = 28, VK_FORMAT_R8G8B8_SRGB = 29, VK_FORMAT_B8G8R8_UNORM = 30, VK_FORMAT_B8G8R8_SNORM = 31, VK_FORMAT_B8G8R8_USCALED = 32, VK_FORMAT_B8G8R8_SSCALED = 33, VK_FORMAT_B8G8R8_UINT = 34, VK_FORMAT_B8G8R8_SINT = 35, VK_FORMAT_B8G8R8_SRGB = 36, VK_FORMAT_R8G8B8A8_UNORM = 37, VK_FORMAT_R8G8B8A8_SNORM = 38, VK_FORMAT_R8G8B8A8_USCALED = 39, VK_FORMAT_R8G8B8A8_SSCALED = 40, VK_FORMAT_R8G8B8A8_UINT = 41, VK_FORMAT_R8G8B8A8_SINT = 42, VK_FORMAT_R8G8B8A8_SRGB = 43, VK_FORMAT_B8G8R8A8_UNORM = 44, VK_FORMAT_B8G8R8A8_SNORM = 45, VK_FORMAT_B8G8R8A8_USCALED = 46, VK_FORMAT_B8G8R8A8_SSCALED = 47, VK_FORMAT_B8G8R8A8_UINT = 48, VK_FORMAT_B8G8R8A8_SINT = 49, VK_FORMAT_B8G8R8A8_SRGB = 50, VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, VK_FORMAT_R16_UNORM = 70, VK_FORMAT_R16_SNORM = 71, VK_FORMAT_R16_USCALED = 72, VK_FORMAT_R16_SSCALED = 73, VK_FORMAT_R16_UINT = 74, VK_FORMAT_R16_SINT = 75, VK_FORMAT_R16_SFLOAT = 76, VK_FORMAT_R16G16_UNORM = 77, VK_FORMAT_R16G16_SNORM = 78, VK_FORMAT_R16G16_USCALED = 79, VK_FORMAT_R16G16_SSCALED = 80, VK_FORMAT_R16G16_UINT = 81, VK_FORMAT_R16G16_SINT = 82, VK_FORMAT_R16G16_SFLOAT = 83, VK_FORMAT_R16G16B16_UNORM = 84, VK_FORMAT_R16G16B16_SNORM = 85, VK_FORMAT_R16G16B16_USCALED = 86, VK_FORMAT_R16G16B16_SSCALED = 87, VK_FORMAT_R16G16B16_UINT = 88, VK_FORMAT_R16G16B16_SINT = 89, VK_FORMAT_R16G16B16_SFLOAT = 90, VK_FORMAT_R16G16B16A16_UNORM = 91, VK_FORMAT_R16G16B16A16_SNORM = 92, VK_FORMAT_R16G16B16A16_USCALED = 93, VK_FORMAT_R16G16B16A16_SSCALED = 94, VK_FORMAT_R16G16B16A16_UINT = 95, VK_FORMAT_R16G16B16A16_SINT = 96, VK_FORMAT_R16G16B16A16_SFLOAT = 97, VK_FORMAT_R32_UINT = 98, VK_FORMAT_R32_SINT = 99, VK_FORMAT_R32_SFLOAT = 100, VK_FORMAT_R32G32_UINT = 101, VK_FORMAT_R32G32_SINT = 102, VK_FORMAT_R32G32_SFLOAT = 103, VK_FORMAT_R32G32B32_UINT = 104, VK_FORMAT_R32G32B32_SINT = 105, VK_FORMAT_R32G32B32_SFLOAT = 106, VK_FORMAT_R32G32B32A32_UINT = 107, VK_FORMAT_R32G32B32A32_SINT = 108, VK_FORMAT_R32G32B32A32_SFLOAT = 109, VK_FORMAT_R64_UINT = 110, VK_FORMAT_R64_SINT = 111, VK_FORMAT_R64_SFLOAT = 112, VK_FORMAT_R64G64_UINT = 113, VK_FORMAT_R64G64_SINT = 114, VK_FORMAT_R64G64_SFLOAT = 115, VK_FORMAT_R64G64B64_UINT = 116, VK_FORMAT_R64G64B64_SINT = 117, VK_FORMAT_R64G64B64_SFLOAT = 118, VK_FORMAT_R64G64B64A64_UINT = 119, VK_FORMAT_R64G64B64A64_SINT = 120, VK_FORMAT_R64G64B64A64_SFLOAT = 121, VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, VK_FORMAT_D16_UNORM = 124, VK_FORMAT_X8_D24_UNORM_PACK32 = 125, VK_FORMAT_D32_SFLOAT = 126, VK_FORMAT_S8_UINT = 127, VK_FORMAT_D16_UNORM_S8_UINT = 128, VK_FORMAT_D24_UNORM_S8_UINT = 129, VK_FORMAT_D32_SFLOAT_S8_UINT = 130, VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, VK_FORMAT_BC2_UNORM_BLOCK = 135, VK_FORMAT_BC2_SRGB_BLOCK = 136, VK_FORMAT_BC3_UNORM_BLOCK = 137, VK_FORMAT_BC3_SRGB_BLOCK = 138, VK_FORMAT_BC4_UNORM_BLOCK = 139, VK_FORMAT_BC4_SNORM_BLOCK = 140, VK_FORMAT_BC5_UNORM_BLOCK = 141, VK_FORMAT_BC5_SNORM_BLOCK = 142, VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, VK_FORMAT_BC7_UNORM_BLOCK = 145, VK_FORMAT_BC7_SRGB_BLOCK = 146, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; typedef enum VkImageType { VK_IMAGE_TYPE_1D = 0, VK_IMAGE_TYPE_2D = 1, VK_IMAGE_TYPE_3D = 2, VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageType; typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF } VkImageTiling; typedef enum VkPhysicalDeviceType { VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, VK_PHYSICAL_DEVICE_TYPE_CPU = 4, VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkPhysicalDeviceType; typedef enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0, VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF } VkQueryType; typedef enum VkSharingMode { VK_SHARING_MODE_EXCLUSIVE = 0, VK_SHARING_MODE_CONCURRENT = 1, VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF } VkSharingMode; typedef enum VkImageLayout { VK_IMAGE_LAYOUT_UNDEFINED = 0, VK_IMAGE_LAYOUT_GENERAL = 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, VK_IMAGE_LAYOUT_PREINITIALIZED = 8, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF } VkImageLayout; typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_1D = 0, VK_IMAGE_VIEW_TYPE_2D = 1, VK_IMAGE_VIEW_TYPE_3D = 2, VK_IMAGE_VIEW_TYPE_CUBE = 3, VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageViewType; typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_IDENTITY = 0, VK_COMPONENT_SWIZZLE_ZERO = 1, VK_COMPONENT_SWIZZLE_ONE = 2, VK_COMPONENT_SWIZZLE_R = 3, VK_COMPONENT_SWIZZLE_G = 4, VK_COMPONENT_SWIZZLE_B = 5, VK_COMPONENT_SWIZZLE_A = 6, VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF } VkComponentSwizzle; typedef enum VkVertexInputRate { VK_VERTEX_INPUT_RATE_VERTEX = 0, VK_VERTEX_INPUT_RATE_INSTANCE = 1, VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF } VkVertexInputRate; typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF } VkPrimitiveTopology; typedef enum VkPolygonMode { VK_POLYGON_MODE_FILL = 0, VK_POLYGON_MODE_LINE = 1, VK_POLYGON_MODE_POINT = 2, VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF } VkPolygonMode; typedef enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, VK_FRONT_FACE_CLOCKWISE = 1, VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF } VkFrontFace; typedef enum VkCompareOp { VK_COMPARE_OP_NEVER = 0, VK_COMPARE_OP_LESS = 1, VK_COMPARE_OP_EQUAL = 2, VK_COMPARE_OP_LESS_OR_EQUAL = 3, VK_COMPARE_OP_GREATER = 4, VK_COMPARE_OP_NOT_EQUAL = 5, VK_COMPARE_OP_GREATER_OR_EQUAL = 6, VK_COMPARE_OP_ALWAYS = 7, VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF } VkCompareOp; typedef enum VkStencilOp { VK_STENCIL_OP_KEEP = 0, VK_STENCIL_OP_ZERO = 1, VK_STENCIL_OP_REPLACE = 2, VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, VK_STENCIL_OP_INVERT = 5, VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF } VkStencilOp; typedef enum VkLogicOp { VK_LOGIC_OP_CLEAR = 0, VK_LOGIC_OP_AND = 1, VK_LOGIC_OP_AND_REVERSE = 2, VK_LOGIC_OP_COPY = 3, VK_LOGIC_OP_AND_INVERTED = 4, VK_LOGIC_OP_NO_OP = 5, VK_LOGIC_OP_XOR = 6, VK_LOGIC_OP_OR = 7, VK_LOGIC_OP_NOR = 8, VK_LOGIC_OP_EQUIVALENT = 9, VK_LOGIC_OP_INVERT = 10, VK_LOGIC_OP_OR_REVERSE = 11, VK_LOGIC_OP_COPY_INVERTED = 12, VK_LOGIC_OP_OR_INVERTED = 13, VK_LOGIC_OP_NAND = 14, VK_LOGIC_OP_SET = 15, VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF } VkLogicOp; typedef enum VkBlendFactor { VK_BLEND_FACTOR_ZERO = 0, VK_BLEND_FACTOR_ONE = 1, VK_BLEND_FACTOR_SRC_COLOR = 2, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, VK_BLEND_FACTOR_DST_COLOR = 4, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, VK_BLEND_FACTOR_SRC_ALPHA = 6, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, VK_BLEND_FACTOR_DST_ALPHA = 8, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, VK_BLEND_FACTOR_CONSTANT_COLOR = 10, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, VK_BLEND_FACTOR_SRC1_COLOR = 15, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, VK_BLEND_FACTOR_SRC1_ALPHA = 17, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF } VkBlendFactor; typedef enum VkBlendOp { VK_BLEND_OP_ADD = 0, VK_BLEND_OP_SUBTRACT = 1, VK_BLEND_OP_REVERSE_SUBTRACT = 2, VK_BLEND_OP_MIN = 3, VK_BLEND_OP_MAX = 4, VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF } VkBlendOp; typedef enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT = 0, VK_DYNAMIC_STATE_SCISSOR = 1, VK_DYNAMIC_STATE_LINE_WIDTH = 2, VK_DYNAMIC_STATE_DEPTH_BIAS = 3, VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF } VkDynamicState; typedef enum VkFilter { VK_FILTER_NEAREST = 0, VK_FILTER_LINEAR = 1, VK_FILTER_CUBIC_IMG = 1000015000, VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, VK_FILTER_END_RANGE = VK_FILTER_LINEAR, VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), VK_FILTER_MAX_ENUM = 0x7FFFFFFF } VkFilter; typedef enum VkSamplerMipmapMode { VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerMipmapMode; typedef enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerAddressMode; typedef enum VkBorderColor { VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF } VkBorderColor; typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_SAMPLER = 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorType; typedef enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0, VK_ATTACHMENT_LOAD_OP_CLEAR = 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentLoadOp; typedef enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0, VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentStoreOp; typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF } VkPipelineBindPoint; typedef enum VkCommandBufferLevel { VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferLevel; typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF } VkIndexType; typedef enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF } VkSubpassContents; typedef VkFlags VkInstanceCreateFlags; typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFormatFeatureFlagBits; typedef VkFlags VkFormatFeatureFlags; typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; typedef VkFlags VkImageUsageFlags; typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageCreateFlagBits; typedef VkFlags VkImageCreateFlags; typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT = 0x00000001, VK_SAMPLE_COUNT_2_BIT = 0x00000002, VK_SAMPLE_COUNT_4_BIT = 0x00000004, VK_SAMPLE_COUNT_8_BIT = 0x00000008, VK_SAMPLE_COUNT_16_BIT = 0x00000010, VK_SAMPLE_COUNT_32_BIT = 0x00000020, VK_SAMPLE_COUNT_64_BIT = 0x00000040, VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSampleCountFlagBits; typedef VkFlags VkSampleCountFlags; typedef enum VkQueueFlagBits { VK_QUEUE_GRAPHICS_BIT = 0x00000001, VK_QUEUE_COMPUTE_BIT = 0x00000002, VK_QUEUE_TRANSFER_BIT = 0x00000004, VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; typedef VkFlags VkQueueFlags; typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryPropertyFlagBits; typedef VkFlags VkMemoryPropertyFlags; typedef enum VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryHeapFlagBits; typedef VkFlags VkMemoryHeapFlags; typedef VkFlags VkDeviceCreateFlags; typedef VkFlags VkDeviceQueueCreateFlags; typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; typedef VkFlags VkPipelineStageFlags; typedef VkFlags VkMemoryMapFlags; typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; typedef VkFlags VkImageAspectFlags; typedef enum VkSparseImageFormatFlagBits { VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseImageFormatFlagBits; typedef VkFlags VkSparseImageFormatFlags; typedef enum VkSparseMemoryBindFlagBits { VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseMemoryBindFlagBits; typedef VkFlags VkSparseMemoryBindFlags; typedef enum VkFenceCreateFlagBits { VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceCreateFlagBits; typedef VkFlags VkFenceCreateFlags; typedef VkFlags VkSemaphoreCreateFlags; typedef VkFlags VkEventCreateFlags; typedef VkFlags VkQueryPoolCreateFlags; typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryPipelineStatisticFlagBits; typedef VkFlags VkQueryPipelineStatisticFlags; typedef enum VkQueryResultFlagBits { VK_QUERY_RESULT_64_BIT = 0x00000001, VK_QUERY_RESULT_WAIT_BIT = 0x00000002, VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryResultFlagBits; typedef VkFlags VkQueryResultFlags; typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; typedef VkFlags VkBufferCreateFlags; typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; typedef VkFlags VkBufferUsageFlags; typedef VkFlags VkBufferViewCreateFlags; typedef VkFlags VkImageViewCreateFlags; typedef VkFlags VkShaderModuleCreateFlags; typedef VkFlags VkPipelineCacheCreateFlags; typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; typedef VkFlags VkPipelineCreateFlags; typedef VkFlags VkPipelineShaderStageCreateFlags; typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; typedef VkFlags VkPipelineVertexInputStateCreateFlags; typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; typedef VkFlags VkPipelineTessellationStateCreateFlags; typedef VkFlags VkPipelineViewportStateCreateFlags; typedef VkFlags VkPipelineRasterizationStateCreateFlags; typedef enum VkCullModeFlagBits { VK_CULL_MODE_NONE = 0, VK_CULL_MODE_FRONT_BIT = 0x00000001, VK_CULL_MODE_BACK_BIT = 0x00000002, VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCullModeFlagBits; typedef VkFlags VkCullModeFlags; typedef VkFlags VkPipelineMultisampleStateCreateFlags; typedef VkFlags VkPipelineDepthStencilStateCreateFlags; typedef VkFlags VkPipelineColorBlendStateCreateFlags; typedef enum VkColorComponentFlagBits { VK_COLOR_COMPONENT_R_BIT = 0x00000001, VK_COLOR_COMPONENT_G_BIT = 0x00000002, VK_COLOR_COMPONENT_B_BIT = 0x00000004, VK_COLOR_COMPONENT_A_BIT = 0x00000008, VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkColorComponentFlagBits; typedef VkFlags VkColorComponentFlags; typedef VkFlags VkPipelineDynamicStateCreateFlags; typedef VkFlags VkPipelineLayoutCreateFlags; typedef VkFlags VkShaderStageFlags; typedef VkFlags VkSamplerCreateFlags; typedef VkFlags VkDescriptorSetLayoutCreateFlags; typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; typedef VkFlags VkDescriptorPoolCreateFlags; typedef VkFlags VkDescriptorPoolResetFlags; typedef VkFlags VkFramebufferCreateFlags; typedef VkFlags VkRenderPassCreateFlags; typedef enum VkAttachmentDescriptionFlagBits { VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAttachmentDescriptionFlagBits; typedef VkFlags VkAttachmentDescriptionFlags; typedef VkFlags VkSubpassDescriptionFlags; typedef enum VkAccessFlagBits { VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, VK_ACCESS_INDEX_READ_BIT = 0x00000002, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, VK_ACCESS_SHADER_READ_BIT = 0x00000020, VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, VK_ACCESS_HOST_READ_BIT = 0x00002000, VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; typedef enum VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDependencyFlagBits; typedef VkFlags VkDependencyFlags; typedef enum VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolCreateFlagBits; typedef VkFlags VkCommandPoolCreateFlags; typedef enum VkCommandPoolResetFlagBits { VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolResetFlagBits; typedef VkFlags VkCommandPoolResetFlags; typedef enum VkCommandBufferUsageFlagBits { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferUsageFlagBits; typedef VkFlags VkCommandBufferUsageFlags; typedef enum VkQueryControlFlagBits { VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryControlFlagBits; typedef VkFlags VkQueryControlFlags; typedef enum VkCommandBufferResetFlagBits { VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferResetFlagBits; typedef VkFlags VkCommandBufferResetFlags; typedef enum VkStencilFaceFlagBits { VK_STENCIL_FACE_FRONT_BIT = 0x00000001, VK_STENCIL_FACE_BACK_BIT = 0x00000002, VK_STENCIL_FRONT_AND_BACK = 0x00000003, VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkStencilFaceFlagBits; typedef VkFlags VkStencilFaceFlags; typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); typedef void (VKAPI_PTR *PFN_vkFreeFunction)( void* pUserData, void* pMemory); typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); typedef struct VkApplicationInfo { VkStructureType sType; const void* pNext; const char* pApplicationName; uint32_t applicationVersion; const char* pEngineName; uint32_t engineVersion; uint32_t apiVersion; } VkApplicationInfo; typedef struct VkInstanceCreateInfo { VkStructureType sType; const void* pNext; VkInstanceCreateFlags flags; const VkApplicationInfo* pApplicationInfo; uint32_t enabledLayerCount; const char* const* ppEnabledLayerNames; uint32_t enabledExtensionCount; const char* const* ppEnabledExtensionNames; } VkInstanceCreateInfo; typedef struct VkAllocationCallbacks { void* pUserData; PFN_vkAllocationFunction pfnAllocation; PFN_vkReallocationFunction pfnReallocation; PFN_vkFreeFunction pfnFree; PFN_vkInternalAllocationNotification pfnInternalAllocation; PFN_vkInternalFreeNotification pfnInternalFree; } VkAllocationCallbacks; typedef struct VkPhysicalDeviceFeatures { VkBool32 robustBufferAccess; VkBool32 fullDrawIndexUint32; VkBool32 imageCubeArray; VkBool32 independentBlend; VkBool32 geometryShader; VkBool32 tessellationShader; VkBool32 sampleRateShading; VkBool32 dualSrcBlend; VkBool32 logicOp; VkBool32 multiDrawIndirect; VkBool32 drawIndirectFirstInstance; VkBool32 depthClamp; VkBool32 depthBiasClamp; VkBool32 fillModeNonSolid; VkBool32 depthBounds; VkBool32 wideLines; VkBool32 largePoints; VkBool32 alphaToOne; VkBool32 multiViewport; VkBool32 samplerAnisotropy; VkBool32 textureCompressionETC2; VkBool32 textureCompressionASTC_LDR; VkBool32 textureCompressionBC; VkBool32 occlusionQueryPrecise; VkBool32 pipelineStatisticsQuery; VkBool32 vertexPipelineStoresAndAtomics; VkBool32 fragmentStoresAndAtomics; VkBool32 shaderTessellationAndGeometryPointSize; VkBool32 shaderImageGatherExtended; VkBool32 shaderStorageImageExtendedFormats; VkBool32 shaderStorageImageMultisample; VkBool32 shaderStorageImageReadWithoutFormat; VkBool32 shaderStorageImageWriteWithoutFormat; VkBool32 shaderUniformBufferArrayDynamicIndexing; VkBool32 shaderSampledImageArrayDynamicIndexing; VkBool32 shaderStorageBufferArrayDynamicIndexing; VkBool32 shaderStorageImageArrayDynamicIndexing; VkBool32 shaderClipDistance; VkBool32 shaderCullDistance; VkBool32 shaderFloat64; VkBool32 shaderInt64; VkBool32 shaderInt16; VkBool32 shaderResourceResidency; VkBool32 shaderResourceMinLod; VkBool32 sparseBinding; VkBool32 sparseResidencyBuffer; VkBool32 sparseResidencyImage2D; VkBool32 sparseResidencyImage3D; VkBool32 sparseResidency2Samples; VkBool32 sparseResidency4Samples; VkBool32 sparseResidency8Samples; VkBool32 sparseResidency16Samples; VkBool32 sparseResidencyAliased; VkBool32 variableMultisampleRate; VkBool32 inheritedQueries; } VkPhysicalDeviceFeatures; typedef struct VkFormatProperties { VkFormatFeatureFlags linearTilingFeatures; VkFormatFeatureFlags optimalTilingFeatures; VkFormatFeatureFlags bufferFeatures; } VkFormatProperties; typedef struct VkExtent3D { uint32_t width; uint32_t height; uint32_t depth; } VkExtent3D; typedef struct VkImageFormatProperties { VkExtent3D maxExtent; uint32_t maxMipLevels; uint32_t maxArrayLayers; VkSampleCountFlags sampleCounts; VkDeviceSize maxResourceSize; } VkImageFormatProperties; typedef struct VkPhysicalDeviceLimits { uint32_t maxImageDimension1D; uint32_t maxImageDimension2D; uint32_t maxImageDimension3D; uint32_t maxImageDimensionCube; uint32_t maxImageArrayLayers; uint32_t maxTexelBufferElements; uint32_t maxUniformBufferRange; uint32_t maxStorageBufferRange; uint32_t maxPushConstantsSize; uint32_t maxMemoryAllocationCount; uint32_t maxSamplerAllocationCount; VkDeviceSize bufferImageGranularity; VkDeviceSize sparseAddressSpaceSize; uint32_t maxBoundDescriptorSets; uint32_t maxPerStageDescriptorSamplers; uint32_t maxPerStageDescriptorUniformBuffers; uint32_t maxPerStageDescriptorStorageBuffers; uint32_t maxPerStageDescriptorSampledImages; uint32_t maxPerStageDescriptorStorageImages; uint32_t maxPerStageDescriptorInputAttachments; uint32_t maxPerStageResources; uint32_t maxDescriptorSetSamplers; uint32_t maxDescriptorSetUniformBuffers; uint32_t maxDescriptorSetUniformBuffersDynamic; uint32_t maxDescriptorSetStorageBuffers; uint32_t maxDescriptorSetStorageBuffersDynamic; uint32_t maxDescriptorSetSampledImages; uint32_t maxDescriptorSetStorageImages; uint32_t maxDescriptorSetInputAttachments; uint32_t maxVertexInputAttributes; uint32_t maxVertexInputBindings; uint32_t maxVertexInputAttributeOffset; uint32_t maxVertexInputBindingStride; uint32_t maxVertexOutputComponents; uint32_t maxTessellationGenerationLevel; uint32_t maxTessellationPatchSize; uint32_t maxTessellationControlPerVertexInputComponents; uint32_t maxTessellationControlPerVertexOutputComponents; uint32_t maxTessellationControlPerPatchOutputComponents; uint32_t maxTessellationControlTotalOutputComponents; uint32_t maxTessellationEvaluationInputComponents; uint32_t maxTessellationEvaluationOutputComponents; uint32_t maxGeometryShaderInvocations; uint32_t maxGeometryInputComponents; uint32_t maxGeometryOutputComponents; uint32_t maxGeometryOutputVertices; uint32_t maxGeometryTotalOutputComponents; uint32_t maxFragmentInputComponents; uint32_t maxFragmentOutputAttachments; uint32_t maxFragmentDualSrcAttachments; uint32_t maxFragmentCombinedOutputResources; uint32_t maxComputeSharedMemorySize; uint32_t maxComputeWorkGroupCount[3]; uint32_t maxComputeWorkGroupInvocations; uint32_t maxComputeWorkGroupSize[3]; uint32_t subPixelPrecisionBits; uint32_t subTexelPrecisionBits; uint32_t mipmapPrecisionBits; uint32_t maxDrawIndexedIndexValue; uint32_t maxDrawIndirectCount; float maxSamplerLodBias; float maxSamplerAnisotropy; uint32_t maxViewports; uint32_t maxViewportDimensions[2]; float viewportBoundsRange[2]; uint32_t viewportSubPixelBits; size_t minMemoryMapAlignment; VkDeviceSize minTexelBufferOffsetAlignment; VkDeviceSize minUniformBufferOffsetAlignment; VkDeviceSize minStorageBufferOffsetAlignment; int32_t minTexelOffset; uint32_t maxTexelOffset; int32_t minTexelGatherOffset; uint32_t maxTexelGatherOffset; float minInterpolationOffset; float maxInterpolationOffset; uint32_t subPixelInterpolationOffsetBits; uint32_t maxFramebufferWidth; uint32_t maxFramebufferHeight; uint32_t maxFramebufferLayers; VkSampleCountFlags framebufferColorSampleCounts; VkSampleCountFlags framebufferDepthSampleCounts; VkSampleCountFlags framebufferStencilSampleCounts; VkSampleCountFlags framebufferNoAttachmentsSampleCounts; uint32_t maxColorAttachments; VkSampleCountFlags sampledImageColorSampleCounts; VkSampleCountFlags sampledImageIntegerSampleCounts; VkSampleCountFlags sampledImageDepthSampleCounts; VkSampleCountFlags sampledImageStencilSampleCounts; VkSampleCountFlags storageImageSampleCounts; uint32_t maxSampleMaskWords; VkBool32 timestampComputeAndGraphics; float timestampPeriod; uint32_t maxClipDistances; uint32_t maxCullDistances; uint32_t maxCombinedClipAndCullDistances; uint32_t discreteQueuePriorities; float pointSizeRange[2]; float lineWidthRange[2]; float pointSizeGranularity; float lineWidthGranularity; VkBool32 strictLines; VkBool32 standardSampleLocations; VkDeviceSize optimalBufferCopyOffsetAlignment; VkDeviceSize optimalBufferCopyRowPitchAlignment; VkDeviceSize nonCoherentAtomSize; } VkPhysicalDeviceLimits; typedef struct VkPhysicalDeviceSparseProperties { VkBool32 residencyStandard2DBlockShape; VkBool32 residencyStandard2DMultisampleBlockShape; VkBool32 residencyStandard3DBlockShape; VkBool32 residencyAlignedMipSize; VkBool32 residencyNonResidentStrict; } VkPhysicalDeviceSparseProperties; typedef struct VkPhysicalDeviceProperties { uint32_t apiVersion; uint32_t driverVersion; uint32_t vendorID; uint32_t deviceID; VkPhysicalDeviceType deviceType; char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; uint8_t pipelineCacheUUID[VK_UUID_SIZE]; VkPhysicalDeviceLimits limits; VkPhysicalDeviceSparseProperties sparseProperties; } VkPhysicalDeviceProperties; typedef struct VkQueueFamilyProperties { VkQueueFlags queueFlags; uint32_t queueCount; uint32_t timestampValidBits; VkExtent3D minImageTransferGranularity; } VkQueueFamilyProperties; typedef struct VkMemoryType { VkMemoryPropertyFlags propertyFlags; uint32_t heapIndex; } VkMemoryType; typedef struct VkMemoryHeap { VkDeviceSize size; VkMemoryHeapFlags flags; } VkMemoryHeap; typedef struct VkPhysicalDeviceMemoryProperties { uint32_t memoryTypeCount; VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; uint32_t memoryHeapCount; VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; } VkPhysicalDeviceMemoryProperties; typedef struct VkDeviceQueueCreateInfo { VkStructureType sType; const void* pNext; VkDeviceQueueCreateFlags flags; uint32_t queueFamilyIndex; uint32_t queueCount; const float* pQueuePriorities; } VkDeviceQueueCreateInfo; typedef struct VkDeviceCreateInfo { VkStructureType sType; const void* pNext; VkDeviceCreateFlags flags; uint32_t queueCreateInfoCount; const VkDeviceQueueCreateInfo* pQueueCreateInfos; uint32_t enabledLayerCount; const char* const* ppEnabledLayerNames; uint32_t enabledExtensionCount; const char* const* ppEnabledExtensionNames; const VkPhysicalDeviceFeatures* pEnabledFeatures; } VkDeviceCreateInfo; typedef struct VkExtensionProperties { char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; uint32_t specVersion; } VkExtensionProperties; typedef struct VkLayerProperties { char layerName[VK_MAX_EXTENSION_NAME_SIZE]; uint32_t specVersion; uint32_t implementationVersion; char description[VK_MAX_DESCRIPTION_SIZE]; } VkLayerProperties; typedef struct VkSubmitInfo { VkStructureType sType; const void* pNext; uint32_t waitSemaphoreCount; const VkSemaphore* pWaitSemaphores; const VkPipelineStageFlags* pWaitDstStageMask; uint32_t commandBufferCount; const VkCommandBuffer* pCommandBuffers; uint32_t signalSemaphoreCount; const VkSemaphore* pSignalSemaphores; } VkSubmitInfo; typedef struct VkMemoryAllocateInfo { VkStructureType sType; const void* pNext; VkDeviceSize allocationSize; uint32_t memoryTypeIndex; } VkMemoryAllocateInfo; typedef struct VkMappedMemoryRange { VkStructureType sType; const void* pNext; VkDeviceMemory memory; VkDeviceSize offset; VkDeviceSize size; } VkMappedMemoryRange; typedef struct VkMemoryRequirements { VkDeviceSize size; VkDeviceSize alignment; uint32_t memoryTypeBits; } VkMemoryRequirements; typedef struct VkSparseImageFormatProperties { VkImageAspectFlags aspectMask; VkExtent3D imageGranularity; VkSparseImageFormatFlags flags; } VkSparseImageFormatProperties; typedef struct VkSparseImageMemoryRequirements { VkSparseImageFormatProperties formatProperties; uint32_t imageMipTailFirstLod; VkDeviceSize imageMipTailSize; VkDeviceSize imageMipTailOffset; VkDeviceSize imageMipTailStride; } VkSparseImageMemoryRequirements; typedef struct VkSparseMemoryBind { VkDeviceSize resourceOffset; VkDeviceSize size; VkDeviceMemory memory; VkDeviceSize memoryOffset; VkSparseMemoryBindFlags flags; } VkSparseMemoryBind; typedef struct VkSparseBufferMemoryBindInfo { VkBuffer buffer; uint32_t bindCount; const VkSparseMemoryBind* pBinds; } VkSparseBufferMemoryBindInfo; typedef struct VkSparseImageOpaqueMemoryBindInfo { VkImage image; uint32_t bindCount; const VkSparseMemoryBind* pBinds; } VkSparseImageOpaqueMemoryBindInfo; typedef struct VkImageSubresource { VkImageAspectFlags aspectMask; uint32_t mipLevel; uint32_t arrayLayer; } VkImageSubresource; typedef struct VkOffset3D { int32_t x; int32_t y; int32_t z; } VkOffset3D; typedef struct VkSparseImageMemoryBind { VkImageSubresource subresource; VkOffset3D offset; VkExtent3D extent; VkDeviceMemory memory; VkDeviceSize memoryOffset; VkSparseMemoryBindFlags flags; } VkSparseImageMemoryBind; typedef struct VkSparseImageMemoryBindInfo { VkImage image; uint32_t bindCount; const VkSparseImageMemoryBind* pBinds; } VkSparseImageMemoryBindInfo; typedef struct VkBindSparseInfo { VkStructureType sType; const void* pNext; uint32_t waitSemaphoreCount; const VkSemaphore* pWaitSemaphores; uint32_t bufferBindCount; const VkSparseBufferMemoryBindInfo* pBufferBinds; uint32_t imageOpaqueBindCount; const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; uint32_t imageBindCount; const VkSparseImageMemoryBindInfo* pImageBinds; uint32_t signalSemaphoreCount; const VkSemaphore* pSignalSemaphores; } VkBindSparseInfo; typedef struct VkFenceCreateInfo { VkStructureType sType; const void* pNext; VkFenceCreateFlags flags; } VkFenceCreateInfo; typedef struct VkSemaphoreCreateInfo { VkStructureType sType; const void* pNext; VkSemaphoreCreateFlags flags; } VkSemaphoreCreateInfo; typedef struct VkEventCreateInfo { VkStructureType sType; const void* pNext; VkEventCreateFlags flags; } VkEventCreateInfo; typedef struct VkQueryPoolCreateInfo { VkStructureType sType; const void* pNext; VkQueryPoolCreateFlags flags; VkQueryType queryType; uint32_t queryCount; VkQueryPipelineStatisticFlags pipelineStatistics; } VkQueryPoolCreateInfo; typedef struct VkBufferCreateInfo { VkStructureType sType; const void* pNext; VkBufferCreateFlags flags; VkDeviceSize size; VkBufferUsageFlags usage; VkSharingMode sharingMode; uint32_t queueFamilyIndexCount; const uint32_t* pQueueFamilyIndices; } VkBufferCreateInfo; typedef struct VkBufferViewCreateInfo { VkStructureType sType; const void* pNext; VkBufferViewCreateFlags flags; VkBuffer buffer; VkFormat format; VkDeviceSize offset; VkDeviceSize range; } VkBufferViewCreateInfo; typedef struct VkImageCreateInfo { VkStructureType sType; const void* pNext; VkImageCreateFlags flags; VkImageType imageType; VkFormat format; VkExtent3D extent; uint32_t mipLevels; uint32_t arrayLayers; VkSampleCountFlagBits samples; VkImageTiling tiling; VkImageUsageFlags usage; VkSharingMode sharingMode; uint32_t queueFamilyIndexCount; const uint32_t* pQueueFamilyIndices; VkImageLayout initialLayout; } VkImageCreateInfo; typedef struct VkSubresourceLayout { VkDeviceSize offset; VkDeviceSize size; VkDeviceSize rowPitch; VkDeviceSize arrayPitch; VkDeviceSize depthPitch; } VkSubresourceLayout; typedef struct VkComponentMapping { VkComponentSwizzle r; VkComponentSwizzle g; VkComponentSwizzle b; VkComponentSwizzle a; } VkComponentMapping; typedef struct VkImageSubresourceRange { VkImageAspectFlags aspectMask; uint32_t baseMipLevel; uint32_t levelCount; uint32_t baseArrayLayer; uint32_t layerCount; } VkImageSubresourceRange; typedef struct VkImageViewCreateInfo { VkStructureType sType; const void* pNext; VkImageViewCreateFlags flags; VkImage image; VkImageViewType viewType; VkFormat format; VkComponentMapping components; VkImageSubresourceRange subresourceRange; } VkImageViewCreateInfo; typedef struct VkShaderModuleCreateInfo { VkStructureType sType; const void* pNext; VkShaderModuleCreateFlags flags; size_t codeSize; const uint32_t* pCode; } VkShaderModuleCreateInfo; typedef struct VkPipelineCacheCreateInfo { VkStructureType sType; const void* pNext; VkPipelineCacheCreateFlags flags; size_t initialDataSize; const void* pInitialData; } VkPipelineCacheCreateInfo; typedef struct VkSpecializationMapEntry { uint32_t constantID; uint32_t offset; size_t size; } VkSpecializationMapEntry; typedef struct VkSpecializationInfo { uint32_t mapEntryCount; const VkSpecializationMapEntry* pMapEntries; size_t dataSize; const void* pData; } VkSpecializationInfo; typedef struct VkPipelineShaderStageCreateInfo { VkStructureType sType; const void* pNext; VkPipelineShaderStageCreateFlags flags; VkShaderStageFlagBits stage; VkShaderModule module; const char* pName; const VkSpecializationInfo* pSpecializationInfo; } VkPipelineShaderStageCreateInfo; typedef struct VkVertexInputBindingDescription { uint32_t binding; uint32_t stride; VkVertexInputRate inputRate; } VkVertexInputBindingDescription; typedef struct VkVertexInputAttributeDescription { uint32_t location; uint32_t binding; VkFormat format; uint32_t offset; } VkVertexInputAttributeDescription; typedef struct VkPipelineVertexInputStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineVertexInputStateCreateFlags flags; uint32_t vertexBindingDescriptionCount; const VkVertexInputBindingDescription* pVertexBindingDescriptions; uint32_t vertexAttributeDescriptionCount; const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; } VkPipelineVertexInputStateCreateInfo; typedef struct VkPipelineInputAssemblyStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineInputAssemblyStateCreateFlags flags; VkPrimitiveTopology topology; VkBool32 primitiveRestartEnable; } VkPipelineInputAssemblyStateCreateInfo; typedef struct VkPipelineTessellationStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineTessellationStateCreateFlags flags; uint32_t patchControlPoints; } VkPipelineTessellationStateCreateInfo; typedef struct VkViewport { float x; float y; float width; float height; float minDepth; float maxDepth; } VkViewport; typedef struct VkOffset2D { int32_t x; int32_t y; } VkOffset2D; typedef struct VkExtent2D { uint32_t width; uint32_t height; } VkExtent2D; typedef struct VkRect2D { VkOffset2D offset; VkExtent2D extent; } VkRect2D; typedef struct VkPipelineViewportStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineViewportStateCreateFlags flags; uint32_t viewportCount; const VkViewport* pViewports; uint32_t scissorCount; const VkRect2D* pScissors; } VkPipelineViewportStateCreateInfo; typedef struct VkPipelineRasterizationStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineRasterizationStateCreateFlags flags; VkBool32 depthClampEnable; VkBool32 rasterizerDiscardEnable; VkPolygonMode polygonMode; VkCullModeFlags cullMode; VkFrontFace frontFace; VkBool32 depthBiasEnable; float depthBiasConstantFactor; float depthBiasClamp; float depthBiasSlopeFactor; float lineWidth; } VkPipelineRasterizationStateCreateInfo; typedef struct VkPipelineMultisampleStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineMultisampleStateCreateFlags flags; VkSampleCountFlagBits rasterizationSamples; VkBool32 sampleShadingEnable; float minSampleShading; const VkSampleMask* pSampleMask; VkBool32 alphaToCoverageEnable; VkBool32 alphaToOneEnable; } VkPipelineMultisampleStateCreateInfo; typedef struct VkStencilOpState { VkStencilOp failOp; VkStencilOp passOp; VkStencilOp depthFailOp; VkCompareOp compareOp; uint32_t compareMask; uint32_t writeMask; uint32_t reference; } VkStencilOpState; typedef struct VkPipelineDepthStencilStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineDepthStencilStateCreateFlags flags; VkBool32 depthTestEnable; VkBool32 depthWriteEnable; VkCompareOp depthCompareOp; VkBool32 depthBoundsTestEnable; VkBool32 stencilTestEnable; VkStencilOpState front; VkStencilOpState back; float minDepthBounds; float maxDepthBounds; } VkPipelineDepthStencilStateCreateInfo; typedef struct VkPipelineColorBlendAttachmentState { VkBool32 blendEnable; VkBlendFactor srcColorBlendFactor; VkBlendFactor dstColorBlendFactor; VkBlendOp colorBlendOp; VkBlendFactor srcAlphaBlendFactor; VkBlendFactor dstAlphaBlendFactor; VkBlendOp alphaBlendOp; VkColorComponentFlags colorWriteMask; } VkPipelineColorBlendAttachmentState; typedef struct VkPipelineColorBlendStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineColorBlendStateCreateFlags flags; VkBool32 logicOpEnable; VkLogicOp logicOp; uint32_t attachmentCount; const VkPipelineColorBlendAttachmentState* pAttachments; float blendConstants[4]; } VkPipelineColorBlendStateCreateInfo; typedef struct VkPipelineDynamicStateCreateInfo { VkStructureType sType; const void* pNext; VkPipelineDynamicStateCreateFlags flags; uint32_t dynamicStateCount; const VkDynamicState* pDynamicStates; } VkPipelineDynamicStateCreateInfo; typedef struct VkGraphicsPipelineCreateInfo { VkStructureType sType; const void* pNext; VkPipelineCreateFlags flags; uint32_t stageCount; const VkPipelineShaderStageCreateInfo* pStages; const VkPipelineVertexInputStateCreateInfo* pVertexInputState; const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; const VkPipelineTessellationStateCreateInfo* pTessellationState; const VkPipelineViewportStateCreateInfo* pViewportState; const VkPipelineRasterizationStateCreateInfo* pRasterizationState; const VkPipelineMultisampleStateCreateInfo* pMultisampleState; const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; const VkPipelineColorBlendStateCreateInfo* pColorBlendState; const VkPipelineDynamicStateCreateInfo* pDynamicState; VkPipelineLayout layout; VkRenderPass renderPass; uint32_t subpass; VkPipeline basePipelineHandle; int32_t basePipelineIndex; } VkGraphicsPipelineCreateInfo; typedef struct VkComputePipelineCreateInfo { VkStructureType sType; const void* pNext; VkPipelineCreateFlags flags; VkPipelineShaderStageCreateInfo stage; VkPipelineLayout layout; VkPipeline basePipelineHandle; int32_t basePipelineIndex; } VkComputePipelineCreateInfo; typedef struct VkPushConstantRange { VkShaderStageFlags stageFlags; uint32_t offset; uint32_t size; } VkPushConstantRange; typedef struct VkPipelineLayoutCreateInfo { VkStructureType sType; const void* pNext; VkPipelineLayoutCreateFlags flags; uint32_t setLayoutCount; const VkDescriptorSetLayout* pSetLayouts; uint32_t pushConstantRangeCount; const VkPushConstantRange* pPushConstantRanges; } VkPipelineLayoutCreateInfo; typedef struct VkSamplerCreateInfo { VkStructureType sType; const void* pNext; VkSamplerCreateFlags flags; VkFilter magFilter; VkFilter minFilter; VkSamplerMipmapMode mipmapMode; VkSamplerAddressMode addressModeU; VkSamplerAddressMode addressModeV; VkSamplerAddressMode addressModeW; float mipLodBias; VkBool32 anisotropyEnable; float maxAnisotropy; VkBool32 compareEnable; VkCompareOp compareOp; float minLod; float maxLod; VkBorderColor borderColor; VkBool32 unnormalizedCoordinates; } VkSamplerCreateInfo; typedef struct VkDescriptorSetLayoutBinding { uint32_t binding; VkDescriptorType descriptorType; uint32_t descriptorCount; VkShaderStageFlags stageFlags; const VkSampler* pImmutableSamplers; } VkDescriptorSetLayoutBinding; typedef struct VkDescriptorSetLayoutCreateInfo { VkStructureType sType; const void* pNext; VkDescriptorSetLayoutCreateFlags flags; uint32_t bindingCount; const VkDescriptorSetLayoutBinding* pBindings; } VkDescriptorSetLayoutCreateInfo; typedef struct VkDescriptorPoolSize { VkDescriptorType type; uint32_t descriptorCount; } VkDescriptorPoolSize; typedef struct VkDescriptorPoolCreateInfo { VkStructureType sType; const void* pNext; VkDescriptorPoolCreateFlags flags; uint32_t maxSets; uint32_t poolSizeCount; const VkDescriptorPoolSize* pPoolSizes; } VkDescriptorPoolCreateInfo; typedef struct VkDescriptorSetAllocateInfo { VkStructureType sType; const void* pNext; VkDescriptorPool descriptorPool; uint32_t descriptorSetCount; const VkDescriptorSetLayout* pSetLayouts; } VkDescriptorSetAllocateInfo; typedef struct VkDescriptorImageInfo { VkSampler sampler; VkImageView imageView; VkImageLayout imageLayout; } VkDescriptorImageInfo; typedef struct VkDescriptorBufferInfo { VkBuffer buffer; VkDeviceSize offset; VkDeviceSize range; } VkDescriptorBufferInfo; typedef struct VkWriteDescriptorSet { VkStructureType sType; const void* pNext; VkDescriptorSet dstSet; uint32_t dstBinding; uint32_t dstArrayElement; uint32_t descriptorCount; VkDescriptorType descriptorType; const VkDescriptorImageInfo* pImageInfo; const VkDescriptorBufferInfo* pBufferInfo; const VkBufferView* pTexelBufferView; } VkWriteDescriptorSet; typedef struct VkCopyDescriptorSet { VkStructureType sType; const void* pNext; VkDescriptorSet srcSet; uint32_t srcBinding; uint32_t srcArrayElement; VkDescriptorSet dstSet; uint32_t dstBinding; uint32_t dstArrayElement; uint32_t descriptorCount; } VkCopyDescriptorSet; typedef struct VkFramebufferCreateInfo { VkStructureType sType; const void* pNext; VkFramebufferCreateFlags flags; VkRenderPass renderPass; uint32_t attachmentCount; const VkImageView* pAttachments; uint32_t width; uint32_t height; uint32_t layers; } VkFramebufferCreateInfo; typedef struct VkAttachmentDescription { VkAttachmentDescriptionFlags flags; VkFormat format; VkSampleCountFlagBits samples; VkAttachmentLoadOp loadOp; VkAttachmentStoreOp storeOp; VkAttachmentLoadOp stencilLoadOp; VkAttachmentStoreOp stencilStoreOp; VkImageLayout initialLayout; VkImageLayout finalLayout; } VkAttachmentDescription; typedef struct VkAttachmentReference { uint32_t attachment; VkImageLayout layout; } VkAttachmentReference; typedef struct VkSubpassDescription { VkSubpassDescriptionFlags flags; VkPipelineBindPoint pipelineBindPoint; uint32_t inputAttachmentCount; const VkAttachmentReference* pInputAttachments; uint32_t colorAttachmentCount; const VkAttachmentReference* pColorAttachments; const VkAttachmentReference* pResolveAttachments; const VkAttachmentReference* pDepthStencilAttachment; uint32_t preserveAttachmentCount; const uint32_t* pPreserveAttachments; } VkSubpassDescription; typedef struct VkSubpassDependency { uint32_t srcSubpass; uint32_t dstSubpass; VkPipelineStageFlags srcStageMask; VkPipelineStageFlags dstStageMask; VkAccessFlags srcAccessMask; VkAccessFlags dstAccessMask; VkDependencyFlags dependencyFlags; } VkSubpassDependency; typedef struct VkRenderPassCreateInfo { VkStructureType sType; const void* pNext; VkRenderPassCreateFlags flags; uint32_t attachmentCount; const VkAttachmentDescription* pAttachments; uint32_t subpassCount; const VkSubpassDescription* pSubpasses; uint32_t dependencyCount; const VkSubpassDependency* pDependencies; } VkRenderPassCreateInfo; typedef struct VkCommandPoolCreateInfo { VkStructureType sType; const void* pNext; VkCommandPoolCreateFlags flags; uint32_t queueFamilyIndex; } VkCommandPoolCreateInfo; typedef struct VkCommandBufferAllocateInfo { VkStructureType sType; const void* pNext; VkCommandPool commandPool; VkCommandBufferLevel level; uint32_t commandBufferCount; } VkCommandBufferAllocateInfo; typedef struct VkCommandBufferInheritanceInfo { VkStructureType sType; const void* pNext; VkRenderPass renderPass; uint32_t subpass; VkFramebuffer framebuffer; VkBool32 occlusionQueryEnable; VkQueryControlFlags queryFlags; VkQueryPipelineStatisticFlags pipelineStatistics; } VkCommandBufferInheritanceInfo; typedef struct VkCommandBufferBeginInfo { VkStructureType sType; const void* pNext; VkCommandBufferUsageFlags flags; const VkCommandBufferInheritanceInfo* pInheritanceInfo; } VkCommandBufferBeginInfo; typedef struct VkBufferCopy { VkDeviceSize srcOffset; VkDeviceSize dstOffset; VkDeviceSize size; } VkBufferCopy; typedef struct VkImageSubresourceLayers { VkImageAspectFlags aspectMask; uint32_t mipLevel; uint32_t baseArrayLayer; uint32_t layerCount; } VkImageSubresourceLayers; typedef struct VkImageCopy { VkImageSubresourceLayers srcSubresource; VkOffset3D srcOffset; VkImageSubresourceLayers dstSubresource; VkOffset3D dstOffset; VkExtent3D extent; } VkImageCopy; typedef struct VkImageBlit { VkImageSubresourceLayers srcSubresource; VkOffset3D srcOffsets[2]; VkImageSubresourceLayers dstSubresource; VkOffset3D dstOffsets[2]; } VkImageBlit; typedef struct VkBufferImageCopy { VkDeviceSize bufferOffset; uint32_t bufferRowLength; uint32_t bufferImageHeight; VkImageSubresourceLayers imageSubresource; VkOffset3D imageOffset; VkExtent3D imageExtent; } VkBufferImageCopy; typedef union VkClearColorValue { float float32[4]; int32_t int32[4]; uint32_t uint32[4]; } VkClearColorValue; typedef struct VkClearDepthStencilValue { float depth; uint32_t stencil; } VkClearDepthStencilValue; typedef union VkClearValue { VkClearColorValue color; VkClearDepthStencilValue depthStencil; } VkClearValue; typedef struct VkClearAttachment { VkImageAspectFlags aspectMask; uint32_t colorAttachment; VkClearValue clearValue; } VkClearAttachment; typedef struct VkClearRect { VkRect2D rect; uint32_t baseArrayLayer; uint32_t layerCount; } VkClearRect; typedef struct VkImageResolve { VkImageSubresourceLayers srcSubresource; VkOffset3D srcOffset; VkImageSubresourceLayers dstSubresource; VkOffset3D dstOffset; VkExtent3D extent; } VkImageResolve; typedef struct VkMemoryBarrier { VkStructureType sType; const void* pNext; VkAccessFlags srcAccessMask; VkAccessFlags dstAccessMask; } VkMemoryBarrier; typedef struct VkBufferMemoryBarrier { VkStructureType sType; const void* pNext; VkAccessFlags srcAccessMask; VkAccessFlags dstAccessMask; uint32_t srcQueueFamilyIndex; uint32_t dstQueueFamilyIndex; VkBuffer buffer; VkDeviceSize offset; VkDeviceSize size; } VkBufferMemoryBarrier; typedef struct VkImageMemoryBarrier { VkStructureType sType; const void* pNext; VkAccessFlags srcAccessMask; VkAccessFlags dstAccessMask; VkImageLayout oldLayout; VkImageLayout newLayout; uint32_t srcQueueFamilyIndex; uint32_t dstQueueFamilyIndex; VkImage image; VkImageSubresourceRange subresourceRange; } VkImageMemoryBarrier; typedef struct VkRenderPassBeginInfo { VkStructureType sType; const void* pNext; VkRenderPass renderPass; VkFramebuffer framebuffer; VkRect2D renderArea; uint32_t clearValueCount; const VkClearValue* pClearValues; } VkRenderPassBeginInfo; typedef struct VkDispatchIndirectCommand { uint32_t x; uint32_t y; uint32_t z; } VkDispatchIndirectCommand; typedef struct VkDrawIndexedIndirectCommand { uint32_t indexCount; uint32_t instanceCount; uint32_t firstIndex; int32_t vertexOffset; uint32_t firstInstance; } VkDrawIndexedIndirectCommand; typedef struct VkDrawIndirectCommand { uint32_t vertexCount; uint32_t instanceCount; uint32_t firstVertex; uint32_t firstInstance; } VkDrawIndirectCommand; typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData); typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( VkInstance instance, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( VkInstance instance, const char* pName); VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( VkDevice device, const char* pName); VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( VkDevice device, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( VkQueue queue); VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( VkDevice device); VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); VKAPI_ATTR void VKAPI_CALL vkFreeMemory( VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( VkDevice device, VkDeviceMemory memory); VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); VKAPI_ATTR void VKAPI_CALL vkDestroyFence( VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences); VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( VkDevice device, VkFence fence); VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( VkDevice device, VkEvent event); VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( VkDevice device, VkEvent event); VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( VkDevice device, VkEvent event); VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); VKAPI_ATTR void VKAPI_CALL vkDestroyImage( VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); VKAPI_ATTR void VKAPI_CALL vkDestroySampler( VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( VkCommandBuffer commandBuffer); VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( VkCommandBuffer commandBuffer, float lineWidth); VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( VkCommandBuffer commandBuffer, const float blendConstants[4]); VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); VKAPI_ATTR void VKAPI_CALL vkCmdDraw( VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData); VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( VkCommandBuffer commandBuffer); VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); #endif #define VK_KHR_surface 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) #define VK_KHR_SURFACE_SPEC_VERSION 25 #define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" #define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF } VkColorSpaceKHR; typedef enum VkPresentModeKHR { VK_PRESENT_MODE_IMMEDIATE_KHR = 0, VK_PRESENT_MODE_MAILBOX_KHR = 1, VK_PRESENT_MODE_FIFO_KHR = 2, VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPresentModeKHR; typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSurfaceTransformFlagBitsKHR; typedef VkFlags VkSurfaceTransformFlagsKHR; typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkCompositeAlphaFlagBitsKHR; typedef VkFlags VkCompositeAlphaFlagsKHR; typedef struct VkSurfaceCapabilitiesKHR { uint32_t minImageCount; uint32_t maxImageCount; VkExtent2D currentExtent; VkExtent2D minImageExtent; VkExtent2D maxImageExtent; uint32_t maxImageArrayLayers; VkSurfaceTransformFlagsKHR supportedTransforms; VkSurfaceTransformFlagBitsKHR currentTransform; VkCompositeAlphaFlagsKHR supportedCompositeAlpha; VkImageUsageFlags supportedUsageFlags; } VkSurfaceCapabilitiesKHR; typedef struct VkSurfaceFormatKHR { VkFormat format; VkColorSpaceKHR colorSpace; } VkSurfaceFormatKHR; typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); #endif #define VK_KHR_swapchain 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) #define VK_KHR_SWAPCHAIN_SPEC_VERSION 68 #define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" typedef VkFlags VkSwapchainCreateFlagsKHR; typedef struct VkSwapchainCreateInfoKHR { VkStructureType sType; const void* pNext; VkSwapchainCreateFlagsKHR flags; VkSurfaceKHR surface; uint32_t minImageCount; VkFormat imageFormat; VkColorSpaceKHR imageColorSpace; VkExtent2D imageExtent; uint32_t imageArrayLayers; VkImageUsageFlags imageUsage; VkSharingMode imageSharingMode; uint32_t queueFamilyIndexCount; const uint32_t* pQueueFamilyIndices; VkSurfaceTransformFlagBitsKHR preTransform; VkCompositeAlphaFlagBitsKHR compositeAlpha; VkPresentModeKHR presentMode; VkBool32 clipped; VkSwapchainKHR oldSwapchain; } VkSwapchainCreateInfoKHR; typedef struct VkPresentInfoKHR { VkStructureType sType; const void* pNext; uint32_t waitSemaphoreCount; const VkSemaphore* pWaitSemaphores; uint32_t swapchainCount; const VkSwapchainKHR* pSwapchains; const uint32_t* pImageIndices; VkResult* pResults; } VkPresentInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( VkQueue queue, const VkPresentInfoKHR* pPresentInfo); #endif #define VK_KHR_display 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) #define VK_KHR_DISPLAY_SPEC_VERSION 21 #define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" typedef enum VkDisplayPlaneAlphaFlagBitsKHR { VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDisplayPlaneAlphaFlagBitsKHR; typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; typedef VkFlags VkDisplayModeCreateFlagsKHR; typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; typedef struct VkDisplayPropertiesKHR { VkDisplayKHR display; const char* displayName; VkExtent2D physicalDimensions; VkExtent2D physicalResolution; VkSurfaceTransformFlagsKHR supportedTransforms; VkBool32 planeReorderPossible; VkBool32 persistentContent; } VkDisplayPropertiesKHR; typedef struct VkDisplayModeParametersKHR { VkExtent2D visibleRegion; uint32_t refreshRate; } VkDisplayModeParametersKHR; typedef struct VkDisplayModePropertiesKHR { VkDisplayModeKHR displayMode; VkDisplayModeParametersKHR parameters; } VkDisplayModePropertiesKHR; typedef struct VkDisplayModeCreateInfoKHR { VkStructureType sType; const void* pNext; VkDisplayModeCreateFlagsKHR flags; VkDisplayModeParametersKHR parameters; } VkDisplayModeCreateInfoKHR; typedef struct VkDisplayPlaneCapabilitiesKHR { VkDisplayPlaneAlphaFlagsKHR supportedAlpha; VkOffset2D minSrcPosition; VkOffset2D maxSrcPosition; VkExtent2D minSrcExtent; VkExtent2D maxSrcExtent; VkOffset2D minDstPosition; VkOffset2D maxDstPosition; VkExtent2D minDstExtent; VkExtent2D maxDstExtent; } VkDisplayPlaneCapabilitiesKHR; typedef struct VkDisplayPlanePropertiesKHR { VkDisplayKHR currentDisplay; uint32_t currentStackIndex; } VkDisplayPlanePropertiesKHR; typedef struct VkDisplaySurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkDisplaySurfaceCreateFlagsKHR flags; VkDisplayModeKHR displayMode; uint32_t planeIndex; uint32_t planeStackIndex; VkSurfaceTransformFlagBitsKHR transform; float globalAlpha; VkDisplayPlaneAlphaFlagBitsKHR alphaMode; VkExtent2D imageExtent; } VkDisplaySurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); #endif #define VK_KHR_display_swapchain 1 #define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 #define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" typedef struct VkDisplayPresentInfoKHR { VkStructureType sType; const void* pNext; VkRect2D srcRect; VkRect2D dstRect; VkBool32 persistent; } VkDisplayPresentInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); #endif #ifdef VK_USE_PLATFORM_XLIB_KHR #define VK_KHR_xlib_surface 1 #include #define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" typedef VkFlags VkXlibSurfaceCreateFlagsKHR; typedef struct VkXlibSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkXlibSurfaceCreateFlagsKHR flags; Display* dpy; Window window; } VkXlibSurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); #endif #endif /* VK_USE_PLATFORM_XLIB_KHR */ #ifdef VK_USE_PLATFORM_XCB_KHR #define VK_KHR_xcb_surface 1 #include #define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" typedef VkFlags VkXcbSurfaceCreateFlagsKHR; typedef struct VkXcbSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkXcbSurfaceCreateFlagsKHR flags; xcb_connection_t* connection; xcb_window_t window; } VkXcbSurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); #endif #endif /* VK_USE_PLATFORM_XCB_KHR */ #ifdef VK_USE_PLATFORM_WAYLAND_KHR #define VK_KHR_wayland_surface 1 #include #define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5 #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef struct VkWaylandSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkWaylandSurfaceCreateFlagsKHR flags; struct wl_display* display; struct wl_surface* surface; } VkWaylandSurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); #endif #endif /* VK_USE_PLATFORM_WAYLAND_KHR */ #ifdef VK_USE_PLATFORM_MIR_KHR #define VK_KHR_mir_surface 1 #include #define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 #define VK_KHR_MIR_SURFACE_EXTENSION_NAME "VK_KHR_mir_surface" typedef VkFlags VkMirSurfaceCreateFlagsKHR; typedef struct VkMirSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkMirSurfaceCreateFlagsKHR flags; MirConnection* connection; MirSurface* mirSurface; } VkMirSurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR( VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection); #endif #endif /* VK_USE_PLATFORM_MIR_KHR */ #ifdef VK_USE_PLATFORM_ANDROID_KHR #define VK_KHR_android_surface 1 #include #define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 #define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; typedef struct VkAndroidSurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkAndroidSurfaceCreateFlagsKHR flags; ANativeWindow* window; } VkAndroidSurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); #endif #endif /* VK_USE_PLATFORM_ANDROID_KHR */ #ifdef VK_USE_PLATFORM_WIN32_KHR #define VK_KHR_win32_surface 1 #include #define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5 #define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef struct VkWin32SurfaceCreateInfoKHR { VkStructureType sType; const void* pNext; VkWin32SurfaceCreateFlagsKHR flags; HINSTANCE hinstance; HWND hwnd; } VkWin32SurfaceCreateInfoKHR; typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); #endif #endif /* VK_USE_PLATFORM_WIN32_KHR */ #define VK_KHR_sampler_mirror_clamp_to_edge 1 #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" #define VK_EXT_debug_report 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) #define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" #define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28, VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportObjectTypeEXT; typedef enum VkDebugReportErrorEXT { VK_DEBUG_REPORT_ERROR_NONE_EXT = 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1, VK_DEBUG_REPORT_ERROR_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_ERROR_NONE_EXT, VK_DEBUG_REPORT_ERROR_END_RANGE_EXT = VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, VK_DEBUG_REPORT_ERROR_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT - VK_DEBUG_REPORT_ERROR_NONE_EXT + 1), VK_DEBUG_REPORT_ERROR_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportErrorEXT; typedef enum VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportFlagBitsEXT; typedef VkFlags VkDebugReportFlagsEXT; typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData); typedef struct VkDebugReportCallbackCreateInfoEXT { VkStructureType sType; const void* pNext; VkDebugReportFlagsEXT flags; PFN_vkDebugReportCallbackEXT pfnCallback; void* pUserData; } VkDebugReportCallbackCreateInfoEXT; typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); #endif #define VK_NV_glsl_shader 1 #define VK_NV_GLSL_SHADER_SPEC_VERSION 1 #define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" #define VK_IMG_filter_cubic 1 #define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 #define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" #define VK_AMD_rasterization_order 1 #define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 #define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" typedef enum VkRasterizationOrderAMD { VK_RASTERIZATION_ORDER_STRICT_AMD = 0, VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF } VkRasterizationOrderAMD; typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { VkStructureType sType; const void* pNext; VkRasterizationOrderAMD rasterizationOrder; } VkPipelineRasterizationStateRasterizationOrderAMD; #define VK_EXT_debug_marker 1 #define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3 #define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" typedef struct VkDebugMarkerObjectNameInfoEXT { VkStructureType sType; const void* pNext; VkDebugReportObjectTypeEXT objectType; uint64_t object; const char* pObjectName; } VkDebugMarkerObjectNameInfoEXT; typedef struct VkDebugMarkerObjectTagInfoEXT { VkStructureType sType; const void* pNext; VkDebugReportObjectTypeEXT objectType; uint64_t object; uint64_t tagName; size_t tagSize; const void* pTag; } VkDebugMarkerObjectTagInfoEXT; typedef struct VkDebugMarkerMarkerInfoEXT { VkStructureType sType; const void* pNext; const char* pMarkerName; float color[4]; } VkDebugMarkerMarkerInfoEXT; typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo); typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo); typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); #ifndef VK_NO_PROTOTYPES VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo); VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo); VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( VkCommandBuffer commandBuffer); VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo); #endif #ifdef __cplusplus } #endif #endif vulkan/include/vulkan/vulkan_loader_data.h0100644 0000000 0000000 00000001674 13077405420 020032 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef VULKAN_VULKAN_LOADER_DATA_H #define VULKAN_VULKAN_LOADER_DATA_H #include struct android_namespace_t; namespace vulkan { struct LoaderData { std::string layer_path; android_namespace_t* app_namespace; __attribute__((visibility("default"))) static LoaderData& GetInstance(); }; } #endif vulkan/libvulkan/0040755 0000000 0000000 00000000000 13077405420 013101 5ustar000000000 0000000 vulkan/libvulkan/Android.mk0100644 0000000 0000000 00000003124 13077405420 015007 0ustar000000000 0000000 # Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_SANITIZE := integer LOCAL_CFLAGS := -DLOG_TAG=\"vulkan\" \ -DVK_USE_PLATFORM_ANDROID_KHR \ -DVK_NO_PROTOTYPES \ -std=c99 -fvisibility=hidden -fstrict-aliasing \ -Weverything -Werror \ -Wno-padded \ -Wno-switch-enum \ -Wno-undef #LOCAL_CFLAGS += -DLOG_NDEBUG=0 LOCAL_CPPFLAGS := -std=c++14 \ -Wno-c99-extensions \ -Wno-c++98-compat-pedantic \ -Wno-exit-time-destructors \ -Wno-global-constructors \ -Wno-zero-length-array LOCAL_C_INCLUDES := \ frameworks/native/vulkan/include \ system/core/libsync/include LOCAL_SRC_FILES := \ api.cpp \ api_gen.cpp \ debug_report.cpp \ driver.cpp \ driver_gen.cpp \ layers_extensions.cpp \ stubhal.cpp \ swapchain.cpp \ vulkan_loader_data.cpp LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := libziparchive LOCAL_SHARED_LIBRARIES := libhardware libsync libbase liblog libutils libcutils libz LOCAL_MODULE := libvulkan include $(BUILD_SHARED_LIBRARY) vulkan/libvulkan/api.cpp0100644 0000000 0000000 00000125620 13077405420 014361 0ustar000000000 0000000 /* * Copyright 2016 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. */ // The API layer of the loader defines Vulkan API and manages layers. The // entrypoints are generated and defined in api_dispatch.cpp. Most of them // simply find the dispatch table and jump. // // There are a few of them requiring manual code for things such as layer // discovery or chaining. They call into functions defined in this file. #include #include #include #include #include #include #include #include #include #include "api.h" #include "driver.h" #include "layers_extensions.h" namespace vulkan { namespace api { namespace { // Provide overridden layer names when there are implicit layers. No effect // otherwise. class OverrideLayerNames { public: OverrideLayerNames(bool is_instance, const VkAllocationCallbacks& allocator) : is_instance_(is_instance), allocator_(allocator), scope_(VK_SYSTEM_ALLOCATION_SCOPE_COMMAND), names_(nullptr), name_count_(0), implicit_layers_() { implicit_layers_.result = VK_SUCCESS; } ~OverrideLayerNames() { allocator_.pfnFree(allocator_.pUserData, names_); allocator_.pfnFree(allocator_.pUserData, implicit_layers_.elements); allocator_.pfnFree(allocator_.pUserData, implicit_layers_.name_pool); } VkResult Parse(const char* const* names, uint32_t count) { AddImplicitLayers(); const auto& arr = implicit_layers_; if (arr.result != VK_SUCCESS) return arr.result; // no need to override when there is no implicit layer if (!arr.count) return VK_SUCCESS; names_ = AllocateNameArray(arr.count + count); if (!names_) return VK_ERROR_OUT_OF_HOST_MEMORY; // add implicit layer names for (uint32_t i = 0; i < arr.count; i++) names_[i] = GetImplicitLayerName(i); name_count_ = arr.count; // add explicit layer names for (uint32_t i = 0; i < count; i++) { // ignore explicit layers that are also implicit if (IsImplicitLayer(names[i])) continue; names_[name_count_++] = names[i]; } return VK_SUCCESS; } const char* const* Names() const { return names_; } uint32_t Count() const { return name_count_; } private: struct ImplicitLayer { int priority; size_t name_offset; }; struct ImplicitLayerArray { ImplicitLayer* elements; uint32_t max_count; uint32_t count; char* name_pool; size_t max_pool_size; size_t pool_size; VkResult result; }; void AddImplicitLayers() { if (!is_instance_ || !driver::Debuggable()) return; ParseDebugVulkanLayers(); property_list(ParseDebugVulkanLayer, this); // sort by priorities auto& arr = implicit_layers_; std::sort(arr.elements, arr.elements + arr.count, [](const ImplicitLayer& a, const ImplicitLayer& b) { return (a.priority < b.priority); }); } void ParseDebugVulkanLayers() { // debug.vulkan.layers specifies colon-separated layer names char prop[PROPERTY_VALUE_MAX]; if (!property_get("debug.vulkan.layers", prop, "")) return; // assign negative/high priorities to them int prio = -PROPERTY_VALUE_MAX; const char* p = prop; const char* delim; while ((delim = strchr(p, ':'))) { if (delim > p) AddImplicitLayer(prio, p, static_cast(delim - p)); prio++; p = delim + 1; } if (p[0] != '\0') AddImplicitLayer(prio, p, strlen(p)); } static void ParseDebugVulkanLayer(const char* key, const char* val, void* user_data) { static const char prefix[] = "debug.vulkan.layer."; const size_t prefix_len = sizeof(prefix) - 1; if (strncmp(key, prefix, prefix_len) || val[0] == '\0') return; key += prefix_len; // debug.vulkan.layer. int priority = -1; if (key[0] >= '0' && key[0] <= '9') priority = atoi(key); if (priority < 0) { ALOGW("Ignored implicit layer %s with invalid priority %s", val, key); return; } OverrideLayerNames& override_layers = *reinterpret_cast(user_data); override_layers.AddImplicitLayer(priority, val, strlen(val)); } void AddImplicitLayer(int priority, const char* name, size_t len) { if (!GrowImplicitLayerArray(1, 0)) return; auto& arr = implicit_layers_; auto& layer = arr.elements[arr.count++]; layer.priority = priority; layer.name_offset = AddImplicitLayerName(name, len); ALOGV("Added implicit layer %s", GetImplicitLayerName(arr.count - 1)); } size_t AddImplicitLayerName(const char* name, size_t len) { if (!GrowImplicitLayerArray(0, len + 1)) return 0; // add the name to the pool auto& arr = implicit_layers_; size_t offset = arr.pool_size; char* dst = arr.name_pool + offset; std::copy(name, name + len, dst); dst[len] = '\0'; arr.pool_size += len + 1; return offset; } bool GrowImplicitLayerArray(uint32_t layer_count, size_t name_size) { const uint32_t initial_max_count = 16; const size_t initial_max_pool_size = 512; auto& arr = implicit_layers_; // grow the element array if needed while (arr.count + layer_count > arr.max_count) { uint32_t new_max_count = (arr.max_count) ? (arr.max_count << 1) : initial_max_count; void* new_mem = nullptr; if (new_max_count > arr.max_count) { new_mem = allocator_.pfnReallocation( allocator_.pUserData, arr.elements, sizeof(ImplicitLayer) * new_max_count, alignof(ImplicitLayer), scope_); } if (!new_mem) { arr.result = VK_ERROR_OUT_OF_HOST_MEMORY; arr.count = 0; return false; } arr.elements = reinterpret_cast(new_mem); arr.max_count = new_max_count; } // grow the name pool if needed while (arr.pool_size + name_size > arr.max_pool_size) { size_t new_max_pool_size = (arr.max_pool_size) ? (arr.max_pool_size << 1) : initial_max_pool_size; void* new_mem = nullptr; if (new_max_pool_size > arr.max_pool_size) { new_mem = allocator_.pfnReallocation( allocator_.pUserData, arr.name_pool, new_max_pool_size, alignof(char), scope_); } if (!new_mem) { arr.result = VK_ERROR_OUT_OF_HOST_MEMORY; arr.pool_size = 0; return false; } arr.name_pool = reinterpret_cast(new_mem); arr.max_pool_size = new_max_pool_size; } return true; } const char* GetImplicitLayerName(uint32_t index) const { const auto& arr = implicit_layers_; // this may return nullptr when arr.result is not VK_SUCCESS return implicit_layers_.name_pool + arr.elements[index].name_offset; } bool IsImplicitLayer(const char* name) const { const auto& arr = implicit_layers_; for (uint32_t i = 0; i < arr.count; i++) { if (strcmp(name, GetImplicitLayerName(i)) == 0) return true; } return false; } const char** AllocateNameArray(uint32_t count) const { return reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(const char*) * count, alignof(const char*), scope_)); } const bool is_instance_; const VkAllocationCallbacks& allocator_; const VkSystemAllocationScope scope_; const char** names_; uint32_t name_count_; ImplicitLayerArray implicit_layers_; }; // Provide overridden extension names when there are implicit extensions. // No effect otherwise. // // This is used only to enable VK_EXT_debug_report. class OverrideExtensionNames { public: OverrideExtensionNames(bool is_instance, const VkAllocationCallbacks& allocator) : is_instance_(is_instance), allocator_(allocator), scope_(VK_SYSTEM_ALLOCATION_SCOPE_COMMAND), names_(nullptr), name_count_(0), install_debug_callback_(false) {} ~OverrideExtensionNames() { allocator_.pfnFree(allocator_.pUserData, names_); } VkResult Parse(const char* const* names, uint32_t count) { // this is only for debug.vulkan.enable_callback if (!EnableDebugCallback()) return VK_SUCCESS; names_ = AllocateNameArray(count + 1); if (!names_) return VK_ERROR_OUT_OF_HOST_MEMORY; std::copy(names, names + count, names_); name_count_ = count; names_[name_count_++] = "VK_EXT_debug_report"; install_debug_callback_ = true; return VK_SUCCESS; } const char* const* Names() const { return names_; } uint32_t Count() const { return name_count_; } bool InstallDebugCallback() const { return install_debug_callback_; } private: bool EnableDebugCallback() const { return (is_instance_ && driver::Debuggable() && property_get_bool("debug.vulkan.enable_callback", false)); } const char** AllocateNameArray(uint32_t count) const { return reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(const char*) * count, alignof(const char*), scope_)); } const bool is_instance_; const VkAllocationCallbacks& allocator_; const VkSystemAllocationScope scope_; const char** names_; uint32_t name_count_; bool install_debug_callback_; }; // vkCreateInstance and vkCreateDevice helpers with support for layer // chaining. class LayerChain { public: struct ActiveLayer { LayerRef ref; union { VkLayerInstanceLink instance_link; VkLayerDeviceLink device_link; }; }; static VkResult CreateInstance(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* instance_out); static VkResult CreateDevice(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* dev_out); static void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* allocator); static void DestroyDevice(VkDevice dev, const VkAllocationCallbacks* allocator); static const ActiveLayer* GetActiveLayers(VkPhysicalDevice physical_dev, uint32_t& count); private: LayerChain(bool is_instance, const driver::DebugReportLogger& logger, const VkAllocationCallbacks& allocator); ~LayerChain(); VkResult ActivateLayers(const char* const* layer_names, uint32_t layer_count, const char* const* extension_names, uint32_t extension_count); VkResult ActivateLayers(VkPhysicalDevice physical_dev, const char* const* layer_names, uint32_t layer_count, const char* const* extension_names, uint32_t extension_count); ActiveLayer* AllocateLayerArray(uint32_t count) const; VkResult LoadLayer(ActiveLayer& layer, const char* name); void SetupLayerLinks(); bool Empty() const; void ModifyCreateInfo(VkInstanceCreateInfo& info); void ModifyCreateInfo(VkDeviceCreateInfo& info); VkResult Create(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* instance_out); VkResult Create(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* dev_out); VkResult ValidateExtensions(const char* const* extension_names, uint32_t extension_count); VkResult ValidateExtensions(VkPhysicalDevice physical_dev, const char* const* extension_names, uint32_t extension_count); VkExtensionProperties* AllocateDriverExtensionArray(uint32_t count) const; bool IsLayerExtension(const char* name) const; bool IsDriverExtension(const char* name) const; template void StealLayers(DataType& data); static void DestroyLayers(ActiveLayer* layers, uint32_t count, const VkAllocationCallbacks& allocator); static VKAPI_ATTR VkResult SetInstanceLoaderData(VkInstance instance, void* object); static VKAPI_ATTR VkResult SetDeviceLoaderData(VkDevice device, void* object); static VKAPI_ATTR VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT obj_type, uint64_t obj, size_t location, int32_t msg_code, const char* layer_prefix, const char* msg, void* user_data); const bool is_instance_; const driver::DebugReportLogger& logger_; const VkAllocationCallbacks& allocator_; OverrideLayerNames override_layers_; OverrideExtensionNames override_extensions_; ActiveLayer* layers_; uint32_t layer_count_; PFN_vkGetInstanceProcAddr get_instance_proc_addr_; PFN_vkGetDeviceProcAddr get_device_proc_addr_; union { VkLayerInstanceCreateInfo instance_chain_info_[2]; VkLayerDeviceCreateInfo device_chain_info_[2]; }; VkExtensionProperties* driver_extensions_; uint32_t driver_extension_count_; std::bitset enabled_extensions_; }; LayerChain::LayerChain(bool is_instance, const driver::DebugReportLogger& logger, const VkAllocationCallbacks& allocator) : is_instance_(is_instance), logger_(logger), allocator_(allocator), override_layers_(is_instance, allocator), override_extensions_(is_instance, allocator), layers_(nullptr), layer_count_(0), get_instance_proc_addr_(nullptr), get_device_proc_addr_(nullptr), driver_extensions_(nullptr), driver_extension_count_(0) { enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE); } LayerChain::~LayerChain() { allocator_.pfnFree(allocator_.pUserData, driver_extensions_); DestroyLayers(layers_, layer_count_, allocator_); } VkResult LayerChain::ActivateLayers(const char* const* layer_names, uint32_t layer_count, const char* const* extension_names, uint32_t extension_count) { VkResult result = override_layers_.Parse(layer_names, layer_count); if (result != VK_SUCCESS) return result; result = override_extensions_.Parse(extension_names, extension_count); if (result != VK_SUCCESS) return result; if (override_layers_.Count()) { layer_names = override_layers_.Names(); layer_count = override_layers_.Count(); } if (!layer_count) { // point head of chain to the driver get_instance_proc_addr_ = driver::GetInstanceProcAddr; return VK_SUCCESS; } layers_ = AllocateLayerArray(layer_count); if (!layers_) return VK_ERROR_OUT_OF_HOST_MEMORY; // load layers for (uint32_t i = 0; i < layer_count; i++) { result = LoadLayer(layers_[i], layer_names[i]); if (result != VK_SUCCESS) return result; // count loaded layers for proper destructions on errors layer_count_++; } SetupLayerLinks(); return VK_SUCCESS; } VkResult LayerChain::ActivateLayers(VkPhysicalDevice physical_dev, const char* const* layer_names, uint32_t layer_count, const char* const* extension_names, uint32_t extension_count) { uint32_t instance_layer_count; const ActiveLayer* instance_layers = GetActiveLayers(physical_dev, instance_layer_count); // log a message if the application device layer array is not empty nor an // exact match of the instance layer array. if (layer_count) { bool exact_match = (instance_layer_count == layer_count); if (exact_match) { for (uint32_t i = 0; i < instance_layer_count; i++) { const Layer& l = *instance_layers[i].ref; if (strcmp(GetLayerProperties(l).layerName, layer_names[i])) { exact_match = false; break; } } } if (!exact_match) { logger_.Warn(physical_dev, "Device layers disagree with instance layers and are " "overridden by instance layers"); } } VkResult result = override_extensions_.Parse(extension_names, extension_count); if (result != VK_SUCCESS) return result; if (!instance_layer_count) { // point head of chain to the driver get_instance_proc_addr_ = driver::GetInstanceProcAddr; get_device_proc_addr_ = driver::GetDeviceProcAddr; return VK_SUCCESS; } layers_ = AllocateLayerArray(instance_layer_count); if (!layers_) return VK_ERROR_OUT_OF_HOST_MEMORY; for (uint32_t i = 0; i < instance_layer_count; i++) { const Layer& l = *instance_layers[i].ref; // no need to and cannot chain non-global layers if (!IsLayerGlobal(l)) continue; // this never fails new (&layers_[layer_count_++]) ActiveLayer{GetLayerRef(l), {}}; } // this may happen when all layers are non-global ones if (!layer_count_) { get_instance_proc_addr_ = driver::GetInstanceProcAddr; get_device_proc_addr_ = driver::GetDeviceProcAddr; return VK_SUCCESS; } SetupLayerLinks(); return VK_SUCCESS; } LayerChain::ActiveLayer* LayerChain::AllocateLayerArray(uint32_t count) const { VkSystemAllocationScope scope = (is_instance_) ? VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE : VK_SYSTEM_ALLOCATION_SCOPE_COMMAND; return reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(ActiveLayer) * count, alignof(ActiveLayer), scope)); } VkResult LayerChain::LoadLayer(ActiveLayer& layer, const char* name) { const Layer* l = FindLayer(name); if (!l) { logger_.Err(VK_NULL_HANDLE, "Failed to find layer %s", name); return VK_ERROR_LAYER_NOT_PRESENT; } new (&layer) ActiveLayer{GetLayerRef(*l), {}}; if (!layer.ref) { ALOGW("Failed to open layer %s", name); layer.ref.~LayerRef(); return VK_ERROR_LAYER_NOT_PRESENT; } ALOGI("Loaded layer %s", name); return VK_SUCCESS; } void LayerChain::SetupLayerLinks() { if (is_instance_) { for (uint32_t i = 0; i < layer_count_; i++) { ActiveLayer& layer = layers_[i]; // point head of chain to the first layer if (i == 0) get_instance_proc_addr_ = layer.ref.GetGetInstanceProcAddr(); // point tail of chain to the driver if (i == layer_count_ - 1) { layer.instance_link.pNext = nullptr; layer.instance_link.pfnNextGetInstanceProcAddr = driver::GetInstanceProcAddr; break; } const ActiveLayer& next = layers_[i + 1]; // const_cast as some naughty layers want to modify our links! layer.instance_link.pNext = const_cast(&next.instance_link); layer.instance_link.pfnNextGetInstanceProcAddr = next.ref.GetGetInstanceProcAddr(); } } else { for (uint32_t i = 0; i < layer_count_; i++) { ActiveLayer& layer = layers_[i]; // point head of chain to the first layer if (i == 0) { get_instance_proc_addr_ = layer.ref.GetGetInstanceProcAddr(); get_device_proc_addr_ = layer.ref.GetGetDeviceProcAddr(); } // point tail of chain to the driver if (i == layer_count_ - 1) { layer.device_link.pNext = nullptr; layer.device_link.pfnNextGetInstanceProcAddr = driver::GetInstanceProcAddr; layer.device_link.pfnNextGetDeviceProcAddr = driver::GetDeviceProcAddr; break; } const ActiveLayer& next = layers_[i + 1]; // const_cast as some naughty layers want to modify our links! layer.device_link.pNext = const_cast(&next.device_link); layer.device_link.pfnNextGetInstanceProcAddr = next.ref.GetGetInstanceProcAddr(); layer.device_link.pfnNextGetDeviceProcAddr = next.ref.GetGetDeviceProcAddr(); } } } bool LayerChain::Empty() const { return (!layer_count_ && !override_layers_.Count() && !override_extensions_.Count()); } void LayerChain::ModifyCreateInfo(VkInstanceCreateInfo& info) { if (layer_count_) { auto& link_info = instance_chain_info_[1]; link_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; link_info.pNext = info.pNext; link_info.function = VK_LAYER_FUNCTION_LINK; link_info.u.pLayerInfo = &layers_[0].instance_link; auto& cb_info = instance_chain_info_[0]; cb_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; cb_info.pNext = &link_info; cb_info.function = VK_LAYER_FUNCTION_DATA_CALLBACK; cb_info.u.pfnSetInstanceLoaderData = SetInstanceLoaderData; info.pNext = &cb_info; } if (override_layers_.Count()) { info.enabledLayerCount = override_layers_.Count(); info.ppEnabledLayerNames = override_layers_.Names(); } if (override_extensions_.Count()) { info.enabledExtensionCount = override_extensions_.Count(); info.ppEnabledExtensionNames = override_extensions_.Names(); } } void LayerChain::ModifyCreateInfo(VkDeviceCreateInfo& info) { if (layer_count_) { auto& link_info = device_chain_info_[1]; link_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; link_info.pNext = info.pNext; link_info.function = VK_LAYER_FUNCTION_LINK; link_info.u.pLayerInfo = &layers_[0].device_link; auto& cb_info = device_chain_info_[0]; cb_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; cb_info.pNext = &link_info; cb_info.function = VK_LAYER_FUNCTION_DATA_CALLBACK; cb_info.u.pfnSetDeviceLoaderData = SetDeviceLoaderData; info.pNext = &cb_info; } if (override_layers_.Count()) { info.enabledLayerCount = override_layers_.Count(); info.ppEnabledLayerNames = override_layers_.Names(); } if (override_extensions_.Count()) { info.enabledExtensionCount = override_extensions_.Count(); info.ppEnabledExtensionNames = override_extensions_.Names(); } } VkResult LayerChain::Create(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* instance_out) { VkResult result = ValidateExtensions(create_info->ppEnabledExtensionNames, create_info->enabledExtensionCount); if (result != VK_SUCCESS) return result; // call down the chain PFN_vkCreateInstance create_instance = reinterpret_cast( get_instance_proc_addr_(VK_NULL_HANDLE, "vkCreateInstance")); VkInstance instance; result = create_instance(create_info, allocator, &instance); if (result != VK_SUCCESS) return result; // initialize InstanceData InstanceData& data = GetData(instance); if (!InitDispatchTable(instance, get_instance_proc_addr_, enabled_extensions_)) { if (data.dispatch.DestroyInstance) data.dispatch.DestroyInstance(instance, allocator); return VK_ERROR_INITIALIZATION_FAILED; } // install debug report callback if (override_extensions_.InstallDebugCallback()) { PFN_vkCreateDebugReportCallbackEXT create_debug_report_callback = reinterpret_cast( get_instance_proc_addr_(instance, "vkCreateDebugReportCallbackEXT")); data.destroy_debug_callback = reinterpret_cast( get_instance_proc_addr_(instance, "vkDestroyDebugReportCallbackEXT")); if (!create_debug_report_callback || !data.destroy_debug_callback) { ALOGE("Broken VK_EXT_debug_report support"); data.dispatch.DestroyInstance(instance, allocator); return VK_ERROR_INITIALIZATION_FAILED; } VkDebugReportCallbackCreateInfoEXT debug_callback_info = {}; debug_callback_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; debug_callback_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; debug_callback_info.pfnCallback = DebugReportCallback; VkDebugReportCallbackEXT debug_callback; result = create_debug_report_callback(instance, &debug_callback_info, nullptr, &debug_callback); if (result != VK_SUCCESS) { ALOGE("Failed to install debug report callback"); data.dispatch.DestroyInstance(instance, allocator); return VK_ERROR_INITIALIZATION_FAILED; } data.debug_callback = debug_callback; ALOGI("Installed debug report callback"); } StealLayers(data); *instance_out = instance; return VK_SUCCESS; } VkResult LayerChain::Create(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* dev_out) { VkResult result = ValidateExtensions(physical_dev, create_info->ppEnabledExtensionNames, create_info->enabledExtensionCount); if (result != VK_SUCCESS) return result; // call down the chain PFN_vkCreateDevice create_device = GetData(physical_dev).dispatch.CreateDevice; VkDevice dev; result = create_device(physical_dev, create_info, allocator, &dev); if (result != VK_SUCCESS) return result; // initialize DeviceData DeviceData& data = GetData(dev); if (!InitDispatchTable(dev, get_device_proc_addr_, enabled_extensions_)) { if (data.dispatch.DestroyDevice) data.dispatch.DestroyDevice(dev, allocator); return VK_ERROR_INITIALIZATION_FAILED; } // no StealLayers so that active layers are destroyed with this // LayerChain *dev_out = dev; return VK_SUCCESS; } VkResult LayerChain::ValidateExtensions(const char* const* extension_names, uint32_t extension_count) { if (!extension_count) return VK_SUCCESS; // query driver instance extensions uint32_t count; VkResult result = EnumerateInstanceExtensionProperties(nullptr, &count, nullptr); if (result == VK_SUCCESS && count) { driver_extensions_ = AllocateDriverExtensionArray(count); result = (driver_extensions_) ? EnumerateInstanceExtensionProperties( nullptr, &count, driver_extensions_) : VK_ERROR_OUT_OF_HOST_MEMORY; } if (result != VK_SUCCESS) return result; driver_extension_count_ = count; for (uint32_t i = 0; i < extension_count; i++) { const char* name = extension_names[i]; if (!IsLayerExtension(name) && !IsDriverExtension(name)) { logger_.Err(VK_NULL_HANDLE, "Failed to enable missing instance extension %s", name); return VK_ERROR_EXTENSION_NOT_PRESENT; } auto ext_bit = driver::GetProcHookExtension(name); if (ext_bit != driver::ProcHook::EXTENSION_UNKNOWN) enabled_extensions_.set(ext_bit); } return VK_SUCCESS; } VkResult LayerChain::ValidateExtensions(VkPhysicalDevice physical_dev, const char* const* extension_names, uint32_t extension_count) { if (!extension_count) return VK_SUCCESS; // query driver device extensions uint32_t count; VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr, &count, nullptr); if (result == VK_SUCCESS && count) { driver_extensions_ = AllocateDriverExtensionArray(count); result = (driver_extensions_) ? EnumerateDeviceExtensionProperties( physical_dev, nullptr, &count, driver_extensions_) : VK_ERROR_OUT_OF_HOST_MEMORY; } if (result != VK_SUCCESS) return result; driver_extension_count_ = count; for (uint32_t i = 0; i < extension_count; i++) { const char* name = extension_names[i]; if (!IsLayerExtension(name) && !IsDriverExtension(name)) { logger_.Err(physical_dev, "Failed to enable missing device extension %s", name); return VK_ERROR_EXTENSION_NOT_PRESENT; } auto ext_bit = driver::GetProcHookExtension(name); if (ext_bit != driver::ProcHook::EXTENSION_UNKNOWN) enabled_extensions_.set(ext_bit); } return VK_SUCCESS; } VkExtensionProperties* LayerChain::AllocateDriverExtensionArray( uint32_t count) const { return reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(VkExtensionProperties) * count, alignof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); } bool LayerChain::IsLayerExtension(const char* name) const { if (is_instance_) { for (uint32_t i = 0; i < layer_count_; i++) { const ActiveLayer& layer = layers_[i]; if (FindLayerInstanceExtension(*layer.ref, name)) return true; } } else { for (uint32_t i = 0; i < layer_count_; i++) { const ActiveLayer& layer = layers_[i]; if (FindLayerDeviceExtension(*layer.ref, name)) return true; } } return false; } bool LayerChain::IsDriverExtension(const char* name) const { for (uint32_t i = 0; i < driver_extension_count_; i++) { if (strcmp(driver_extensions_[i].extensionName, name) == 0) return true; } return false; } template void LayerChain::StealLayers(DataType& data) { data.layers = layers_; data.layer_count = layer_count_; layers_ = nullptr; layer_count_ = 0; } void LayerChain::DestroyLayers(ActiveLayer* layers, uint32_t count, const VkAllocationCallbacks& allocator) { for (uint32_t i = 0; i < count; i++) layers[i].ref.~LayerRef(); allocator.pfnFree(allocator.pUserData, layers); } VkResult LayerChain::SetInstanceLoaderData(VkInstance instance, void* object) { driver::InstanceDispatchable dispatchable = reinterpret_cast(object); return (driver::SetDataInternal(dispatchable, &driver::GetData(instance))) ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED; } VkResult LayerChain::SetDeviceLoaderData(VkDevice device, void* object) { driver::DeviceDispatchable dispatchable = reinterpret_cast(object); return (driver::SetDataInternal(dispatchable, &driver::GetData(device))) ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED; } VkBool32 LayerChain::DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT obj_type, uint64_t obj, size_t location, int32_t msg_code, const char* layer_prefix, const char* msg, void* user_data) { int prio; if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) prio = ANDROID_LOG_ERROR; else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) prio = ANDROID_LOG_WARN; else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) prio = ANDROID_LOG_INFO; else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) prio = ANDROID_LOG_DEBUG; else prio = ANDROID_LOG_UNKNOWN; LOG_PRI(prio, LOG_TAG, "[%s] Code %d : %s", layer_prefix, msg_code, msg); (void)obj_type; (void)obj; (void)location; (void)user_data; return false; } VkResult LayerChain::CreateInstance(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* instance_out) { LayerChain chain(true, driver::DebugReportLogger(*create_info), (allocator) ? *allocator : driver::GetDefaultAllocator()); VkResult result = chain.ActivateLayers(create_info->ppEnabledLayerNames, create_info->enabledLayerCount, create_info->ppEnabledExtensionNames, create_info->enabledExtensionCount); if (result != VK_SUCCESS) return result; // use a local create info when the chain is not empty VkInstanceCreateInfo local_create_info; if (!chain.Empty()) { local_create_info = *create_info; chain.ModifyCreateInfo(local_create_info); create_info = &local_create_info; } return chain.Create(create_info, allocator, instance_out); } VkResult LayerChain::CreateDevice(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* dev_out) { LayerChain chain( false, driver::Logger(physical_dev), (allocator) ? *allocator : driver::GetData(physical_dev).allocator); VkResult result = chain.ActivateLayers( physical_dev, create_info->ppEnabledLayerNames, create_info->enabledLayerCount, create_info->ppEnabledExtensionNames, create_info->enabledExtensionCount); if (result != VK_SUCCESS) return result; // use a local create info when the chain is not empty VkDeviceCreateInfo local_create_info; if (!chain.Empty()) { local_create_info = *create_info; chain.ModifyCreateInfo(local_create_info); create_info = &local_create_info; } return chain.Create(physical_dev, create_info, allocator, dev_out); } void LayerChain::DestroyInstance(VkInstance instance, const VkAllocationCallbacks* allocator) { InstanceData& data = GetData(instance); if (data.debug_callback != VK_NULL_HANDLE) data.destroy_debug_callback(instance, data.debug_callback, allocator); ActiveLayer* layers = reinterpret_cast(data.layers); uint32_t layer_count = data.layer_count; VkAllocationCallbacks local_allocator; if (!allocator) local_allocator = driver::GetData(instance).allocator; // this also destroys InstanceData data.dispatch.DestroyInstance(instance, allocator); DestroyLayers(layers, layer_count, (allocator) ? *allocator : local_allocator); } void LayerChain::DestroyDevice(VkDevice device, const VkAllocationCallbacks* allocator) { DeviceData& data = GetData(device); // this also destroys DeviceData data.dispatch.DestroyDevice(device, allocator); } const LayerChain::ActiveLayer* LayerChain::GetActiveLayers( VkPhysicalDevice physical_dev, uint32_t& count) { count = GetData(physical_dev).layer_count; return reinterpret_cast(GetData(physical_dev).layers); } // ---------------------------------------------------------------------------- bool EnsureInitialized() { static std::once_flag once_flag; static bool initialized; std::call_once(once_flag, []() { if (driver::OpenHAL()) { DiscoverLayers(); initialized = true; } }); return initialized; } } // anonymous namespace VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { if (!EnsureInitialized()) return VK_ERROR_INITIALIZATION_FAILED; return LayerChain::CreateInstance(pCreateInfo, pAllocator, pInstance); } void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator) { if (instance != VK_NULL_HANDLE) LayerChain::DestroyInstance(instance, pAllocator); } VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); } void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { if (device != VK_NULL_HANDLE) LayerChain::DestroyDevice(device, pAllocator); } VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties) { if (!EnsureInitialized()) return VK_ERROR_INITIALIZATION_FAILED; uint32_t count = GetLayerCount(); if (!pProperties) { *pPropertyCount = count; return VK_SUCCESS; } uint32_t copied = std::min(*pPropertyCount, count); for (uint32_t i = 0; i < copied; i++) pProperties[i] = GetLayerProperties(GetLayer(i)); *pPropertyCount = copied; return (copied == count) ? VK_SUCCESS : VK_INCOMPLETE; } VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { if (!EnsureInitialized()) return VK_ERROR_INITIALIZATION_FAILED; if (pLayerName) { const Layer* layer = FindLayer(pLayerName); if (!layer) return VK_ERROR_LAYER_NOT_PRESENT; uint32_t count; const VkExtensionProperties* props = GetLayerInstanceExtensions(*layer, count); if (!pProperties || *pPropertyCount > count) *pPropertyCount = count; if (pProperties) std::copy(props, props + *pPropertyCount, pProperties); return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } // TODO how about extensions from implicitly enabled layers? return vulkan::driver::EnumerateInstanceExtensionProperties( nullptr, pPropertyCount, pProperties); } VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties) { uint32_t count; const LayerChain::ActiveLayer* layers = LayerChain::GetActiveLayers(physicalDevice, count); if (!pProperties) { *pPropertyCount = count; return VK_SUCCESS; } uint32_t copied = std::min(*pPropertyCount, count); for (uint32_t i = 0; i < copied; i++) pProperties[i] = GetLayerProperties(*layers[i].ref); *pPropertyCount = copied; return (copied == count) ? VK_SUCCESS : VK_INCOMPLETE; } VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { if (pLayerName) { // EnumerateDeviceLayerProperties enumerates active layers for // backward compatibility. The extension query here should work for // all layers. const Layer* layer = FindLayer(pLayerName); if (!layer) return VK_ERROR_LAYER_NOT_PRESENT; uint32_t count; const VkExtensionProperties* props = GetLayerDeviceExtensions(*layer, count); if (!pProperties || *pPropertyCount > count) *pPropertyCount = count; if (pProperties) std::copy(props, props + *pPropertyCount, pProperties); return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } // TODO how about extensions from implicitly enabled layers? const InstanceData& data = GetData(physicalDevice); return data.dispatch.EnumerateDeviceExtensionProperties( physicalDevice, nullptr, pPropertyCount, pProperties); } } // namespace api } // namespace vulkan vulkan/libvulkan/api.h0100644 0000000 0000000 00000004654 13077405420 014031 0ustar000000000 0000000 /* * Copyright 2016 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 LIBVULKAN_API_H #define LIBVULKAN_API_H 1 #include #include "api_gen.h" #include "driver.h" namespace vulkan { namespace api { // clang-format off VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); // clang-format on inline InstanceData& GetData(VkInstance instance) { return driver::GetData(instance).opaque_api_data; } inline InstanceData& GetData(VkPhysicalDevice physical_dev) { return driver::GetData(physical_dev).opaque_api_data; } inline DeviceData& GetData(VkDevice dev) { return driver::GetData(dev).opaque_api_data; } inline DeviceData& GetData(VkQueue queue) { return driver::GetData(queue).opaque_api_data; } inline DeviceData& GetData(VkCommandBuffer cmd) { return driver::GetData(cmd).opaque_api_data; } } // namespace api } // namespace vulkan #endif // LIBVULKAN_API_H vulkan/libvulkan/api_gen.cpp0100644 0000000 0000000 00000361342 13077405420 015215 0ustar000000000 0000000 /* * Copyright 2016 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. */ // WARNING: This file is generated. See ../README.md for instructions. #include #include #include // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" namespace vulkan { namespace api { #define UNLIKELY(expr) __builtin_expect((expr), 0) #define INIT_PROC(obj, proc) \ do { \ data.dispatch.proc = \ reinterpret_cast(get_proc(obj, "vk" #proc)); \ if (UNLIKELY(!data.dispatch.proc)) { \ ALOGE("missing " #obj " proc: vk" #proc); \ success = false; \ } \ } while (0) // Exported extension functions may be invoked even when their extensions // are disabled. Dispatch to stubs when that happens. #define INIT_PROC_EXT(ext, obj, proc) \ do { \ if (extensions[driver::ProcHook::ext]) \ INIT_PROC(obj, proc); \ else \ data.dispatch.proc = disabled##proc; \ } while (0) namespace { // clang-format off VKAPI_ATTR void disabledDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR, const VkAllocationCallbacks*) { driver::Logger(instance).Err(instance, "VK_KHR_surface not enabled. Exported vkDestroySurfaceKHR not executed."); } VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t, VkSurfaceKHR, VkBool32*) { driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_surface not enabled. Exported vkGetPhysicalDeviceSurfaceSupportKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*) { driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_surface not enabled. Exported vkGetPhysicalDeviceSurfaceCapabilitiesKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*) { driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_surface not enabled. Exported vkGetPhysicalDeviceSurfaceFormatsKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*) { driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_surface not enabled. Exported vkGetPhysicalDeviceSurfacePresentModesKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*) { driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkCreateSwapchainKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR void disabledDestroySwapchainKHR(VkDevice device, VkSwapchainKHR, const VkAllocationCallbacks*) { driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkDestroySwapchainKHR not executed."); } VKAPI_ATTR VkResult disabledGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR, uint32_t*, VkImage*) { driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetSwapchainImagesKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledAcquireNextImageKHR(VkDevice device, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t*) { driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImageKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR*) { driver::Logger(queue).Err(queue, "VK_KHR_swapchain not enabled. Exported vkQueuePresentKHR not executed."); return VK_SUCCESS; } VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) { driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed."); return VK_SUCCESS; } // clang-format on } // anonymous bool InitDispatchTable( VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset& extensions) { auto& data = GetData(instance); bool success = true; // clang-format off INIT_PROC(instance, DestroyInstance); INIT_PROC(instance, EnumeratePhysicalDevices); INIT_PROC(instance, GetInstanceProcAddr); INIT_PROC(instance, GetPhysicalDeviceProperties); INIT_PROC(instance, GetPhysicalDeviceQueueFamilyProperties); INIT_PROC(instance, GetPhysicalDeviceMemoryProperties); INIT_PROC(instance, GetPhysicalDeviceFeatures); INIT_PROC(instance, GetPhysicalDeviceFormatProperties); INIT_PROC(instance, GetPhysicalDeviceImageFormatProperties); INIT_PROC(instance, CreateDevice); INIT_PROC(instance, EnumerateDeviceExtensionProperties); INIT_PROC(instance, GetPhysicalDeviceSparseImageFormatProperties); INIT_PROC_EXT(KHR_surface, instance, DestroySurfaceKHR); INIT_PROC_EXT(KHR_surface, instance, GetPhysicalDeviceSurfaceSupportKHR); INIT_PROC_EXT(KHR_surface, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR); INIT_PROC_EXT(KHR_surface, instance, GetPhysicalDeviceSurfaceFormatsKHR); INIT_PROC_EXT(KHR_surface, instance, GetPhysicalDeviceSurfacePresentModesKHR); INIT_PROC_EXT(KHR_android_surface, instance, CreateAndroidSurfaceKHR); // clang-format on return success; } bool InitDispatchTable( VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset& extensions) { auto& data = GetData(dev); bool success = true; // clang-format off INIT_PROC(dev, GetDeviceProcAddr); INIT_PROC(dev, DestroyDevice); INIT_PROC(dev, GetDeviceQueue); INIT_PROC(dev, QueueSubmit); INIT_PROC(dev, QueueWaitIdle); INIT_PROC(dev, DeviceWaitIdle); INIT_PROC(dev, AllocateMemory); INIT_PROC(dev, FreeMemory); INIT_PROC(dev, MapMemory); INIT_PROC(dev, UnmapMemory); INIT_PROC(dev, FlushMappedMemoryRanges); INIT_PROC(dev, InvalidateMappedMemoryRanges); INIT_PROC(dev, GetDeviceMemoryCommitment); INIT_PROC(dev, GetBufferMemoryRequirements); INIT_PROC(dev, BindBufferMemory); INIT_PROC(dev, GetImageMemoryRequirements); INIT_PROC(dev, BindImageMemory); INIT_PROC(dev, GetImageSparseMemoryRequirements); INIT_PROC(dev, QueueBindSparse); INIT_PROC(dev, CreateFence); INIT_PROC(dev, DestroyFence); INIT_PROC(dev, ResetFences); INIT_PROC(dev, GetFenceStatus); INIT_PROC(dev, WaitForFences); INIT_PROC(dev, CreateSemaphore); INIT_PROC(dev, DestroySemaphore); INIT_PROC(dev, CreateEvent); INIT_PROC(dev, DestroyEvent); INIT_PROC(dev, GetEventStatus); INIT_PROC(dev, SetEvent); INIT_PROC(dev, ResetEvent); INIT_PROC(dev, CreateQueryPool); INIT_PROC(dev, DestroyQueryPool); INIT_PROC(dev, GetQueryPoolResults); INIT_PROC(dev, CreateBuffer); INIT_PROC(dev, DestroyBuffer); INIT_PROC(dev, CreateBufferView); INIT_PROC(dev, DestroyBufferView); INIT_PROC(dev, CreateImage); INIT_PROC(dev, DestroyImage); INIT_PROC(dev, GetImageSubresourceLayout); INIT_PROC(dev, CreateImageView); INIT_PROC(dev, DestroyImageView); INIT_PROC(dev, CreateShaderModule); INIT_PROC(dev, DestroyShaderModule); INIT_PROC(dev, CreatePipelineCache); INIT_PROC(dev, DestroyPipelineCache); INIT_PROC(dev, GetPipelineCacheData); INIT_PROC(dev, MergePipelineCaches); INIT_PROC(dev, CreateGraphicsPipelines); INIT_PROC(dev, CreateComputePipelines); INIT_PROC(dev, DestroyPipeline); INIT_PROC(dev, CreatePipelineLayout); INIT_PROC(dev, DestroyPipelineLayout); INIT_PROC(dev, CreateSampler); INIT_PROC(dev, DestroySampler); INIT_PROC(dev, CreateDescriptorSetLayout); INIT_PROC(dev, DestroyDescriptorSetLayout); INIT_PROC(dev, CreateDescriptorPool); INIT_PROC(dev, DestroyDescriptorPool); INIT_PROC(dev, ResetDescriptorPool); INIT_PROC(dev, AllocateDescriptorSets); INIT_PROC(dev, FreeDescriptorSets); INIT_PROC(dev, UpdateDescriptorSets); INIT_PROC(dev, CreateFramebuffer); INIT_PROC(dev, DestroyFramebuffer); INIT_PROC(dev, CreateRenderPass); INIT_PROC(dev, DestroyRenderPass); INIT_PROC(dev, GetRenderAreaGranularity); INIT_PROC(dev, CreateCommandPool); INIT_PROC(dev, DestroyCommandPool); INIT_PROC(dev, ResetCommandPool); INIT_PROC(dev, AllocateCommandBuffers); INIT_PROC(dev, FreeCommandBuffers); INIT_PROC(dev, BeginCommandBuffer); INIT_PROC(dev, EndCommandBuffer); INIT_PROC(dev, ResetCommandBuffer); INIT_PROC(dev, CmdBindPipeline); INIT_PROC(dev, CmdSetViewport); INIT_PROC(dev, CmdSetScissor); INIT_PROC(dev, CmdSetLineWidth); INIT_PROC(dev, CmdSetDepthBias); INIT_PROC(dev, CmdSetBlendConstants); INIT_PROC(dev, CmdSetDepthBounds); INIT_PROC(dev, CmdSetStencilCompareMask); INIT_PROC(dev, CmdSetStencilWriteMask); INIT_PROC(dev, CmdSetStencilReference); INIT_PROC(dev, CmdBindDescriptorSets); INIT_PROC(dev, CmdBindIndexBuffer); INIT_PROC(dev, CmdBindVertexBuffers); INIT_PROC(dev, CmdDraw); INIT_PROC(dev, CmdDrawIndexed); INIT_PROC(dev, CmdDrawIndirect); INIT_PROC(dev, CmdDrawIndexedIndirect); INIT_PROC(dev, CmdDispatch); INIT_PROC(dev, CmdDispatchIndirect); INIT_PROC(dev, CmdCopyBuffer); INIT_PROC(dev, CmdCopyImage); INIT_PROC(dev, CmdBlitImage); INIT_PROC(dev, CmdCopyBufferToImage); INIT_PROC(dev, CmdCopyImageToBuffer); INIT_PROC(dev, CmdUpdateBuffer); INIT_PROC(dev, CmdFillBuffer); INIT_PROC(dev, CmdClearColorImage); INIT_PROC(dev, CmdClearDepthStencilImage); INIT_PROC(dev, CmdClearAttachments); INIT_PROC(dev, CmdResolveImage); INIT_PROC(dev, CmdSetEvent); INIT_PROC(dev, CmdResetEvent); INIT_PROC(dev, CmdWaitEvents); INIT_PROC(dev, CmdPipelineBarrier); INIT_PROC(dev, CmdBeginQuery); INIT_PROC(dev, CmdEndQuery); INIT_PROC(dev, CmdResetQueryPool); INIT_PROC(dev, CmdWriteTimestamp); INIT_PROC(dev, CmdCopyQueryPoolResults); INIT_PROC(dev, CmdPushConstants); INIT_PROC(dev, CmdBeginRenderPass); INIT_PROC(dev, CmdNextSubpass); INIT_PROC(dev, CmdEndRenderPass); INIT_PROC(dev, CmdExecuteCommands); INIT_PROC_EXT(KHR_swapchain, dev, CreateSwapchainKHR); INIT_PROC_EXT(KHR_swapchain, dev, DestroySwapchainKHR); INIT_PROC_EXT(KHR_swapchain, dev, GetSwapchainImagesKHR); INIT_PROC_EXT(KHR_swapchain, dev, AcquireNextImageKHR); INIT_PROC_EXT(KHR_swapchain, dev, QueuePresentKHR); // clang-format on return success; } // clang-format off namespace { // forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName); VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName); VKAPI_ATTR void GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); VKAPI_ATTR void GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); VKAPI_ATTR void GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); VKAPI_ATTR void GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); VKAPI_ATTR VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); VKAPI_ATTR VkResult QueueWaitIdle(VkQueue queue); VKAPI_ATTR VkResult DeviceWaitIdle(VkDevice device); VKAPI_ATTR VkResult AllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); VKAPI_ATTR void FreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult MapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); VKAPI_ATTR void UnmapMemory(VkDevice device, VkDeviceMemory memory); VKAPI_ATTR VkResult FlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR VkResult InvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR void GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); VKAPI_ATTR void GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR VkResult BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR void GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR VkResult BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR void GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); VKAPI_ATTR VkResult QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); VKAPI_ATTR VkResult CreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); VKAPI_ATTR void DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences); VKAPI_ATTR VkResult GetFenceStatus(VkDevice device, VkFence fence); VKAPI_ATTR VkResult WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); VKAPI_ATTR VkResult CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); VKAPI_ATTR void DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); VKAPI_ATTR void DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetEventStatus(VkDevice device, VkEvent event); VKAPI_ATTR VkResult SetEvent(VkDevice device, VkEvent event); VKAPI_ATTR VkResult ResetEvent(VkDevice device, VkEvent event); VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); VKAPI_ATTR void DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); VKAPI_ATTR void DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); VKAPI_ATTR VkResult CreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); VKAPI_ATTR void DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); VKAPI_ATTR void DestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); VKAPI_ATTR void DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); VKAPI_ATTR VkResult MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); VKAPI_ATTR VkResult CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR VkResult CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR void DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); VKAPI_ATTR void DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); VKAPI_ATTR void DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); VKAPI_ATTR void DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); VKAPI_ATTR void DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); VKAPI_ATTR VkResult AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); VKAPI_ATTR VkResult FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); VKAPI_ATTR void UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); VKAPI_ATTR VkResult CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); VKAPI_ATTR void DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); VKAPI_ATTR void DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void GetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); VKAPI_ATTR VkResult CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); VKAPI_ATTR void DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); VKAPI_ATTR void FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); VKAPI_ATTR VkResult BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); VKAPI_ATTR VkResult EndCommandBuffer(VkCommandBuffer commandBuffer); VKAPI_ATTR VkResult ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); VKAPI_ATTR void CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); VKAPI_ATTR void CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); VKAPI_ATTR void CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); VKAPI_ATTR void CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth); VKAPI_ATTR void CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); VKAPI_ATTR void CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]); VKAPI_ATTR void CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); VKAPI_ATTR void CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); VKAPI_ATTR void CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); VKAPI_ATTR void CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); VKAPI_ATTR void CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); VKAPI_ATTR void CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); VKAPI_ATTR void CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); VKAPI_ATTR void CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); VKAPI_ATTR void CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); VKAPI_ATTR void CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); VKAPI_ATTR void CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); VKAPI_ATTR void CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData); VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); VKAPI_ATTR void CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); VKAPI_ATTR void CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); VKAPI_ATTR void CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); VKAPI_ATTR void CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR void CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) { return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices); } VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) { if (device == VK_NULL_HANDLE) { ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call"); return nullptr; } static const char* const known_non_device_names[] = { "vkCreateAndroidSurfaceKHR", "vkCreateDebugReportCallbackEXT", "vkCreateDevice", "vkCreateInstance", "vkDebugReportMessageEXT", "vkDestroyDebugReportCallbackEXT", "vkDestroyInstance", "vkDestroySurfaceKHR", "vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceLayerProperties", "vkEnumerateInstanceExtensionProperties", "vkEnumerateInstanceLayerProperties", "vkEnumeratePhysicalDevices", "vkGetInstanceProcAddr", "vkGetPhysicalDeviceFeatures", "vkGetPhysicalDeviceFormatProperties", "vkGetPhysicalDeviceImageFormatProperties", "vkGetPhysicalDeviceMemoryProperties", "vkGetPhysicalDeviceProperties", "vkGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceSparseImageFormatProperties", "vkGetPhysicalDeviceSurfaceCapabilitiesKHR", "vkGetPhysicalDeviceSurfaceFormatsKHR", "vkGetPhysicalDeviceSurfacePresentModesKHR", "vkGetPhysicalDeviceSurfaceSupportKHR", }; // clang-format on constexpr size_t count = sizeof(known_non_device_names) / sizeof(known_non_device_names[0]); if (!pName || std::binary_search( known_non_device_names, known_non_device_names + count, pName, [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) { vulkan::driver::Logger(device).Err( device, "invalid vkGetDeviceProcAddr(%p, \"%s\") call", device, (pName) ? pName : "(null)"); return nullptr; } // clang-format off if (strcmp(pName, "vkGetDeviceProcAddr") == 0) return reinterpret_cast(GetDeviceProcAddr); if (strcmp(pName, "vkDestroyDevice") == 0) return reinterpret_cast(DestroyDevice); return GetData(device).dispatch.GetDeviceProcAddr(device, pName); } VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { // global functions if (instance == VK_NULL_HANDLE) { if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast(CreateInstance); if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast(EnumerateInstanceLayerProperties); if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast(EnumerateInstanceExtensionProperties); ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName); return nullptr; } static const struct Hook { const char* name; PFN_vkVoidFunction proc; } hooks[] = { { "vkAcquireNextImageKHR", reinterpret_cast(AcquireNextImageKHR) }, { "vkAllocateCommandBuffers", reinterpret_cast(AllocateCommandBuffers) }, { "vkAllocateDescriptorSets", reinterpret_cast(AllocateDescriptorSets) }, { "vkAllocateMemory", reinterpret_cast(AllocateMemory) }, { "vkBeginCommandBuffer", reinterpret_cast(BeginCommandBuffer) }, { "vkBindBufferMemory", reinterpret_cast(BindBufferMemory) }, { "vkBindImageMemory", reinterpret_cast(BindImageMemory) }, { "vkCmdBeginQuery", reinterpret_cast(CmdBeginQuery) }, { "vkCmdBeginRenderPass", reinterpret_cast(CmdBeginRenderPass) }, { "vkCmdBindDescriptorSets", reinterpret_cast(CmdBindDescriptorSets) }, { "vkCmdBindIndexBuffer", reinterpret_cast(CmdBindIndexBuffer) }, { "vkCmdBindPipeline", reinterpret_cast(CmdBindPipeline) }, { "vkCmdBindVertexBuffers", reinterpret_cast(CmdBindVertexBuffers) }, { "vkCmdBlitImage", reinterpret_cast(CmdBlitImage) }, { "vkCmdClearAttachments", reinterpret_cast(CmdClearAttachments) }, { "vkCmdClearColorImage", reinterpret_cast(CmdClearColorImage) }, { "vkCmdClearDepthStencilImage", reinterpret_cast(CmdClearDepthStencilImage) }, { "vkCmdCopyBuffer", reinterpret_cast(CmdCopyBuffer) }, { "vkCmdCopyBufferToImage", reinterpret_cast(CmdCopyBufferToImage) }, { "vkCmdCopyImage", reinterpret_cast(CmdCopyImage) }, { "vkCmdCopyImageToBuffer", reinterpret_cast(CmdCopyImageToBuffer) }, { "vkCmdCopyQueryPoolResults", reinterpret_cast(CmdCopyQueryPoolResults) }, { "vkCmdDispatch", reinterpret_cast(CmdDispatch) }, { "vkCmdDispatchIndirect", reinterpret_cast(CmdDispatchIndirect) }, { "vkCmdDraw", reinterpret_cast(CmdDraw) }, { "vkCmdDrawIndexed", reinterpret_cast(CmdDrawIndexed) }, { "vkCmdDrawIndexedIndirect", reinterpret_cast(CmdDrawIndexedIndirect) }, { "vkCmdDrawIndirect", reinterpret_cast(CmdDrawIndirect) }, { "vkCmdEndQuery", reinterpret_cast(CmdEndQuery) }, { "vkCmdEndRenderPass", reinterpret_cast(CmdEndRenderPass) }, { "vkCmdExecuteCommands", reinterpret_cast(CmdExecuteCommands) }, { "vkCmdFillBuffer", reinterpret_cast(CmdFillBuffer) }, { "vkCmdNextSubpass", reinterpret_cast(CmdNextSubpass) }, { "vkCmdPipelineBarrier", reinterpret_cast(CmdPipelineBarrier) }, { "vkCmdPushConstants", reinterpret_cast(CmdPushConstants) }, { "vkCmdResetEvent", reinterpret_cast(CmdResetEvent) }, { "vkCmdResetQueryPool", reinterpret_cast(CmdResetQueryPool) }, { "vkCmdResolveImage", reinterpret_cast(CmdResolveImage) }, { "vkCmdSetBlendConstants", reinterpret_cast(CmdSetBlendConstants) }, { "vkCmdSetDepthBias", reinterpret_cast(CmdSetDepthBias) }, { "vkCmdSetDepthBounds", reinterpret_cast(CmdSetDepthBounds) }, { "vkCmdSetEvent", reinterpret_cast(CmdSetEvent) }, { "vkCmdSetLineWidth", reinterpret_cast(CmdSetLineWidth) }, { "vkCmdSetScissor", reinterpret_cast(CmdSetScissor) }, { "vkCmdSetStencilCompareMask", reinterpret_cast(CmdSetStencilCompareMask) }, { "vkCmdSetStencilReference", reinterpret_cast(CmdSetStencilReference) }, { "vkCmdSetStencilWriteMask", reinterpret_cast(CmdSetStencilWriteMask) }, { "vkCmdSetViewport", reinterpret_cast(CmdSetViewport) }, { "vkCmdUpdateBuffer", reinterpret_cast(CmdUpdateBuffer) }, { "vkCmdWaitEvents", reinterpret_cast(CmdWaitEvents) }, { "vkCmdWriteTimestamp", reinterpret_cast(CmdWriteTimestamp) }, { "vkCreateBuffer", reinterpret_cast(CreateBuffer) }, { "vkCreateBufferView", reinterpret_cast(CreateBufferView) }, { "vkCreateCommandPool", reinterpret_cast(CreateCommandPool) }, { "vkCreateComputePipelines", reinterpret_cast(CreateComputePipelines) }, { "vkCreateDescriptorPool", reinterpret_cast(CreateDescriptorPool) }, { "vkCreateDescriptorSetLayout", reinterpret_cast(CreateDescriptorSetLayout) }, { "vkCreateDevice", reinterpret_cast(CreateDevice) }, { "vkCreateEvent", reinterpret_cast(CreateEvent) }, { "vkCreateFence", reinterpret_cast(CreateFence) }, { "vkCreateFramebuffer", reinterpret_cast(CreateFramebuffer) }, { "vkCreateGraphicsPipelines", reinterpret_cast(CreateGraphicsPipelines) }, { "vkCreateImage", reinterpret_cast(CreateImage) }, { "vkCreateImageView", reinterpret_cast(CreateImageView) }, { "vkCreateInstance", nullptr }, { "vkCreatePipelineCache", reinterpret_cast(CreatePipelineCache) }, { "vkCreatePipelineLayout", reinterpret_cast(CreatePipelineLayout) }, { "vkCreateQueryPool", reinterpret_cast(CreateQueryPool) }, { "vkCreateRenderPass", reinterpret_cast(CreateRenderPass) }, { "vkCreateSampler", reinterpret_cast(CreateSampler) }, { "vkCreateSemaphore", reinterpret_cast(CreateSemaphore) }, { "vkCreateShaderModule", reinterpret_cast(CreateShaderModule) }, { "vkCreateSwapchainKHR", reinterpret_cast(CreateSwapchainKHR) }, { "vkDestroyBuffer", reinterpret_cast(DestroyBuffer) }, { "vkDestroyBufferView", reinterpret_cast(DestroyBufferView) }, { "vkDestroyCommandPool", reinterpret_cast(DestroyCommandPool) }, { "vkDestroyDescriptorPool", reinterpret_cast(DestroyDescriptorPool) }, { "vkDestroyDescriptorSetLayout", reinterpret_cast(DestroyDescriptorSetLayout) }, { "vkDestroyDevice", reinterpret_cast(DestroyDevice) }, { "vkDestroyEvent", reinterpret_cast(DestroyEvent) }, { "vkDestroyFence", reinterpret_cast(DestroyFence) }, { "vkDestroyFramebuffer", reinterpret_cast(DestroyFramebuffer) }, { "vkDestroyImage", reinterpret_cast(DestroyImage) }, { "vkDestroyImageView", reinterpret_cast(DestroyImageView) }, { "vkDestroyInstance", reinterpret_cast(DestroyInstance) }, { "vkDestroyPipeline", reinterpret_cast(DestroyPipeline) }, { "vkDestroyPipelineCache", reinterpret_cast(DestroyPipelineCache) }, { "vkDestroyPipelineLayout", reinterpret_cast(DestroyPipelineLayout) }, { "vkDestroyQueryPool", reinterpret_cast(DestroyQueryPool) }, { "vkDestroyRenderPass", reinterpret_cast(DestroyRenderPass) }, { "vkDestroySampler", reinterpret_cast(DestroySampler) }, { "vkDestroySemaphore", reinterpret_cast(DestroySemaphore) }, { "vkDestroyShaderModule", reinterpret_cast(DestroyShaderModule) }, { "vkDestroySwapchainKHR", reinterpret_cast(DestroySwapchainKHR) }, { "vkDeviceWaitIdle", reinterpret_cast(DeviceWaitIdle) }, { "vkEndCommandBuffer", reinterpret_cast(EndCommandBuffer) }, { "vkEnumerateDeviceExtensionProperties", reinterpret_cast(EnumerateDeviceExtensionProperties) }, { "vkEnumerateDeviceLayerProperties", reinterpret_cast(EnumerateDeviceLayerProperties) }, { "vkEnumerateInstanceExtensionProperties", nullptr }, { "vkEnumerateInstanceLayerProperties", nullptr }, { "vkFlushMappedMemoryRanges", reinterpret_cast(FlushMappedMemoryRanges) }, { "vkFreeCommandBuffers", reinterpret_cast(FreeCommandBuffers) }, { "vkFreeDescriptorSets", reinterpret_cast(FreeDescriptorSets) }, { "vkFreeMemory", reinterpret_cast(FreeMemory) }, { "vkGetBufferMemoryRequirements", reinterpret_cast(GetBufferMemoryRequirements) }, { "vkGetDeviceMemoryCommitment", reinterpret_cast(GetDeviceMemoryCommitment) }, { "vkGetDeviceProcAddr", reinterpret_cast(GetDeviceProcAddr) }, { "vkGetDeviceQueue", reinterpret_cast(GetDeviceQueue) }, { "vkGetEventStatus", reinterpret_cast(GetEventStatus) }, { "vkGetFenceStatus", reinterpret_cast(GetFenceStatus) }, { "vkGetImageMemoryRequirements", reinterpret_cast(GetImageMemoryRequirements) }, { "vkGetImageSparseMemoryRequirements", reinterpret_cast(GetImageSparseMemoryRequirements) }, { "vkGetImageSubresourceLayout", reinterpret_cast(GetImageSubresourceLayout) }, { "vkGetInstanceProcAddr", reinterpret_cast(GetInstanceProcAddr) }, { "vkGetPipelineCacheData", reinterpret_cast(GetPipelineCacheData) }, { "vkGetQueryPoolResults", reinterpret_cast(GetQueryPoolResults) }, { "vkGetRenderAreaGranularity", reinterpret_cast(GetRenderAreaGranularity) }, { "vkGetSwapchainImagesKHR", reinterpret_cast(GetSwapchainImagesKHR) }, { "vkInvalidateMappedMemoryRanges", reinterpret_cast(InvalidateMappedMemoryRanges) }, { "vkMapMemory", reinterpret_cast(MapMemory) }, { "vkMergePipelineCaches", reinterpret_cast(MergePipelineCaches) }, { "vkQueueBindSparse", reinterpret_cast(QueueBindSparse) }, { "vkQueuePresentKHR", reinterpret_cast(QueuePresentKHR) }, { "vkQueueSubmit", reinterpret_cast(QueueSubmit) }, { "vkQueueWaitIdle", reinterpret_cast(QueueWaitIdle) }, { "vkResetCommandBuffer", reinterpret_cast(ResetCommandBuffer) }, { "vkResetCommandPool", reinterpret_cast(ResetCommandPool) }, { "vkResetDescriptorPool", reinterpret_cast(ResetDescriptorPool) }, { "vkResetEvent", reinterpret_cast(ResetEvent) }, { "vkResetFences", reinterpret_cast(ResetFences) }, { "vkSetEvent", reinterpret_cast(SetEvent) }, { "vkUnmapMemory", reinterpret_cast(UnmapMemory) }, { "vkUpdateDescriptorSets", reinterpret_cast(UpdateDescriptorSets) }, { "vkWaitForFences", reinterpret_cast(WaitForFences) }, }; // clang-format on constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]); auto hook = std::lower_bound( hooks, hooks + count, pName, [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; }); if (hook < hooks + count && strcmp(hook->name, pName) == 0) { if (!hook->proc) { vulkan::driver::Logger(instance).Err( instance, "invalid vkGetInstanceProcAddr(%p, \"%s\") call", instance, pName); } return hook->proc; } // clang-format off return GetData(instance).dispatch.GetInstanceProcAddr(instance, pName); } VKAPI_ATTR void GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) { GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties(physicalDevice, pProperties); } VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties) { GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); } VKAPI_ATTR void GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) { GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties); } VKAPI_ATTR void GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) { GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures(physicalDevice, pFeatures); } VKAPI_ATTR void GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) { GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatProperties); } VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) { return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, flags, pImageFormatProperties); } VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) { GetData(device).dispatch.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); } VKAPI_ATTR VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) { return GetData(queue).dispatch.QueueSubmit(queue, submitCount, pSubmits, fence); } VKAPI_ATTR VkResult QueueWaitIdle(VkQueue queue) { return GetData(queue).dispatch.QueueWaitIdle(queue); } VKAPI_ATTR VkResult DeviceWaitIdle(VkDevice device) { return GetData(device).dispatch.DeviceWaitIdle(device); } VKAPI_ATTR VkResult AllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory) { return GetData(device).dispatch.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory); } VKAPI_ATTR void FreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.FreeMemory(device, memory, pAllocator); } VKAPI_ATTR VkResult MapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) { return GetData(device).dispatch.MapMemory(device, memory, offset, size, flags, ppData); } VKAPI_ATTR void UnmapMemory(VkDevice device, VkDeviceMemory memory) { GetData(device).dispatch.UnmapMemory(device, memory); } VKAPI_ATTR VkResult FlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { return GetData(device).dispatch.FlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges); } VKAPI_ATTR VkResult InvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { return GetData(device).dispatch.InvalidateMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges); } VKAPI_ATTR void GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) { GetData(device).dispatch.GetDeviceMemoryCommitment(device, memory, pCommittedMemoryInBytes); } VKAPI_ATTR void GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) { GetData(device).dispatch.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements); } VKAPI_ATTR VkResult BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) { return GetData(device).dispatch.BindBufferMemory(device, buffer, memory, memoryOffset); } VKAPI_ATTR void GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) { GetData(device).dispatch.GetImageMemoryRequirements(device, image, pMemoryRequirements); } VKAPI_ATTR VkResult BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) { return GetData(device).dispatch.BindImageMemory(device, image, memory, memoryOffset); } VKAPI_ATTR void GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { GetData(device).dispatch.GetImageSparseMemoryRequirements(device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements); } VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties) { GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pPropertyCount, pProperties); } VKAPI_ATTR VkResult QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence) { return GetData(queue).dispatch.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); } VKAPI_ATTR VkResult CreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence) { return GetData(device).dispatch.CreateFence(device, pCreateInfo, pAllocator, pFence); } VKAPI_ATTR void DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyFence(device, fence, pAllocator); } VKAPI_ATTR VkResult ResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences) { return GetData(device).dispatch.ResetFences(device, fenceCount, pFences); } VKAPI_ATTR VkResult GetFenceStatus(VkDevice device, VkFence fence) { return GetData(device).dispatch.GetFenceStatus(device, fence); } VKAPI_ATTR VkResult WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout) { return GetData(device).dispatch.WaitForFences(device, fenceCount, pFences, waitAll, timeout); } VKAPI_ATTR VkResult CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore) { return GetData(device).dispatch.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); } VKAPI_ATTR void DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroySemaphore(device, semaphore, pAllocator); } VKAPI_ATTR VkResult CreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent) { return GetData(device).dispatch.CreateEvent(device, pCreateInfo, pAllocator, pEvent); } VKAPI_ATTR void DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyEvent(device, event, pAllocator); } VKAPI_ATTR VkResult GetEventStatus(VkDevice device, VkEvent event) { return GetData(device).dispatch.GetEventStatus(device, event); } VKAPI_ATTR VkResult SetEvent(VkDevice device, VkEvent event) { return GetData(device).dispatch.SetEvent(device, event); } VKAPI_ATTR VkResult ResetEvent(VkDevice device, VkEvent event) { return GetData(device).dispatch.ResetEvent(device, event); } VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool) { return GetData(device).dispatch.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); } VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyQueryPool(device, queryPool, pAllocator); } VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags) { return GetData(device).dispatch.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags); } VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) { return GetData(device).dispatch.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); } VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyBuffer(device, buffer, pAllocator); } VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView) { return GetData(device).dispatch.CreateBufferView(device, pCreateInfo, pAllocator, pView); } VKAPI_ATTR void DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyBufferView(device, bufferView, pAllocator); } VKAPI_ATTR VkResult CreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { return GetData(device).dispatch.CreateImage(device, pCreateInfo, pAllocator, pImage); } VKAPI_ATTR void DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyImage(device, image, pAllocator); } VKAPI_ATTR void GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { GetData(device).dispatch.GetImageSubresourceLayout(device, image, pSubresource, pLayout); } VKAPI_ATTR VkResult CreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView) { return GetData(device).dispatch.CreateImageView(device, pCreateInfo, pAllocator, pView); } VKAPI_ATTR void DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyImageView(device, imageView, pAllocator); } VKAPI_ATTR VkResult CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule) { return GetData(device).dispatch.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); } VKAPI_ATTR void DestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyShaderModule(device, shaderModule, pAllocator); } VKAPI_ATTR VkResult CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache) { return GetData(device).dispatch.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache); } VKAPI_ATTR void DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyPipelineCache(device, pipelineCache, pAllocator); } VKAPI_ATTR VkResult GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData) { return GetData(device).dispatch.GetPipelineCacheData(device, pipelineCache, pDataSize, pData); } VKAPI_ATTR VkResult MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) { return GetData(device).dispatch.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches); } VKAPI_ATTR VkResult CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { return GetData(device).dispatch.CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); } VKAPI_ATTR VkResult CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { return GetData(device).dispatch.CreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); } VKAPI_ATTR void DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyPipeline(device, pipeline, pAllocator); } VKAPI_ATTR VkResult CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout) { return GetData(device).dispatch.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); } VKAPI_ATTR void DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyPipelineLayout(device, pipelineLayout, pAllocator); } VKAPI_ATTR VkResult CreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler) { return GetData(device).dispatch.CreateSampler(device, pCreateInfo, pAllocator, pSampler); } VKAPI_ATTR void DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroySampler(device, sampler, pAllocator); } VKAPI_ATTR VkResult CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout) { return GetData(device).dispatch.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); } VKAPI_ATTR void DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator); } VKAPI_ATTR VkResult CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool) { return GetData(device).dispatch.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool); } VKAPI_ATTR void DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyDescriptorPool(device, descriptorPool, pAllocator); } VKAPI_ATTR VkResult ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { return GetData(device).dispatch.ResetDescriptorPool(device, descriptorPool, flags); } VKAPI_ATTR VkResult AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets) { return GetData(device).dispatch.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); } VKAPI_ATTR VkResult FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets) { return GetData(device).dispatch.FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets); } VKAPI_ATTR void UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies) { GetData(device).dispatch.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); } VKAPI_ATTR VkResult CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer) { return GetData(device).dispatch.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); } VKAPI_ATTR void DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyFramebuffer(device, framebuffer, pAllocator); } VKAPI_ATTR VkResult CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) { return GetData(device).dispatch.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); } VKAPI_ATTR void DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyRenderPass(device, renderPass, pAllocator); } VKAPI_ATTR void GetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) { GetData(device).dispatch.GetRenderAreaGranularity(device, renderPass, pGranularity); } VKAPI_ATTR VkResult CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool) { return GetData(device).dispatch.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); } VKAPI_ATTR void DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroyCommandPool(device, commandPool, pAllocator); } VKAPI_ATTR VkResult ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { return GetData(device).dispatch.ResetCommandPool(device, commandPool, flags); } VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) { return GetData(device).dispatch.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers); } VKAPI_ATTR void FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { GetData(device).dispatch.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); } VKAPI_ATTR VkResult BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo) { return GetData(commandBuffer).dispatch.BeginCommandBuffer(commandBuffer, pBeginInfo); } VKAPI_ATTR VkResult EndCommandBuffer(VkCommandBuffer commandBuffer) { return GetData(commandBuffer).dispatch.EndCommandBuffer(commandBuffer); } VKAPI_ATTR VkResult ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { return GetData(commandBuffer).dispatch.ResetCommandBuffer(commandBuffer, flags); } VKAPI_ATTR void CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { GetData(commandBuffer).dispatch.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); } VKAPI_ATTR void CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) { GetData(commandBuffer).dispatch.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); } VKAPI_ATTR void CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) { GetData(commandBuffer).dispatch.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); } VKAPI_ATTR void CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) { GetData(commandBuffer).dispatch.CmdSetLineWidth(commandBuffer, lineWidth); } VKAPI_ATTR void CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) { GetData(commandBuffer).dispatch.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); } VKAPI_ATTR void CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) { GetData(commandBuffer).dispatch.CmdSetBlendConstants(commandBuffer, blendConstants); } VKAPI_ATTR void CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) { GetData(commandBuffer).dispatch.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds); } VKAPI_ATTR void CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) { GetData(commandBuffer).dispatch.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask); } VKAPI_ATTR void CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) { GetData(commandBuffer).dispatch.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask); } VKAPI_ATTR void CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) { GetData(commandBuffer).dispatch.CmdSetStencilReference(commandBuffer, faceMask, reference); } VKAPI_ATTR void CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) { GetData(commandBuffer).dispatch.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); } VKAPI_ATTR void CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { GetData(commandBuffer).dispatch.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); } VKAPI_ATTR void CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) { GetData(commandBuffer).dispatch.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); } VKAPI_ATTR void CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { GetData(commandBuffer).dispatch.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } VKAPI_ATTR void CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { GetData(commandBuffer).dispatch.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); } VKAPI_ATTR void CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { GetData(commandBuffer).dispatch.CmdDrawIndirect(commandBuffer, buffer, offset, drawCount, stride); } VKAPI_ATTR void CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { GetData(commandBuffer).dispatch.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride); } VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { GetData(commandBuffer).dispatch.CmdDispatch(commandBuffer, x, y, z); } VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { GetData(commandBuffer).dispatch.CmdDispatchIndirect(commandBuffer, buffer, offset); } VKAPI_ATTR void CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions) { GetData(commandBuffer).dispatch.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); } VKAPI_ATTR void CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions) { GetData(commandBuffer).dispatch.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); } VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter) { GetData(commandBuffer).dispatch.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); } VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions) { GetData(commandBuffer).dispatch.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); } VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) { GetData(commandBuffer).dispatch.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); } VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) { GetData(commandBuffer).dispatch.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); } VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { GetData(commandBuffer).dispatch.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); } VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { GetData(commandBuffer).dispatch.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); } VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { GetData(commandBuffer).dispatch.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges); } VKAPI_ATTR void CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { GetData(commandBuffer).dispatch.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects); } VKAPI_ATTR void CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions) { GetData(commandBuffer).dispatch.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); } VKAPI_ATTR void CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { GetData(commandBuffer).dispatch.CmdSetEvent(commandBuffer, event, stageMask); } VKAPI_ATTR void CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { GetData(commandBuffer).dispatch.CmdResetEvent(commandBuffer, event, stageMask); } VKAPI_ATTR void CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { GetData(commandBuffer).dispatch.CmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); } VKAPI_ATTR void CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { GetData(commandBuffer).dispatch.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); } VKAPI_ATTR void CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) { GetData(commandBuffer).dispatch.CmdBeginQuery(commandBuffer, queryPool, query, flags); } VKAPI_ATTR void CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query) { GetData(commandBuffer).dispatch.CmdEndQuery(commandBuffer, queryPool, query); } VKAPI_ATTR void CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { GetData(commandBuffer).dispatch.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); } VKAPI_ATTR void CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query) { GetData(commandBuffer).dispatch.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query); } VKAPI_ATTR void CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { GetData(commandBuffer).dispatch.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); } VKAPI_ATTR void CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) { GetData(commandBuffer).dispatch.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); } VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { GetData(commandBuffer).dispatch.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); } VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { GetData(commandBuffer).dispatch.CmdNextSubpass(commandBuffer, contents); } VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer) { GetData(commandBuffer).dispatch.CmdEndRenderPass(commandBuffer); } VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); } VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator); } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); } VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); } VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { return GetData(device).dispatch.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); } VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { GetData(device).dispatch.DestroySwapchainKHR(device, swapchain, pAllocator); } VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { return GetData(device).dispatch.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); } VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { return GetData(device).dispatch.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); } VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo); } VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } } // anonymous namespace // clang-format on } // namespace api } // namespace vulkan // clang-format off __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { return vulkan::api::CreateInstance(pCreateInfo, pAllocator, pInstance); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyInstance(instance, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) { return vulkan::api::EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices); } __attribute__((visibility("default"))) VKAPI_ATTR PFN_vkVoidFunction vkGetDeviceProcAddr(VkDevice device, const char* pName) { return vulkan::api::GetDeviceProcAddr(device, pName); } __attribute__((visibility("default"))) VKAPI_ATTR PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance instance, const char* pName) { return vulkan::api::GetInstanceProcAddr(instance, pName); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) { vulkan::api::GetPhysicalDeviceProperties(physicalDevice, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties) { vulkan::api::GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) { vulkan::api::GetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) { vulkan::api::GetPhysicalDeviceFeatures(physicalDevice, pFeatures); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) { vulkan::api::GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) { return vulkan::api::GetPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, flags, pImageFormatProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { return vulkan::api::CreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyDevice(device, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties) { return vulkan::api::EnumerateInstanceLayerProperties(pPropertyCount, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { return vulkan::api::EnumerateInstanceExtensionProperties(pLayerName, pPropertyCount, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties) { return vulkan::api::EnumerateDeviceLayerProperties(physicalDevice, pPropertyCount, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { return vulkan::api::EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pPropertyCount, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) { vulkan::api::GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) { return vulkan::api::QueueSubmit(queue, submitCount, pSubmits, fence); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkQueueWaitIdle(VkQueue queue) { return vulkan::api::QueueWaitIdle(queue); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkDeviceWaitIdle(VkDevice device) { return vulkan::api::DeviceWaitIdle(device); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory) { return vulkan::api::AllocateMemory(device, pAllocateInfo, pAllocator, pMemory); } __attribute__((visibility("default"))) VKAPI_ATTR void vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator) { vulkan::api::FreeMemory(device, memory, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) { return vulkan::api::MapMemory(device, memory, offset, size, flags, ppData); } __attribute__((visibility("default"))) VKAPI_ATTR void vkUnmapMemory(VkDevice device, VkDeviceMemory memory) { vulkan::api::UnmapMemory(device, memory); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { return vulkan::api::FlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { return vulkan::api::InvalidateMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) { vulkan::api::GetDeviceMemoryCommitment(device, memory, pCommittedMemoryInBytes); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) { vulkan::api::GetBufferMemoryRequirements(device, buffer, pMemoryRequirements); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) { return vulkan::api::BindBufferMemory(device, buffer, memory, memoryOffset); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) { vulkan::api::GetImageMemoryRequirements(device, image, pMemoryRequirements); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) { return vulkan::api::BindImageMemory(device, image, memory, memoryOffset); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { vulkan::api::GetImageSparseMemoryRequirements(device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties) { vulkan::api::GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pPropertyCount, pProperties); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence) { return vulkan::api::QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence) { return vulkan::api::CreateFence(device, pCreateInfo, pAllocator, pFence); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyFence(device, fence, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences) { return vulkan::api::ResetFences(device, fenceCount, pFences); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetFenceStatus(VkDevice device, VkFence fence) { return vulkan::api::GetFenceStatus(device, fence); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout) { return vulkan::api::WaitForFences(device, fenceCount, pFences, waitAll, timeout); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore) { return vulkan::api::CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroySemaphore(device, semaphore, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent) { return vulkan::api::CreateEvent(device, pCreateInfo, pAllocator, pEvent); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyEvent(device, event, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetEventStatus(VkDevice device, VkEvent event) { return vulkan::api::GetEventStatus(device, event); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkSetEvent(VkDevice device, VkEvent event) { return vulkan::api::SetEvent(device, event); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkResetEvent(VkDevice device, VkEvent event) { return vulkan::api::ResetEvent(device, event); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool) { return vulkan::api::CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyQueryPool(device, queryPool, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags) { return vulkan::api::GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) { return vulkan::api::CreateBuffer(device, pCreateInfo, pAllocator, pBuffer); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyBuffer(device, buffer, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView) { return vulkan::api::CreateBufferView(device, pCreateInfo, pAllocator, pView); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyBufferView(device, bufferView, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage) { return vulkan::api::CreateImage(device, pCreateInfo, pAllocator, pImage); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyImage(device, image, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { vulkan::api::GetImageSubresourceLayout(device, image, pSubresource, pLayout); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView) { return vulkan::api::CreateImageView(device, pCreateInfo, pAllocator, pView); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyImageView(device, imageView, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule) { return vulkan::api::CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyShaderModule(device, shaderModule, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache) { return vulkan::api::CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyPipelineCache(device, pipelineCache, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData) { return vulkan::api::GetPipelineCacheData(device, pipelineCache, pDataSize, pData); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) { return vulkan::api::MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { return vulkan::api::CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { return vulkan::api::CreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyPipeline(device, pipeline, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout) { return vulkan::api::CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyPipelineLayout(device, pipelineLayout, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler) { return vulkan::api::CreateSampler(device, pCreateInfo, pAllocator, pSampler); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroySampler(device, sampler, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout) { return vulkan::api::CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool) { return vulkan::api::CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyDescriptorPool(device, descriptorPool, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { return vulkan::api::ResetDescriptorPool(device, descriptorPool, flags); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets) { return vulkan::api::AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets) { return vulkan::api::FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets); } __attribute__((visibility("default"))) VKAPI_ATTR void vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies) { vulkan::api::UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer) { return vulkan::api::CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyFramebuffer(device, framebuffer, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) { return vulkan::api::CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyRenderPass(device, renderPass, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR void vkGetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) { vulkan::api::GetRenderAreaGranularity(device, renderPass, pGranularity); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool) { return vulkan::api::CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroyCommandPool(device, commandPool, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { return vulkan::api::ResetCommandPool(device, commandPool, flags); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) { return vulkan::api::AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers); } __attribute__((visibility("default"))) VKAPI_ATTR void vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { vulkan::api::FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo) { return vulkan::api::BeginCommandBuffer(commandBuffer, pBeginInfo); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEndCommandBuffer(VkCommandBuffer commandBuffer) { return vulkan::api::EndCommandBuffer(commandBuffer); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { return vulkan::api::ResetCommandBuffer(commandBuffer, flags); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { vulkan::api::CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) { vulkan::api::CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) { vulkan::api::CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) { vulkan::api::CmdSetLineWidth(commandBuffer, lineWidth); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) { vulkan::api::CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) { vulkan::api::CmdSetBlendConstants(commandBuffer, blendConstants); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) { vulkan::api::CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) { vulkan::api::CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) { vulkan::api::CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) { vulkan::api::CmdSetStencilReference(commandBuffer, faceMask, reference); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) { vulkan::api::CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { vulkan::api::CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) { vulkan::api::CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { vulkan::api::CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { vulkan::api::CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { vulkan::api::CmdDrawIndirect(commandBuffer, buffer, offset, drawCount, stride); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { vulkan::api::CmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { vulkan::api::CmdDispatch(commandBuffer, x, y, z); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { vulkan::api::CmdDispatchIndirect(commandBuffer, buffer, offset); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions) { vulkan::api::CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions) { vulkan::api::CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter) { vulkan::api::CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions) { vulkan::api::CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) { vulkan::api::CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) { vulkan::api::CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { vulkan::api::CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { vulkan::api::CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { vulkan::api::CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { vulkan::api::CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions) { vulkan::api::CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { vulkan::api::CmdSetEvent(commandBuffer, event, stageMask); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { vulkan::api::CmdResetEvent(commandBuffer, event, stageMask); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { vulkan::api::CmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { vulkan::api::CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) { vulkan::api::CmdBeginQuery(commandBuffer, queryPool, query, flags); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query) { vulkan::api::CmdEndQuery(commandBuffer, queryPool, query); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { vulkan::api::CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query) { vulkan::api::CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { vulkan::api::CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues) { vulkan::api::CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { vulkan::api::CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { vulkan::api::CmdNextSubpass(commandBuffer, contents); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdEndRenderPass(VkCommandBuffer commandBuffer) { vulkan::api::CmdEndRenderPass(commandBuffer); } __attribute__((visibility("default"))) VKAPI_ATTR void vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { vulkan::api::CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { return vulkan::api::GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { return vulkan::api::GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { return vulkan::api::GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { return vulkan::api::GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { return vulkan::api::CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); } __attribute__((visibility("default"))) VKAPI_ATTR void vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { vulkan::api::DestroySwapchainKHR(device, swapchain, pAllocator); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { return vulkan::api::GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { return vulkan::api::AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { return vulkan::api::QueuePresentKHR(queue, pPresentInfo); } __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } // clang-format on vulkan/libvulkan/api_gen.h0100644 0000000 0000000 00000020621 13077405420 014652 0ustar000000000 0000000 /* * Copyright 2016 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. */ // WARNING: This file is generated. See ../README.md for instructions. #ifndef LIBVULKAN_API_GEN_H #define LIBVULKAN_API_GEN_H #include #include #include "driver_gen.h" namespace vulkan { namespace api { struct InstanceDispatchTable { // clang-format off PFN_vkDestroyInstance DestroyInstance; PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties; PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties; PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures; PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties; PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties; PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties; PFN_vkDestroySurfaceKHR DestroySurfaceKHR; PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR; PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR; // clang-format on }; struct DeviceDispatchTable { // clang-format off PFN_vkGetDeviceProcAddr GetDeviceProcAddr; PFN_vkDestroyDevice DestroyDevice; PFN_vkGetDeviceQueue GetDeviceQueue; PFN_vkQueueSubmit QueueSubmit; PFN_vkQueueWaitIdle QueueWaitIdle; PFN_vkDeviceWaitIdle DeviceWaitIdle; PFN_vkAllocateMemory AllocateMemory; PFN_vkFreeMemory FreeMemory; PFN_vkMapMemory MapMemory; PFN_vkUnmapMemory UnmapMemory; PFN_vkFlushMappedMemoryRanges FlushMappedMemoryRanges; PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges; PFN_vkGetDeviceMemoryCommitment GetDeviceMemoryCommitment; PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements; PFN_vkBindBufferMemory BindBufferMemory; PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements; PFN_vkBindImageMemory BindImageMemory; PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements; PFN_vkQueueBindSparse QueueBindSparse; PFN_vkCreateFence CreateFence; PFN_vkDestroyFence DestroyFence; PFN_vkResetFences ResetFences; PFN_vkGetFenceStatus GetFenceStatus; PFN_vkWaitForFences WaitForFences; PFN_vkCreateSemaphore CreateSemaphore; PFN_vkDestroySemaphore DestroySemaphore; PFN_vkCreateEvent CreateEvent; PFN_vkDestroyEvent DestroyEvent; PFN_vkGetEventStatus GetEventStatus; PFN_vkSetEvent SetEvent; PFN_vkResetEvent ResetEvent; PFN_vkCreateQueryPool CreateQueryPool; PFN_vkDestroyQueryPool DestroyQueryPool; PFN_vkGetQueryPoolResults GetQueryPoolResults; PFN_vkCreateBuffer CreateBuffer; PFN_vkDestroyBuffer DestroyBuffer; PFN_vkCreateBufferView CreateBufferView; PFN_vkDestroyBufferView DestroyBufferView; PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkGetImageSubresourceLayout GetImageSubresourceLayout; PFN_vkCreateImageView CreateImageView; PFN_vkDestroyImageView DestroyImageView; PFN_vkCreateShaderModule CreateShaderModule; PFN_vkDestroyShaderModule DestroyShaderModule; PFN_vkCreatePipelineCache CreatePipelineCache; PFN_vkDestroyPipelineCache DestroyPipelineCache; PFN_vkGetPipelineCacheData GetPipelineCacheData; PFN_vkMergePipelineCaches MergePipelineCaches; PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines; PFN_vkCreateComputePipelines CreateComputePipelines; PFN_vkDestroyPipeline DestroyPipeline; PFN_vkCreatePipelineLayout CreatePipelineLayout; PFN_vkDestroyPipelineLayout DestroyPipelineLayout; PFN_vkCreateSampler CreateSampler; PFN_vkDestroySampler DestroySampler; PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout; PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout; PFN_vkCreateDescriptorPool CreateDescriptorPool; PFN_vkDestroyDescriptorPool DestroyDescriptorPool; PFN_vkResetDescriptorPool ResetDescriptorPool; PFN_vkAllocateDescriptorSets AllocateDescriptorSets; PFN_vkFreeDescriptorSets FreeDescriptorSets; PFN_vkUpdateDescriptorSets UpdateDescriptorSets; PFN_vkCreateFramebuffer CreateFramebuffer; PFN_vkDestroyFramebuffer DestroyFramebuffer; PFN_vkCreateRenderPass CreateRenderPass; PFN_vkDestroyRenderPass DestroyRenderPass; PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity; PFN_vkCreateCommandPool CreateCommandPool; PFN_vkDestroyCommandPool DestroyCommandPool; PFN_vkResetCommandPool ResetCommandPool; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; PFN_vkFreeCommandBuffers FreeCommandBuffers; PFN_vkBeginCommandBuffer BeginCommandBuffer; PFN_vkEndCommandBuffer EndCommandBuffer; PFN_vkResetCommandBuffer ResetCommandBuffer; PFN_vkCmdBindPipeline CmdBindPipeline; PFN_vkCmdSetViewport CmdSetViewport; PFN_vkCmdSetScissor CmdSetScissor; PFN_vkCmdSetLineWidth CmdSetLineWidth; PFN_vkCmdSetDepthBias CmdSetDepthBias; PFN_vkCmdSetBlendConstants CmdSetBlendConstants; PFN_vkCmdSetDepthBounds CmdSetDepthBounds; PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; PFN_vkCmdSetStencilReference CmdSetStencilReference; PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; PFN_vkCmdDraw CmdDraw; PFN_vkCmdDrawIndexed CmdDrawIndexed; PFN_vkCmdDrawIndirect CmdDrawIndirect; PFN_vkCmdDrawIndexedIndirect CmdDrawIndexedIndirect; PFN_vkCmdDispatch CmdDispatch; PFN_vkCmdDispatchIndirect CmdDispatchIndirect; PFN_vkCmdCopyBuffer CmdCopyBuffer; PFN_vkCmdCopyImage CmdCopyImage; PFN_vkCmdBlitImage CmdBlitImage; PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage; PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer; PFN_vkCmdUpdateBuffer CmdUpdateBuffer; PFN_vkCmdFillBuffer CmdFillBuffer; PFN_vkCmdClearColorImage CmdClearColorImage; PFN_vkCmdClearDepthStencilImage CmdClearDepthStencilImage; PFN_vkCmdClearAttachments CmdClearAttachments; PFN_vkCmdResolveImage CmdResolveImage; PFN_vkCmdSetEvent CmdSetEvent; PFN_vkCmdResetEvent CmdResetEvent; PFN_vkCmdWaitEvents CmdWaitEvents; PFN_vkCmdPipelineBarrier CmdPipelineBarrier; PFN_vkCmdBeginQuery CmdBeginQuery; PFN_vkCmdEndQuery CmdEndQuery; PFN_vkCmdResetQueryPool CmdResetQueryPool; PFN_vkCmdWriteTimestamp CmdWriteTimestamp; PFN_vkCmdCopyQueryPoolResults CmdCopyQueryPoolResults; PFN_vkCmdPushConstants CmdPushConstants; PFN_vkCmdBeginRenderPass CmdBeginRenderPass; PFN_vkCmdNextSubpass CmdNextSubpass; PFN_vkCmdEndRenderPass CmdEndRenderPass; PFN_vkCmdExecuteCommands CmdExecuteCommands; PFN_vkCreateSwapchainKHR CreateSwapchainKHR; PFN_vkDestroySwapchainKHR DestroySwapchainKHR; PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR; PFN_vkAcquireNextImageKHR AcquireNextImageKHR; PFN_vkQueuePresentKHR QueuePresentKHR; // clang-format on }; bool InitDispatchTable( VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset& extensions); bool InitDispatchTable( VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset& extensions); } // namespace api } // namespace vulkan #endif // LIBVULKAN_API_GEN_H vulkan/libvulkan/code-generator.tmpl0100644 0000000 0000000 00000102764 13077405420 016704 0ustar000000000 0000000 {{define "Copyright"}} /* •* Copyright 2016 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. •*/ ¶{{end}} {{Include "../api/templates/vulkan_common.tmpl"}} {{Global "clang-format" (Strings "clang-format" "-style=file")}} {{Macro "DefineGlobals" $}} {{$ | Macro "api_gen.h" | Format (Global "clang-format") | Write "api_gen.h" }} {{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}} {{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}} {{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}} {{/* ------------------------------------------------------------------------------- api_gen.h ------------------------------------------------------------------------------- */}} {{define "api_gen.h"}} {{Macro "Copyright"}} ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #ifndef LIBVULKAN_API_GEN_H #define LIBVULKAN_API_GEN_H ¶ #include #include #include "driver_gen.h" ¶ namespace vulkan {« namespace api {« ¶ struct InstanceDispatchTable { // clang-format off {{range $f := AllCommands $}} {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}} {{Macro "C++.DeclareTableEntry" $f}}; {{end}} {{end}} // clang-format on }; ¶ struct DeviceDispatchTable { // clang-format off {{range $f := AllCommands $}} {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}} {{Macro "C++.DeclareTableEntry" $f}}; {{end}} {{end}} // clang-format on }; ¶ bool InitDispatchTable( VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset &extensions); bool InitDispatchTable( VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset &extensions); ¶ »} // namespace api »} // namespace vulkan ¶ #endif // LIBVULKAN_API_GEN_H ¶{{end}} {{/* ------------------------------------------------------------------------------- api_gen.cpp ------------------------------------------------------------------------------- */}} {{define "api_gen.cpp"}} {{Macro "Copyright"}} ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #include #include #include ¶ // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" ¶ namespace vulkan {« namespace api {« ¶ {{Macro "C++.DefineInitProcMacro" "dispatch"}} ¶ {{Macro "api.C++.DefineInitProcExtMacro"}} ¶ namespace {« ¶ // clang-format off ¶ {{range $f := AllCommands $}} {{Macro "api.C++.DefineExtensionStub" $f}} {{end}} // clang-format on ¶ »} // anonymous ¶ bool InitDispatchTable( VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset &extensions) { auto& data = GetData(instance); bool success = true; ¶ // clang-format off {{range $f := AllCommands $}} {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}} {{Macro "C++.InitProc" $f}} {{end}} {{end}} // clang-format on ¶ return success; } ¶ bool InitDispatchTable( VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset &extensions) { auto& data = GetData(dev); bool success = true; ¶ // clang-format off {{range $f := AllCommands $}} {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}} {{Macro "C++.InitProc" $f}} {{end}} {{end}} // clang-format on ¶ return success; } ¶ // clang-format off ¶ namespace {« ¶ // forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr {{range $f := AllCommands $}} {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}} VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}); {{end}} {{end}} ¶ {{range $f := AllCommands $}} {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}} VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}) { {{ if eq $f.Name "vkGetInstanceProcAddr"}} {{Macro "api.C++.InterceptInstanceProcAddr" $}} {{else if eq $f.Name "vkGetDeviceProcAddr"}} {{Macro "api.C++.InterceptDeviceProcAddr" $}} {{end}} {{Macro "api.C++.Dispatch" $f}} } ¶ {{end}} {{end}} ¶ »} // anonymous namespace ¶ // clang-format on ¶ »} // namespace api »} // namespace vulkan ¶ // clang-format off ¶ {{range $f := AllCommands $}} {{if (Macro "IsFunctionExported" $f)}} __attribute__((visibility("default"))) VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) { {{if not (IsVoid $f.Return.Type)}}return §{{end}} vulkan::api::{{Macro "BaseName" $f}}({{Macro "Arguments" $f}}); } ¶ {{end}} {{end}} ¶ // clang-format on ¶{{end}} {{/* ------------------------------------------------------------------------------- driver_gen.h ------------------------------------------------------------------------------- */}} {{define "driver_gen.h"}} {{Macro "Copyright"}} ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #ifndef LIBVULKAN_DRIVER_GEN_H #define LIBVULKAN_DRIVER_GEN_H ¶ #include #include #include ¶ namespace vulkan {« namespace driver {« ¶ {{Macro "driver.C++.DefineProcHookType"}} ¶ struct InstanceDriverTable { // clang-format off {{range $f := AllCommands $}} {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}} {{Macro "C++.DeclareTableEntry" $f}}; {{end}} {{end}} // clang-format on }; ¶ struct DeviceDriverTable { // clang-format off {{range $f := AllCommands $}} {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}} {{Macro "C++.DeclareTableEntry" $f}}; {{end}} {{end}} // clang-format on }; ¶ const ProcHook* GetProcHook(const char* name); ProcHook::Extension GetProcHookExtension(const char* name); ¶ bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset &extensions); bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset &extensions); ¶ »} // namespace driver »} // namespace vulkan ¶ #endif // LIBVULKAN_DRIVER_TABLE_H ¶{{end}} {{/* ------------------------------------------------------------------------------- driver_gen.cpp ------------------------------------------------------------------------------- */}} {{define "driver_gen.cpp"}} {{Macro "Copyright"}} ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #include #include #include ¶ #include "driver.h" ¶ namespace vulkan {« namespace driver {« ¶ namespace {« ¶ // clang-format off ¶ {{range $f := AllCommands $}} {{Macro "driver.C++.DefineProcHookStub" $f}} {{end}} // clang-format on ¶ const ProcHook g_proc_hooks[] = { // clang-format off {{range $f := SortBy (AllCommands $) "FunctionName"}} {{if (Macro "driver.IsIntercepted" $f)}} {{ if (Macro "IsGloballyDispatched" $f)}} {{Macro "driver.C++.DefineGlobalProcHook" $f}} {{else if (Macro "IsInstanceDispatched" $f)}} {{Macro "driver.C++.DefineInstanceProcHook" $f}} {{else if (Macro "IsDeviceDispatched" $f)}} {{Macro "driver.C++.DefineDeviceProcHook" $f}} {{end}} {{end}} {{end}} // clang-format on }; ¶ »} // anonymous ¶ const ProcHook* GetProcHook(const char* name) { const auto& begin = g_proc_hooks; const auto& end = g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); const auto hook = std::lower_bound(begin, end, name, [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; } ¶ ProcHook::Extension GetProcHookExtension(const char* name) { {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}} // clang-format off {{range $e := $exts}} if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}}; {{end}} // clang-format on return ProcHook::EXTENSION_UNKNOWN; } ¶ {{Macro "C++.DefineInitProcMacro" "driver"}} ¶ {{Macro "driver.C++.DefineInitProcExtMacro"}} ¶ bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset &extensions) { auto& data = GetData(instance); bool success = true; ¶ // clang-format off {{range $f := AllCommands $}} {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}} {{Macro "C++.InitProc" $f}} {{end}} {{end}} // clang-format on ¶ return success; } ¶ bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset &extensions) { auto& data = GetData(dev); bool success = true; ¶ // clang-format off {{range $f := AllCommands $}} {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}} {{Macro "C++.InitProc" $f}} {{end}} {{end}} // clang-format on ¶ return success; } ¶ »} // namespace driver »} // namespace vulkan ¶ // clang-format on ¶{{end}} {{/* ------------------------------------------------------------------------------ Emits a declaration of a dispatch/driver table entry. ------------------------------------------------------------------------------ */}} {{define "C++.DeclareTableEntry"}} {{AssertType $ "Function"}} {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}} {{end}} {{/* ------------------------------------------------------------------------------- Emits INIT_PROC macro. ------------------------------------------------------------------------------- */}} {{define "C++.DefineInitProcMacro"}} #define UNLIKELY(expr) __builtin_expect((expr), 0) ¶ #define INIT_PROC(obj, proc) do { \ data.{{$}}.proc = reinterpret_cast( \ get_proc(obj, "vk" # proc)); \ if (UNLIKELY(!data.{{$}}.proc)) { \ ALOGE("missing " # obj " proc: vk" # proc); \ success = false; \ } \ } while(0) {{end}} {{/* ------------------------------------------------------------------------------- Emits code to invoke INIT_PROC or INIT_PROC_EXT. ------------------------------------------------------------------------------- */}} {{define "C++.InitProc"}} {{AssertType $ "Function"}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} INIT_PROC_EXT({{Macro "BaseName" $ext}}, § {{else}} INIT_PROC(§ {{end}} {{if (Macro "IsInstanceDispatched" $)}} instance, § {{else}} dev, § {{end}} {{Macro "BaseName" $}}); {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a function is exported and instance-dispatched. ------------------------------------------------------------------------------ */}} {{define "api.IsInstanceDispatchTableEntry"}} {{AssertType $ "Function"}} {{if and (Macro "IsFunctionExported" $) (Macro "IsInstanceDispatched" $)}} {{/* deprecated and unused internally */}} {{if not (eq $.Name "vkEnumerateDeviceLayerProperties")}} true {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a function is exported and device-dispatched. ------------------------------------------------------------------------------ */}} {{define "api.IsDeviceDispatchTableEntry"}} {{AssertType $ "Function"}} {{if and (Macro "IsFunctionExported" $) (Macro "IsDeviceDispatched" $)}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a function is intercepted by vulkan::api. ------------------------------------------------------------------------------ */}} {{define "api.IsIntercepted"}} {{AssertType $ "Function"}} {{if (Macro "IsFunctionSupported" $)}} {{/* Global functions cannot be dispatched at all */}} {{ if (Macro "IsGloballyDispatched" $)}}true {{/* VkPhysicalDevice functions that manage device layers */}} {{else if eq $.Name "vkCreateDevice"}}true {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true {{/* Destroy functions of dispatchable objects */}} {{else if eq $.Name "vkDestroyInstance"}}true {{else if eq $.Name "vkDestroyDevice"}}true {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits INIT_PROC_EXT macro for vulkan::api. ------------------------------------------------------------------------------- */}} {{define "api.C++.DefineInitProcExtMacro"}} // Exported extension functions may be invoked even when their extensions // are disabled. Dispatch to stubs when that happens. #define INIT_PROC_EXT(ext, obj, proc) do { \ if (extensions[driver::ProcHook::ext]) \ INIT_PROC(obj, proc); \ else \ data.dispatch.proc = disabled ## proc; \ } while(0) {{end}} {{/* ------------------------------------------------------------------------------- Emits a stub for an exported extension function. ------------------------------------------------------------------------------- */}} {{define "api.C++.DefineExtensionStub"}} {{AssertType $ "Function"}} {{$ext := GetAnnotation $ "extension"}} {{if and $ext (Macro "IsFunctionExported" $)}} {{$ext_name := index $ext.Arguments 0}} {{$base := (Macro "BaseName" $)}} {{$p0 := (index $.CallParameters 0)}} {{$ptail := (Tail 1 $.CallParameters)}} {{$first_type := (Macro "Parameter" $p0)}} {{$tail_types := (ForEach $ptail "ParameterType" | JoinWith ", ")}} VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$first_type}}, {{$tail_types}}) { driver::Logger({{$p0.Name}}).Err({{$p0.Name}}, § "{{$ext_name}} not enabled. Exported {{$.Name}} not executed."); {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}} } ¶ {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits code for vkGetInstanceProcAddr for function interception. ------------------------------------------------------------------------------ */}} {{define "api.C++.InterceptInstanceProcAddr"}} {{AssertType $ "API"}} // global functions if (instance == VK_NULL_HANDLE) { {{range $f := AllCommands $}} {{if (Macro "IsGloballyDispatched" $f)}} if (strcmp(pName, "{{$f.Name}}") == 0) return § reinterpret_cast({{Macro "BaseName" $f}}); {{end}} {{end}} ¶ ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName); return nullptr; } ¶ static const struct Hook { const char* name; PFN_vkVoidFunction proc; } hooks[] = { {{range $f := SortBy (AllCommands $) "FunctionName"}} {{if (Macro "IsFunctionExported" $f)}} {{/* hide global functions */}} {{if (Macro "IsGloballyDispatched" $f)}} { "{{$f.Name}}", nullptr }, {{/* redirect intercepted functions */}} {{else if (Macro "api.IsIntercepted" $f)}} { "{{$f.Name}}", reinterpret_cast(§ {{Macro "BaseName" $f}}) }, {{/* redirect vkGetInstanceProcAddr to itself */}} {{else if eq $f.Name "vkGetInstanceProcAddr"}} { "{{$f.Name}}", reinterpret_cast({{Macro "BaseName" $f}}) }, {{/* redirect device functions to themselves as a workaround for layers that do not intercept in their vkGetInstanceProcAddr */}} {{else if (Macro "IsDeviceDispatched" $f)}} { "{{$f.Name}}", reinterpret_cast({{Macro "BaseName" $f}}) }, {{end}} {{end}} {{end}} }; // clang-format on constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]); auto hook = std::lower_bound( hooks, hooks + count, pName, [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; }); if (hook < hooks + count && strcmp(hook->name, pName) == 0) { if (!hook->proc) { vulkan::driver::Logger(instance).Err( instance, "invalid vkGetInstanceProcAddr(%p, \"%s\") call", instance, pName); } return hook->proc; } // clang-format off ¶ {{end}} {{/* ------------------------------------------------------------------------------ Emits code for vkGetDeviceProcAddr for function interception. ------------------------------------------------------------------------------ */}} {{define "api.C++.InterceptDeviceProcAddr"}} {{AssertType $ "API"}} if (device == VK_NULL_HANDLE) { ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call"); return nullptr; } ¶ static const char* const known_non_device_names[] = { {{range $f := SortBy (AllCommands $) "FunctionName"}} {{if (Macro "IsFunctionSupported" $f)}} {{if not (Macro "IsDeviceDispatched" $f)}} "{{$f.Name}}", {{end}} {{end}} {{end}} }; // clang-format on constexpr size_t count = sizeof(known_non_device_names) / sizeof(known_non_device_names[0]); if (!pName || std::binary_search( known_non_device_names, known_non_device_names + count, pName, [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) { vulkan::driver::Logger(device).Err(§ device, "invalid vkGetDeviceProcAddr(%p, \"%s\") call", device,§ (pName) ? pName : "(null)"); return nullptr; } // clang-format off ¶ {{range $f := AllCommands $}} {{if (Macro "IsDeviceDispatched" $f)}} {{ if (Macro "api.IsIntercepted" $f)}} if (strcmp(pName, "{{$f.Name}}") == 0) return § reinterpret_cast(§ {{Macro "BaseName" $f}}); {{else if eq $f.Name "vkGetDeviceProcAddr"}} if (strcmp(pName, "{{$f.Name}}") == 0) return § reinterpret_cast(§ {{Macro "BaseName" $f}}); {{end}} {{end}} {{end}} ¶ {{end}} {{/* ------------------------------------------------------------------------------ Emits code to dispatch a function. ------------------------------------------------------------------------------ */}} {{define "api.C++.Dispatch"}} {{AssertType $ "Function"}} {{if (Macro "api.IsIntercepted" $)}} {{Error "$.Name should not be generated"}} {{end}} {{if not (IsVoid $.Return.Type)}}return §{{end}} {{$p0 := index $.CallParameters 0}} GetData({{$p0.Name}}).dispatch.§ {{Macro "BaseName" $}}({{Macro "Arguments" $}}); {{end}} {{/* ------------------------------------------------------------------------------ Emits a list of extensions intercepted by vulkan::driver. ------------------------------------------------------------------------------ */}} {{define "driver.InterceptedExtensions"}} VK_ANDROID_native_buffer VK_EXT_debug_report VK_KHR_android_surface VK_KHR_surface VK_KHR_swapchain {{end}} {{/* ------------------------------------------------------------------------------ Emits true if an extension is intercepted by vulkan::driver. ------------------------------------------------------------------------------ */}} {{define "driver.IsExtensionIntercepted"}} {{$ext_name := index $.Arguments 0}} {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}} {{range $f := $filters}} {{if eq $ext_name $f}}true{{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a function is intercepted by vulkan::driver. ------------------------------------------------------------------------------ */}} {{define "driver.IsIntercepted"}} {{AssertType $ "Function"}} {{if (Macro "IsFunctionSupported" $)}} {{/* Create functions of dispatchable objects */}} {{ if eq $.Name "vkCreateInstance"}}true {{else if eq $.Name "vkCreateDevice"}}true {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true {{else if eq $.Name "vkGetDeviceQueue"}}true {{else if eq $.Name "vkAllocateCommandBuffers"}}true {{/* Destroy functions of dispatchable objects */}} {{else if eq $.Name "vkDestroyInstance"}}true {{else if eq $.Name "vkDestroyDevice"}}true {{/* Enumeration of extensions */}} {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true {{else if eq $.Name "vkGetInstanceProcAddr"}}true {{else if eq $.Name "vkGetDeviceProcAddr"}}true {{end}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{Macro "driver.IsExtensionIntercepted" $ext}} {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a function needs a ProcHook stub. ------------------------------------------------------------------------------ */}} {{define "driver.NeedProcHookStub"}} {{AssertType $ "Function"}} {{if and (Macro "driver.IsIntercepted" $) (Macro "IsDeviceDispatched" $)}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}} {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits definition of struct ProcHook. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineProcHookType"}} struct ProcHook { enum Type { GLOBAL, INSTANCE, DEVICE, }; enum Extension { {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}} {{range $e := $exts}} {{TrimPrefix "VK_" $e}}, {{end}} ¶ EXTENSION_CORE, // valid bit EXTENSION_COUNT, EXTENSION_UNKNOWN, }; ¶ const char* name; Type type; Extension extension; ¶ PFN_vkVoidFunction proc; PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks }; {{end}} {{/* ------------------------------------------------------------------------------- Emits INIT_PROC_EXT macro for vulkan::driver. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineInitProcExtMacro"}} #define INIT_PROC_EXT(ext, obj, proc) do { \ if (extensions[ProcHook::ext]) \ INIT_PROC(obj, proc); \ } while(0) {{end}} {{/* ------------------------------------------------------------------------------- Emits a stub for ProcHook::checked_proc. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineProcHookStub"}} {{AssertType $ "Function"}} {{if (Macro "driver.NeedProcHookStub" $)}} {{$ext := GetAnnotation $ "extension"}} {{$ext_name := index $ext.Arguments 0}} {{$base := (Macro "BaseName" $)}} VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) { {{$p0 := index $.CallParameters 0}} {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}} if (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) { {{if not (IsVoid $.Return.Type)}}return §{{end}} {{$base}}({{Macro "Arguments" $}}); } else { Logger({{$p0.Name}}).Err({{$p0.Name}}, "{{$ext_name}} not enabled. {{$.Name}} not executed."); {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}} } } ¶ {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits definition of a global ProcHook. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineGlobalProcHook"}} {{AssertType $ "Function"}} {{$base := (Macro "BaseName" $)}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{Error "invalid global extension"}} {{end}} { "{{$.Name}}", ProcHook::GLOBAL, ProcHook::EXTENSION_CORE, reinterpret_cast({{$base}}), nullptr, }, {{end}} {{/* ------------------------------------------------------------------------------- Emits definition of an instance ProcHook. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineInstanceProcHook"}} {{AssertType $ "Function"}} {{$base := (Macro "BaseName" $)}} { "{{$.Name}}", ProcHook::INSTANCE, {{$ext := GetAnnotation $ "extension"}} {{if $ext}} ProcHook::{{Macro "BaseName" $ext}}, {{if (Macro "IsExtensionInternal" $ext)}} nullptr, nullptr, {{else}} reinterpret_cast({{$base}}), nullptr, {{end}} {{else}} ProcHook::EXTENSION_CORE, reinterpret_cast({{$base}}), nullptr, {{end}} }, {{end}} {{/* ------------------------------------------------------------------------------- Emits definition of a device ProcHook. ------------------------------------------------------------------------------- */}} {{define "driver.C++.DefineDeviceProcHook"}} {{AssertType $ "Function"}} {{$base := (Macro "BaseName" $)}} { "{{$.Name}}", ProcHook::DEVICE, {{$ext := GetAnnotation $ "extension"}} {{if $ext}} ProcHook::{{Macro "BaseName" $ext}}, {{if (Macro "IsExtensionInternal" $ext)}} nullptr, nullptr, {{else}} reinterpret_cast({{$base}}), reinterpret_cast(checked{{$base}}), {{end}} {{else}} ProcHook::EXTENSION_CORE, reinterpret_cast({{$base}}), nullptr, {{end}} }, {{end}} {{/* ------------------------------------------------------------------------------- Emits true if a function is needed by vulkan::driver. ------------------------------------------------------------------------------- */}} {{define "driver.IsDriverTableEntry"}} {{AssertType $ "Function"}} {{if (Macro "IsFunctionSupported" $)}} {{/* Create functions of dispatchable objects */}} {{ if eq $.Name "vkCreateDevice"}}true {{else if eq $.Name "vkGetDeviceQueue"}}true {{else if eq $.Name "vkAllocateCommandBuffers"}}true {{/* Destroy functions of dispatchable objects */}} {{else if eq $.Name "vkDestroyInstance"}}true {{else if eq $.Name "vkDestroyDevice"}}true {{/* Enumeration of extensions */}} {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true {{/* We cache physical devices in loader.cpp */}} {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true {{else if eq $.Name "vkGetInstanceProcAddr"}}true {{else if eq $.Name "vkGetDeviceProcAddr"}}true {{/* VK_KHR_swapchain->VK_ANDROID_native_buffer translation */}} {{else if eq $.Name "vkCreateImage"}}true {{else if eq $.Name "vkDestroyImage"}}true {{end}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{$ext_name := index $ext.Arguments 0}} {{ if eq $ext_name "VK_ANDROID_native_buffer"}}true {{else if eq $ext_name "VK_EXT_debug_report"}}true {{end}} {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if an instance-dispatched function is needed by vulkan::driver. ------------------------------------------------------------------------------ */}} {{define "driver.IsInstanceDriverTableEntry"}} {{AssertType $ "Function"}} {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsInstanceDispatched" $)}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emits true if a device-dispatched function is needed by vulkan::driver. ------------------------------------------------------------------------------ */}} {{define "driver.IsDeviceDriverTableEntry"}} {{AssertType $ "Function"}} {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsDeviceDispatched" $)}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits a function/extension name without the "vk"/"VK_" prefix. ------------------------------------------------------------------------------- */}} {{define "BaseName"}} {{ if IsFunction $}}{{TrimPrefix "vk" $.Name}} {{else if eq $.Name "extension"}}{{TrimPrefix "VK_" (index $.Arguments 0)}} {{else}}{{Error "invalid use of BaseName"}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------- Emits a comma-separated list of C parameter names for the given command. ------------------------------------------------------------------------------- */}} {{define "Arguments"}} {{AssertType $ "Function"}} {{ForEach $.CallParameters "ParameterName" | JoinWith ", "}} {{end}} {{/* ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ */}} {{define "IsGloballyDispatched"}} {{AssertType $ "Function"}} {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Global")}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emit "true" for supported functions that undergo table dispatch. Only global functions and functions handled in the loader top without calling into lower layers are not dispatched. ------------------------------------------------------------------------------ */}} {{define "IsInstanceDispatched"}} {{AssertType $ "Function"}} {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emit "true" for supported functions that can have device-specific dispatch. ------------------------------------------------------------------------------ */}} {{define "IsDeviceDispatched"}} {{AssertType $ "Function"}} {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Device")}} true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emit "true" if a function is core or from a supportable extension. ------------------------------------------------------------------------------ */}} {{define "IsFunctionSupported"}} {{AssertType $ "Function"}} {{if not (GetAnnotation $ "pfn")}} {{$ext := GetAnnotation $ "extension"}} {{if not $ext}}true {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Decides whether a function should be exported from the Android Vulkan library. Functions in the core API and in loader extensions are exported. ------------------------------------------------------------------------------ */}} {{define "IsFunctionExported"}} {{AssertType $ "Function"}} {{if (Macro "IsFunctionSupported" $)}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{Macro "IsExtensionExported" $ext}} {{else}} true {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Emit "true" if an extension is unsupportable on Android. ------------------------------------------------------------------------------ */}} {{define "IsExtensionBlacklisted"}} {{$ext := index $.Arguments 0}} {{ if eq $ext "VK_KHR_display"}}true {{else if eq $ext "VK_KHR_display_swapchain"}}true {{else if eq $ext "VK_KHR_xlib_surface"}}true {{else if eq $ext "VK_KHR_xcb_surface"}}true {{else if eq $ext "VK_KHR_wayland_surface"}}true {{else if eq $ext "VK_KHR_mir_surface"}}true {{else if eq $ext "VK_KHR_win32_surface"}}true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Reports whether an extension is implemented entirely by the loader, so drivers should not enumerate it. ------------------------------------------------------------------------------ */}} {{define "IsExtensionExported"}} {{$ext := index $.Arguments 0}} {{ if eq $ext "VK_KHR_surface"}}true {{else if eq $ext "VK_KHR_swapchain"}}true {{else if eq $ext "VK_KHR_android_surface"}}true {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Reports whether an extension is internal to the loader and drivers, so the loader should not enumerate it. ------------------------------------------------------------------------------ */}} {{define "IsExtensionInternal"}} {{$ext := index $.Arguments 0}} {{ if eq $ext "VK_ANDROID_native_buffer"}}true {{end}} {{end}} vulkan/libvulkan/debug_report.cpp0100644 0000000 0000000 00000015460 13077405420 016271 0ustar000000000 0000000 /* * Copyright 2016 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 "driver.h" namespace vulkan { namespace driver { DebugReportCallbackList::Node* DebugReportCallbackList::AddCallback( const VkDebugReportCallbackCreateInfoEXT& info, VkDebugReportCallbackEXT driver_handle, const VkAllocationCallbacks& allocator) { void* mem = allocator.pfnAllocation(allocator.pUserData, sizeof(Node), alignof(Node), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!mem) return nullptr; // initialize and prepend node to the list std::lock_guard lock(rwmutex_); head_.next = new (mem) Node{head_.next, info.flags, info.pfnCallback, info.pUserData, driver_handle}; return head_.next; } void DebugReportCallbackList::RemoveCallback( Node* node, const VkAllocationCallbacks& allocator) { // remove node from the list { std::lock_guard lock(rwmutex_); Node* prev = &head_; while (prev && prev->next != node) prev = prev->next; prev->next = node->next; } allocator.pfnFree(allocator.pUserData, node); } void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location, int32_t message_code, const char* layer_prefix, const char* message) const { std::shared_lock lock(rwmutex_); const Node* node = &head_; while ((node = node->next)) { if ((node->flags & flags) != 0) { node->callback(flags, object_type, object, location, message_code, layer_prefix, message, node->user_data); } } } void DebugReportLogger::Message(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location, int32_t message_code, const char* layer_prefix, const char* message) const { const VkDebugReportCallbackCreateInfoEXT* info = reinterpret_cast( instance_pnext_); while (info) { if (info->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT && (info->flags & flags) != 0) { info->pfnCallback(flags, object_type, object, location, message_code, layer_prefix, message, info->pUserData); } info = reinterpret_cast( info->pNext); } if (callbacks_) { callbacks_->Message(flags, object_type, object, location, message_code, layer_prefix, message); } } void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, const char* format, va_list ap) const { char buf[1024]; int len = vsnprintf(buf, sizeof(buf), format, ap); // message truncated if (len >= static_cast(sizeof(buf))) memcpy(buf + sizeof(buf) - 4, "...", 4); Message(flags, object_type, object, 0, 0, LOG_TAG, buf); } VkResult CreateDebugReportCallbackEXT( VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* create_info, const VkAllocationCallbacks* allocator, VkDebugReportCallbackEXT* callback) { const auto& driver = GetData(instance).driver; VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE; if (driver.CreateDebugReportCallbackEXT) { VkResult result = driver.CreateDebugReportCallbackEXT( instance, create_info, allocator, &driver_handle); if (result != VK_SUCCESS) return result; } auto& callbacks = GetData(instance).debug_report_callbacks; auto node = callbacks.AddCallback( *create_info, driver_handle, (allocator) ? *allocator : GetData(instance).allocator); if (!node) { if (driver_handle != VK_NULL_HANDLE) { driver.DestroyDebugReportCallbackEXT(instance, driver_handle, allocator); } return VK_ERROR_OUT_OF_HOST_MEMORY; } *callback = callbacks.GetHandle(node); return VK_SUCCESS; } void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* allocator) { if (callback == VK_NULL_HANDLE) return; auto& callbacks = GetData(instance).debug_report_callbacks; auto node = callbacks.FromHandle(callback); auto driver_handle = callbacks.GetDriverHandle(node); callbacks.RemoveCallback( node, (allocator) ? *allocator : GetData(instance).allocator); if (driver_handle != VK_NULL_HANDLE) { GetData(instance).driver.DestroyDebugReportCallbackEXT( instance, driver_handle, allocator); } } void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location, int32_t message_code, const char* layer_prefix, const char* message) { if (GetData(instance).driver.DebugReportMessageEXT) { GetData(instance).driver.DebugReportMessageEXT( instance, flags, object_type, object, location, message_code, layer_prefix, message); } else { GetData(instance).debug_report_callbacks.Message( flags, object_type, object, location, message_code, layer_prefix, message); } } } // namespace driver } // namespace vulkan vulkan/libvulkan/debug_report.h0100644 0000000 0000000 00000013652 13077405420 015737 0ustar000000000 0000000 /* * Copyright 2016 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 LIBVULKAN_DEBUG_REPORT_H #define LIBVULKAN_DEBUG_REPORT_H 1 #include #include #include namespace vulkan { namespace driver { // clang-format off VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); // clang-format on class DebugReportCallbackList { private: // forward declaration struct Node; public: DebugReportCallbackList() : head_{nullptr, 0, nullptr, nullptr, VK_NULL_HANDLE} {} DebugReportCallbackList(const DebugReportCallbackList&) = delete; DebugReportCallbackList& operator=(const DebugReportCallbackList&) = delete; ~DebugReportCallbackList() = default; Node* AddCallback(const VkDebugReportCallbackCreateInfoEXT& info, VkDebugReportCallbackEXT driver_handle, const VkAllocationCallbacks& allocator); void RemoveCallback(Node* node, const VkAllocationCallbacks& allocator); void Message(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location, int32_t message_code, const char* layer_prefix, const char* message) const; static Node* FromHandle(VkDebugReportCallbackEXT handle) { return reinterpret_cast(uintptr_t(handle)); } static VkDebugReportCallbackEXT GetHandle(const Node* node) { return VkDebugReportCallbackEXT(reinterpret_cast(node)); } static VkDebugReportCallbackEXT GetDriverHandle(const Node* node) { return node->driver_handle; } private: struct Node { Node* next; VkDebugReportFlagsEXT flags; PFN_vkDebugReportCallbackEXT callback; void* user_data; VkDebugReportCallbackEXT driver_handle; }; // TODO(jessehall): replace with std::shared_mutex when available in libc++ mutable std::shared_timed_mutex rwmutex_; Node head_; }; class DebugReportLogger { public: DebugReportLogger(const VkInstanceCreateInfo& info) : instance_pnext_(info.pNext), callbacks_(nullptr) {} DebugReportLogger(const DebugReportCallbackList& callbacks) : instance_pnext_(nullptr), callbacks_(&callbacks) {} void Message(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, size_t location, int32_t message_code, const char* layer_prefix, const char* message) const; #define DEBUG_REPORT_LOGGER_PRINTF(fmt, args) \ __attribute__((format(printf, (fmt) + 1, (args) + 1))) template void Info(ObjectType object, const char* format, ...) const DEBUG_REPORT_LOGGER_PRINTF(2, 3) { va_list ap; va_start(ap, format); PrintV(VK_DEBUG_REPORT_INFORMATION_BIT_EXT, GetObjectType(object), GetObjectUInt64(object), format, ap); va_end(ap); } template void Warn(ObjectType object, const char* format, ...) const DEBUG_REPORT_LOGGER_PRINTF(2, 3) { va_list ap; va_start(ap, format); PrintV(VK_DEBUG_REPORT_WARNING_BIT_EXT, GetObjectType(object), GetObjectUInt64(object), format, ap); va_end(ap); } template void Err(ObjectType object, const char* format, ...) const DEBUG_REPORT_LOGGER_PRINTF(2, 3) { va_list ap; va_start(ap, format); PrintV(VK_DEBUG_REPORT_ERROR_BIT_EXT, GetObjectType(object), GetObjectUInt64(object), format, ap); va_end(ap); } private: template static VkDebugReportObjectTypeEXT GetObjectType(ObjectType) { if (std::is_same::value) return VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT; else if (std::is_same::value) return VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT; else if (std::is_same::value) return VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT; else return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; } template static uint64_t GetObjectUInt64(ObjectType object) { return uint64_t(object); } #define DEBUG_REPORT_LOGGER_VPRINTF(fmt) \ __attribute__((format(printf, (fmt) + 1, 0))) void PrintV(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type, uint64_t object, const char* format, va_list ap) const DEBUG_REPORT_LOGGER_VPRINTF(4); const void* const instance_pnext_; const DebugReportCallbackList* const callbacks_; }; } // namespace driver } // namespace vulkan #endif // LIBVULKAN_DEBUG_REPORT_H vulkan/libvulkan/driver.cpp0100644 0000000 0000000 00000065702 13077405420 015107 0ustar000000000 0000000 /* * Copyright 2016 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 #include #include #include #include #include #include #include "driver.h" #include "stubhal.h" // #define ENABLE_ALLOC_CALLSTACKS 1 #if ENABLE_ALLOC_CALLSTACKS #include #define ALOGD_CALLSTACK(...) \ do { \ ALOGD(__VA_ARGS__); \ android::CallStack callstack; \ callstack.update(); \ callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \ } while (false) #else #define ALOGD_CALLSTACK(...) \ do { \ } while (false) #endif namespace vulkan { namespace driver { namespace { class Hal { public: static bool Open(); static const Hal& Get() { return hal_; } static const hwvulkan_device_t& Device() { return *Get().dev_; } int GetDebugReportIndex() const { return debug_report_index_; } private: Hal() : dev_(nullptr), debug_report_index_(-1) {} Hal(const Hal&) = delete; Hal& operator=(const Hal&) = delete; bool InitDebugReportIndex(); static Hal hal_; const hwvulkan_device_t* dev_; int debug_report_index_; }; class CreateInfoWrapper { public: CreateInfoWrapper(const VkInstanceCreateInfo& create_info, const VkAllocationCallbacks& allocator); CreateInfoWrapper(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo& create_info, const VkAllocationCallbacks& allocator); ~CreateInfoWrapper(); VkResult Validate(); const std::bitset& GetHookExtensions() const; const std::bitset& GetHalExtensions() const; explicit operator const VkInstanceCreateInfo*() const; explicit operator const VkDeviceCreateInfo*() const; private: struct ExtensionFilter { VkExtensionProperties* exts; uint32_t ext_count; const char** names; uint32_t name_count; }; VkResult SanitizePNext(); VkResult SanitizeLayers(); VkResult SanitizeExtensions(); VkResult QueryExtensionCount(uint32_t& count) const; VkResult EnumerateExtensions(uint32_t& count, VkExtensionProperties* props) const; VkResult InitExtensionFilter(); void FilterExtension(const char* name); const bool is_instance_; const VkAllocationCallbacks& allocator_; VkPhysicalDevice physical_dev_; union { VkInstanceCreateInfo instance_info_; VkDeviceCreateInfo dev_info_; }; ExtensionFilter extension_filter_; std::bitset hook_extensions_; std::bitset hal_extensions_; }; Hal Hal::hal_; bool Hal::Open() { ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once"); // Use a stub device unless we successfully open a real HAL device. hal_.dev_ = &stubhal::kDevice; const hwvulkan_module_t* module; int result = hw_get_module("vulkan", reinterpret_cast(&module)); if (result != 0) { ALOGI("no Vulkan HAL present, using stub HAL"); return true; } hwvulkan_device_t* device; result = module->common.methods->open(&module->common, HWVULKAN_DEVICE_0, reinterpret_cast(&device)); if (result != 0) { // Any device with a Vulkan HAL should be able to open the device. ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result), result); return false; } hal_.dev_ = device; hal_.InitDebugReportIndex(); return true; } bool Hal::InitDebugReportIndex() { uint32_t count; if (dev_->EnumerateInstanceExtensionProperties(nullptr, &count, nullptr) != VK_SUCCESS) { ALOGE("failed to get HAL instance extension count"); return false; } VkExtensionProperties* exts = reinterpret_cast( malloc(sizeof(VkExtensionProperties) * count)); if (!exts) { ALOGE("failed to allocate HAL instance extension array"); return false; } if (dev_->EnumerateInstanceExtensionProperties(nullptr, &count, exts) != VK_SUCCESS) { ALOGE("failed to enumerate HAL instance extensions"); free(exts); return false; } for (uint32_t i = 0; i < count; i++) { if (strcmp(exts[i].extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { debug_report_index_ = static_cast(i); break; } } free(exts); return true; } CreateInfoWrapper::CreateInfoWrapper(const VkInstanceCreateInfo& create_info, const VkAllocationCallbacks& allocator) : is_instance_(true), allocator_(allocator), physical_dev_(VK_NULL_HANDLE), instance_info_(create_info), extension_filter_() { hook_extensions_.set(ProcHook::EXTENSION_CORE); hal_extensions_.set(ProcHook::EXTENSION_CORE); } CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev, const VkDeviceCreateInfo& create_info, const VkAllocationCallbacks& allocator) : is_instance_(false), allocator_(allocator), physical_dev_(physical_dev), dev_info_(create_info), extension_filter_() { hook_extensions_.set(ProcHook::EXTENSION_CORE); hal_extensions_.set(ProcHook::EXTENSION_CORE); } CreateInfoWrapper::~CreateInfoWrapper() { allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts); allocator_.pfnFree(allocator_.pUserData, extension_filter_.names); } VkResult CreateInfoWrapper::Validate() { VkResult result = SanitizePNext(); if (result == VK_SUCCESS) result = SanitizeLayers(); if (result == VK_SUCCESS) result = SanitizeExtensions(); return result; } const std::bitset& CreateInfoWrapper::GetHookExtensions() const { return hook_extensions_; } const std::bitset& CreateInfoWrapper::GetHalExtensions() const { return hal_extensions_; } CreateInfoWrapper::operator const VkInstanceCreateInfo*() const { return &instance_info_; } CreateInfoWrapper::operator const VkDeviceCreateInfo*() const { return &dev_info_; } VkResult CreateInfoWrapper::SanitizePNext() { const struct StructHeader { VkStructureType type; const void* next; } * header; if (is_instance_) { header = reinterpret_cast(instance_info_.pNext); // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs while (header && header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO) header = reinterpret_cast(header->next); instance_info_.pNext = header; } else { header = reinterpret_cast(dev_info_.pNext); // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs while (header && header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO) header = reinterpret_cast(header->next); dev_info_.pNext = header; } return VK_SUCCESS; } VkResult CreateInfoWrapper::SanitizeLayers() { auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames : dev_info_.ppEnabledLayerNames; auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount : dev_info_.enabledLayerCount; // remove all layers layer_names = nullptr; layer_count = 0; return VK_SUCCESS; } VkResult CreateInfoWrapper::SanitizeExtensions() { auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames : dev_info_.ppEnabledExtensionNames; auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount : dev_info_.enabledExtensionCount; if (!ext_count) return VK_SUCCESS; VkResult result = InitExtensionFilter(); if (result != VK_SUCCESS) return result; for (uint32_t i = 0; i < ext_count; i++) FilterExtension(ext_names[i]); ext_names = extension_filter_.names; ext_count = extension_filter_.name_count; return VK_SUCCESS; } VkResult CreateInfoWrapper::QueryExtensionCount(uint32_t& count) const { if (is_instance_) { return Hal::Device().EnumerateInstanceExtensionProperties( nullptr, &count, nullptr); } else { const auto& driver = GetData(physical_dev_).driver; return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr, &count, nullptr); } } VkResult CreateInfoWrapper::EnumerateExtensions( uint32_t& count, VkExtensionProperties* props) const { if (is_instance_) { return Hal::Device().EnumerateInstanceExtensionProperties( nullptr, &count, props); } else { const auto& driver = GetData(physical_dev_).driver; return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr, &count, props); } } VkResult CreateInfoWrapper::InitExtensionFilter() { // query extension count uint32_t count; VkResult result = QueryExtensionCount(count); if (result != VK_SUCCESS || count == 0) return result; auto& filter = extension_filter_; filter.exts = reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(VkExtensionProperties) * count, alignof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); if (!filter.exts) return VK_ERROR_OUT_OF_HOST_MEMORY; // enumerate extensions result = EnumerateExtensions(count, filter.exts); if (result != VK_SUCCESS && result != VK_INCOMPLETE) return result; if (!count) return VK_SUCCESS; filter.ext_count = count; // allocate name array uint32_t enabled_ext_count = (is_instance_) ? instance_info_.enabledExtensionCount : dev_info_.enabledExtensionCount; count = std::min(filter.ext_count, enabled_ext_count); filter.names = reinterpret_cast(allocator_.pfnAllocation( allocator_.pUserData, sizeof(const char*) * count, alignof(const char*), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)); if (!filter.names) return VK_ERROR_OUT_OF_HOST_MEMORY; return VK_SUCCESS; } void CreateInfoWrapper::FilterExtension(const char* name) { auto& filter = extension_filter_; ProcHook::Extension ext_bit = GetProcHookExtension(name); if (is_instance_) { switch (ext_bit) { case ProcHook::KHR_android_surface: case ProcHook::KHR_surface: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; case ProcHook::EXT_debug_report: // both we and HAL can take part in hook_extensions_.set(ext_bit); break; case ProcHook::EXTENSION_UNKNOWN: // HAL's extensions break; default: ALOGW("Ignored invalid instance extension %s", name); return; } } else { switch (ext_bit) { case ProcHook::KHR_swapchain: // map VK_KHR_swapchain to VK_ANDROID_native_buffer name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME; ext_bit = ProcHook::ANDROID_native_buffer; break; case ProcHook::EXTENSION_UNKNOWN: // HAL's extensions break; default: ALOGW("Ignored invalid device extension %s", name); return; } } for (uint32_t i = 0; i < filter.ext_count; i++) { const VkExtensionProperties& props = filter.exts[i]; // ignore unknown extensions if (strcmp(name, props.extensionName) != 0) continue; filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) hook_extensions_.set(ProcHook::KHR_swapchain); hal_extensions_.set(ext_bit); } break; } } VKAPI_ATTR void* DefaultAllocate(void*, size_t size, size_t alignment, VkSystemAllocationScope) { void* ptr = nullptr; // Vulkan requires 'alignment' to be a power of two, but posix_memalign // additionally requires that it be at least sizeof(void*). int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment, ret, ptr); return ret == 0 ? ptr : nullptr; } VKAPI_ATTR void* DefaultReallocate(void*, void* ptr, size_t size, size_t alignment, VkSystemAllocationScope) { if (size == 0) { free(ptr); return nullptr; } // TODO(jessehall): Right now we never shrink allocations; if the new // request is smaller than the existing chunk, we just continue using it. // Right now the loader never reallocs, so this doesn't matter. If that // changes, or if this code is copied into some other project, this should // probably have a heuristic to allocate-copy-free when doing so will save // "enough" space. size_t old_size = ptr ? malloc_usable_size(ptr) : 0; if (size <= old_size) return ptr; void* new_ptr = nullptr; if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) return nullptr; if (ptr) { memcpy(new_ptr, ptr, std::min(old_size, size)); free(ptr); } return new_ptr; } VKAPI_ATTR void DefaultFree(void*, void* ptr) { ALOGD_CALLSTACK("Free: %p", ptr); free(ptr); } InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) { void* data_mem = allocator.pfnAllocation( allocator.pUserData, sizeof(InstanceData), alignof(InstanceData), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!data_mem) return nullptr; return new (data_mem) InstanceData(allocator); } void FreeInstanceData(InstanceData* data, const VkAllocationCallbacks& allocator) { data->~InstanceData(); allocator.pfnFree(allocator.pUserData, data); } DeviceData* AllocateDeviceData( const VkAllocationCallbacks& allocator, const DebugReportCallbackList& debug_report_callbacks) { void* data_mem = allocator.pfnAllocation( allocator.pUserData, sizeof(DeviceData), alignof(DeviceData), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); if (!data_mem) return nullptr; return new (data_mem) DeviceData(allocator, debug_report_callbacks); } void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) { data->~DeviceData(); allocator.pfnFree(allocator.pUserData, data); } } // anonymous namespace bool Debuggable() { return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0); } bool OpenHAL() { return Hal::Open(); } const VkAllocationCallbacks& GetDefaultAllocator() { static const VkAllocationCallbacks kDefaultAllocCallbacks = { .pUserData = nullptr, .pfnAllocation = DefaultAllocate, .pfnReallocation = DefaultReallocate, .pfnFree = DefaultFree, }; return kDefaultAllocCallbacks; } PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { const ProcHook* hook = GetProcHook(pName); if (!hook) return Hal::Device().GetInstanceProcAddr(instance, pName); if (!instance) { if (hook->type == ProcHook::GLOBAL) return hook->proc; // v0 layers expect // // vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice"); // // to work. if (strcmp(pName, "vkCreateDevice") == 0) return hook->proc; ALOGE( "internal vkGetInstanceProcAddr called for %s without an instance", pName); return nullptr; } PFN_vkVoidFunction proc; switch (hook->type) { case ProcHook::INSTANCE: proc = (GetData(instance).hook_extensions[hook->extension]) ? hook->proc : nullptr; break; case ProcHook::DEVICE: proc = (hook->extension == ProcHook::EXTENSION_CORE) ? hook->proc : hook->checked_proc; break; default: ALOGE( "internal vkGetInstanceProcAddr called for %s with an instance", pName); proc = nullptr; break; } return proc; } PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) { const ProcHook* hook = GetProcHook(pName); if (!hook) return GetData(device).driver.GetDeviceProcAddr(device, pName); if (hook->type != ProcHook::DEVICE) { ALOGE("internal vkGetDeviceProcAddr called for %s", pName); return nullptr; } return (GetData(device).hook_extensions[hook->extension]) ? hook->proc : nullptr; } VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { static const std::array loader_extensions = {{ // WSI extensions {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}, {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_SPEC_VERSION}, }}; static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, }; // enumerate our extensions first if (!pLayerName && pProperties) { uint32_t count = std::min( *pPropertyCount, static_cast(loader_extensions.size())); std::copy_n(loader_extensions.begin(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; return VK_INCOMPLETE; } pProperties += count; *pPropertyCount -= count; if (Hal::Get().GetDebugReportIndex() < 0) { if (!*pPropertyCount) { *pPropertyCount = count; return VK_INCOMPLETE; } pProperties[0] = loader_debug_report_extension; pProperties += 1; *pPropertyCount -= 1; } } VkResult result = Hal::Device().EnumerateInstanceExtensionProperties( pLayerName, pPropertyCount, pProperties); if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE)) { int idx = Hal::Get().GetDebugReportIndex(); if (idx < 0) { *pPropertyCount += 1; } else if (pProperties && static_cast(idx) < *pPropertyCount) { pProperties[idx].specVersion = std::min(pProperties[idx].specVersion, loader_debug_report_extension.specVersion); } *pPropertyCount += loader_extensions.size(); } return result; } VkResult EnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { const InstanceData& data = GetData(physicalDevice); VkResult result = data.driver.EnumerateDeviceExtensionProperties( physicalDevice, pLayerName, pPropertyCount, pProperties); if (result != VK_SUCCESS && result != VK_INCOMPLETE) return result; if (!pProperties) return result; // map VK_ANDROID_native_buffer to VK_KHR_swapchain for (uint32_t i = 0; i < *pPropertyCount; i++) { auto& prop = pProperties[i]; if (strcmp(prop.extensionName, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0) continue; memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME, sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME)); prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION; } return result; } VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { const VkAllocationCallbacks& data_allocator = (pAllocator) ? *pAllocator : GetDefaultAllocator(); CreateInfoWrapper wrapper(*pCreateInfo, data_allocator); VkResult result = wrapper.Validate(); if (result != VK_SUCCESS) return result; InstanceData* data = AllocateInstanceData(data_allocator); if (!data) return VK_ERROR_OUT_OF_HOST_MEMORY; data->hook_extensions |= wrapper.GetHookExtensions(); // call into the driver VkInstance instance; result = Hal::Device().CreateInstance( static_cast(wrapper), pAllocator, &instance); if (result != VK_SUCCESS) { FreeInstanceData(data, data_allocator); return result; } // initialize InstanceDriverTable if (!SetData(instance, *data) || !InitDriverTable(instance, Hal::Device().GetInstanceProcAddr, wrapper.GetHalExtensions())) { data->driver.DestroyInstance = reinterpret_cast( Hal::Device().GetInstanceProcAddr(instance, "vkDestroyInstance")); if (data->driver.DestroyInstance) data->driver.DestroyInstance(instance, pAllocator); FreeInstanceData(data, data_allocator); return VK_ERROR_INCOMPATIBLE_DRIVER; } data->get_device_proc_addr = reinterpret_cast( Hal::Device().GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); if (!data->get_device_proc_addr) { data->driver.DestroyInstance(instance, pAllocator); FreeInstanceData(data, data_allocator); return VK_ERROR_INCOMPATIBLE_DRIVER; } *pInstance = instance; return VK_SUCCESS; } void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator) { InstanceData& data = GetData(instance); data.driver.DestroyInstance(instance, pAllocator); VkAllocationCallbacks local_allocator; if (!pAllocator) { local_allocator = data.allocator; pAllocator = &local_allocator; } FreeInstanceData(&data, *pAllocator); } VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { const InstanceData& instance_data = GetData(physicalDevice); const VkAllocationCallbacks& data_allocator = (pAllocator) ? *pAllocator : instance_data.allocator; CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator); VkResult result = wrapper.Validate(); if (result != VK_SUCCESS) return result; DeviceData* data = AllocateDeviceData(data_allocator, instance_data.debug_report_callbacks); if (!data) return VK_ERROR_OUT_OF_HOST_MEMORY; data->hook_extensions |= wrapper.GetHookExtensions(); // call into the driver VkDevice dev; result = instance_data.driver.CreateDevice( physicalDevice, static_cast(wrapper), pAllocator, &dev); if (result != VK_SUCCESS) { FreeDeviceData(data, data_allocator); return result; } // initialize DeviceDriverTable if (!SetData(dev, *data) || !InitDriverTable(dev, instance_data.get_device_proc_addr, wrapper.GetHalExtensions())) { data->driver.DestroyDevice = reinterpret_cast( instance_data.get_device_proc_addr(dev, "vkDestroyDevice")); if (data->driver.DestroyDevice) data->driver.DestroyDevice(dev, pAllocator); FreeDeviceData(data, data_allocator); return VK_ERROR_INCOMPATIBLE_DRIVER; } data->driver_device = dev; *pDevice = dev; return VK_SUCCESS; } void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) { DeviceData& data = GetData(device); data.driver.DestroyDevice(device, pAllocator); VkAllocationCallbacks local_allocator; if (!pAllocator) { local_allocator = data.allocator; pAllocator = &local_allocator; } FreeDeviceData(&data, *pAllocator); } VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) { const auto& data = GetData(instance); VkResult result = data.driver.EnumeratePhysicalDevices( instance, pPhysicalDeviceCount, pPhysicalDevices); if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) { for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) SetData(pPhysicalDevices[i], data); } return result; } void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue) { const auto& data = GetData(device); data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); SetData(*pQueue, data); } VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) { const auto& data = GetData(device); VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers); if (result == VK_SUCCESS) { for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) SetData(pCommandBuffers[i], data); } return result; } } // namespace driver } // namespace vulkan vulkan/libvulkan/driver.h0100644 0000000 0000000 00000017027 13077405420 014551 0ustar000000000 0000000 /* * Copyright 2016 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 LIBVULKAN_DRIVER_H #define LIBVULKAN_DRIVER_H 1 #include #include #include #include #include #include #include "api_gen.h" #include "driver_gen.h" #include "debug_report.h" #include "swapchain.h" namespace vulkan { // This is here so that we can embed api::{Instance,Device}Data in // driver::{Instance,Device}Data to avoid pointer chasing. They are // considered opaque to the driver layer. namespace api { struct InstanceData { InstanceDispatchTable dispatch; // LayerChain::ActiveLayer array void* layers; uint32_t layer_count; // debug.vulkan.enable_callback PFN_vkDestroyDebugReportCallbackEXT destroy_debug_callback; VkDebugReportCallbackEXT debug_callback; }; struct DeviceData { DeviceDispatchTable dispatch; }; } // namespace api namespace driver { VK_DEFINE_HANDLE(InstanceDispatchable) VK_DEFINE_HANDLE(DeviceDispatchable) struct InstanceData { InstanceData(const VkAllocationCallbacks& alloc) : opaque_api_data(), allocator(alloc), driver(), get_device_proc_addr(nullptr) { hook_extensions.set(ProcHook::EXTENSION_CORE); } api::InstanceData opaque_api_data; const VkAllocationCallbacks allocator; std::bitset hook_extensions; InstanceDriverTable driver; PFN_vkGetDeviceProcAddr get_device_proc_addr; DebugReportCallbackList debug_report_callbacks; }; struct DeviceData { DeviceData(const VkAllocationCallbacks& alloc, const DebugReportCallbackList& debug_report_callbacks_) : opaque_api_data(), allocator(alloc), debug_report_callbacks(debug_report_callbacks_), driver() { hook_extensions.set(ProcHook::EXTENSION_CORE); } api::DeviceData opaque_api_data; const VkAllocationCallbacks allocator; const DebugReportCallbackList& debug_report_callbacks; std::bitset hook_extensions; VkDevice driver_device; DeviceDriverTable driver; }; bool Debuggable(); bool OpenHAL(); const VkAllocationCallbacks& GetDefaultAllocator(); // clang-format off VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName); VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName); VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); // clang-format on template void StaticAssertDispatchable(DispatchableType) { static_assert( std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, "unrecognized dispatchable type"); } template bool SetDataInternal(DispatchableType dispatchable, const void* data) { StaticAssertDispatchable(dispatchable); hwvulkan_dispatch_t* dispatch = reinterpret_cast(dispatchable); // must be magic or already set if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC && dispatch->vtbl != data) { ALOGE("invalid dispatchable object magic 0x%" PRIxPTR, dispatch->magic); return false; } dispatch->vtbl = data; return true; } template void* GetDataInternal(DispatchableType dispatchable) { StaticAssertDispatchable(dispatchable); const hwvulkan_dispatch_t* dispatch = reinterpret_cast(dispatchable); return const_cast(dispatch->vtbl); } inline bool SetData(VkInstance instance, const InstanceData& data) { return SetDataInternal(instance, &data); } inline bool SetData(VkPhysicalDevice physical_dev, const InstanceData& data) { return SetDataInternal(physical_dev, &data); } inline bool SetData(InstanceDispatchable dispatchable, const InstanceData& data) { return SetDataInternal(dispatchable, &data); } inline bool SetData(VkDevice dev, const DeviceData& data) { return SetDataInternal(dev, &data); } inline bool SetData(VkQueue queue, const DeviceData& data) { return SetDataInternal(queue, &data); } inline bool SetData(VkCommandBuffer cmd, const DeviceData& data) { return SetDataInternal(cmd, &data); } inline bool SetData(DeviceDispatchable dispatchable, const DeviceData& data) { return SetDataInternal(dispatchable, &data); } inline InstanceData& GetData(VkInstance instance) { return *reinterpret_cast(GetDataInternal(instance)); } inline InstanceData& GetData(VkPhysicalDevice physical_dev) { return *reinterpret_cast(GetDataInternal(physical_dev)); } inline InstanceData& GetData(InstanceDispatchable dispatchable) { return *reinterpret_cast(GetDataInternal(dispatchable)); } inline DeviceData& GetData(VkDevice dev) { return *reinterpret_cast(GetDataInternal(dev)); } inline DeviceData& GetData(VkQueue queue) { return *reinterpret_cast(GetDataInternal(queue)); } inline DeviceData& GetData(VkCommandBuffer cmd) { return *reinterpret_cast(GetDataInternal(cmd)); } inline DeviceData& GetData(DeviceDispatchable dispatchable) { return *reinterpret_cast(GetDataInternal(dispatchable)); } template const DebugReportLogger Logger(DispatchableType dispatchable) { return DebugReportLogger(GetData(dispatchable).debug_report_callbacks); } } // namespace driver } // namespace vulkan #endif // LIBVULKAN_DRIVER_H vulkan/libvulkan/driver_gen.cpp0100644 0000000 0000000 00000027771 13077405420 015744 0ustar000000000 0000000 /* * Copyright 2016 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. */ // WARNING: This file is generated. See ../README.md for instructions. #include #include #include #include "driver.h" namespace vulkan { namespace driver { namespace { // clang-format off VKAPI_ATTR VkResult checkedCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { return CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); } else { Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed."); return VK_SUCCESS; } } VKAPI_ATTR void checkedDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { DestroySwapchainKHR(device, swapchain, pAllocator); } else { Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed."); } } VKAPI_ATTR VkResult checkedGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { return GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); } else { Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed."); return VK_SUCCESS; } } VKAPI_ATTR VkResult checkedAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { return AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); } else { Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed."); return VK_SUCCESS; } } VKAPI_ATTR VkResult checkedQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { if (GetData(queue).hook_extensions[ProcHook::KHR_swapchain]) { return QueuePresentKHR(queue, pPresentInfo); } else { Logger(queue).Err(queue, "VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed."); return VK_SUCCESS; } } // clang-format on const ProcHook g_proc_hooks[] = { // clang-format off { "vkAcquireImageANDROID", ProcHook::DEVICE, ProcHook::ANDROID_native_buffer, nullptr, nullptr, }, { "vkAcquireNextImageKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, reinterpret_cast(AcquireNextImageKHR), reinterpret_cast(checkedAcquireNextImageKHR), }, { "vkAllocateCommandBuffers", ProcHook::DEVICE, ProcHook::EXTENSION_CORE, reinterpret_cast(AllocateCommandBuffers), nullptr, }, { "vkCreateAndroidSurfaceKHR", ProcHook::INSTANCE, ProcHook::KHR_android_surface, reinterpret_cast(CreateAndroidSurfaceKHR), nullptr, }, { "vkCreateDebugReportCallbackEXT", ProcHook::INSTANCE, ProcHook::EXT_debug_report, reinterpret_cast(CreateDebugReportCallbackEXT), nullptr, }, { "vkCreateDevice", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, reinterpret_cast(CreateDevice), nullptr, }, { "vkCreateInstance", ProcHook::GLOBAL, ProcHook::EXTENSION_CORE, reinterpret_cast(CreateInstance), nullptr, }, { "vkCreateSwapchainKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, reinterpret_cast(CreateSwapchainKHR), reinterpret_cast(checkedCreateSwapchainKHR), }, { "vkDebugReportMessageEXT", ProcHook::INSTANCE, ProcHook::EXT_debug_report, reinterpret_cast(DebugReportMessageEXT), nullptr, }, { "vkDestroyDebugReportCallbackEXT", ProcHook::INSTANCE, ProcHook::EXT_debug_report, reinterpret_cast(DestroyDebugReportCallbackEXT), nullptr, }, { "vkDestroyDevice", ProcHook::DEVICE, ProcHook::EXTENSION_CORE, reinterpret_cast(DestroyDevice), nullptr, }, { "vkDestroyInstance", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, reinterpret_cast(DestroyInstance), nullptr, }, { "vkDestroySurfaceKHR", ProcHook::INSTANCE, ProcHook::KHR_surface, reinterpret_cast(DestroySurfaceKHR), nullptr, }, { "vkDestroySwapchainKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, reinterpret_cast(DestroySwapchainKHR), reinterpret_cast(checkedDestroySwapchainKHR), }, { "vkEnumerateDeviceExtensionProperties", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, reinterpret_cast(EnumerateDeviceExtensionProperties), nullptr, }, { "vkEnumerateInstanceExtensionProperties", ProcHook::GLOBAL, ProcHook::EXTENSION_CORE, reinterpret_cast(EnumerateInstanceExtensionProperties), nullptr, }, { "vkEnumeratePhysicalDevices", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, reinterpret_cast(EnumeratePhysicalDevices), nullptr, }, { "vkGetDeviceProcAddr", ProcHook::DEVICE, ProcHook::EXTENSION_CORE, reinterpret_cast(GetDeviceProcAddr), nullptr, }, { "vkGetDeviceQueue", ProcHook::DEVICE, ProcHook::EXTENSION_CORE, reinterpret_cast(GetDeviceQueue), nullptr, }, { "vkGetInstanceProcAddr", ProcHook::INSTANCE, ProcHook::EXTENSION_CORE, reinterpret_cast(GetInstanceProcAddr), nullptr, }, { "vkGetPhysicalDeviceSurfaceCapabilitiesKHR", ProcHook::INSTANCE, ProcHook::KHR_surface, reinterpret_cast(GetPhysicalDeviceSurfaceCapabilitiesKHR), nullptr, }, { "vkGetPhysicalDeviceSurfaceFormatsKHR", ProcHook::INSTANCE, ProcHook::KHR_surface, reinterpret_cast(GetPhysicalDeviceSurfaceFormatsKHR), nullptr, }, { "vkGetPhysicalDeviceSurfacePresentModesKHR", ProcHook::INSTANCE, ProcHook::KHR_surface, reinterpret_cast(GetPhysicalDeviceSurfacePresentModesKHR), nullptr, }, { "vkGetPhysicalDeviceSurfaceSupportKHR", ProcHook::INSTANCE, ProcHook::KHR_surface, reinterpret_cast(GetPhysicalDeviceSurfaceSupportKHR), nullptr, }, { "vkGetSwapchainGrallocUsageANDROID", ProcHook::DEVICE, ProcHook::ANDROID_native_buffer, nullptr, nullptr, }, { "vkGetSwapchainImagesKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, reinterpret_cast(GetSwapchainImagesKHR), reinterpret_cast(checkedGetSwapchainImagesKHR), }, { "vkQueuePresentKHR", ProcHook::DEVICE, ProcHook::KHR_swapchain, reinterpret_cast(QueuePresentKHR), reinterpret_cast(checkedQueuePresentKHR), }, { "vkQueueSignalReleaseImageANDROID", ProcHook::DEVICE, ProcHook::ANDROID_native_buffer, nullptr, nullptr, }, // clang-format on }; } // anonymous const ProcHook* GetProcHook(const char* name) { const auto& begin = g_proc_hooks; const auto& end = g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); const auto hook = std::lower_bound( begin, end, name, [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; } ProcHook::Extension GetProcHookExtension(const char* name) { // clang-format off if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer; if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report; if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface; if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; // clang-format on return ProcHook::EXTENSION_UNKNOWN; } #define UNLIKELY(expr) __builtin_expect((expr), 0) #define INIT_PROC(obj, proc) \ do { \ data.driver.proc = \ reinterpret_cast(get_proc(obj, "vk" #proc)); \ if (UNLIKELY(!data.driver.proc)) { \ ALOGE("missing " #obj " proc: vk" #proc); \ success = false; \ } \ } while (0) #define INIT_PROC_EXT(ext, obj, proc) \ do { \ if (extensions[ProcHook::ext]) \ INIT_PROC(obj, proc); \ } while (0) bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset& extensions) { auto& data = GetData(instance); bool success = true; // clang-format off INIT_PROC(instance, DestroyInstance); INIT_PROC(instance, EnumeratePhysicalDevices); INIT_PROC(instance, GetInstanceProcAddr); INIT_PROC(instance, CreateDevice); INIT_PROC(instance, EnumerateDeviceExtensionProperties); INIT_PROC_EXT(EXT_debug_report, instance, CreateDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, instance, DestroyDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, instance, DebugReportMessageEXT); // clang-format on return success; } bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset& extensions) { auto& data = GetData(dev); bool success = true; // clang-format off INIT_PROC(dev, GetDeviceProcAddr); INIT_PROC(dev, DestroyDevice); INIT_PROC(dev, GetDeviceQueue); INIT_PROC(dev, CreateImage); INIT_PROC(dev, DestroyImage); INIT_PROC(dev, AllocateCommandBuffers); INIT_PROC_EXT(ANDROID_native_buffer, dev, GetSwapchainGrallocUsageANDROID); INIT_PROC_EXT(ANDROID_native_buffer, dev, AcquireImageANDROID); INIT_PROC_EXT(ANDROID_native_buffer, dev, QueueSignalReleaseImageANDROID); // clang-format on return success; } } // namespace driver } // namespace vulkan // clang-format on vulkan/libvulkan/driver_gen.h0100644 0000000 0000000 00000005712 13077405420 015400 0ustar000000000 0000000 /* * Copyright 2016 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. */ // WARNING: This file is generated. See ../README.md for instructions. #ifndef LIBVULKAN_DRIVER_GEN_H #define LIBVULKAN_DRIVER_GEN_H #include #include #include namespace vulkan { namespace driver { struct ProcHook { enum Type { GLOBAL, INSTANCE, DEVICE, }; enum Extension { ANDROID_native_buffer, EXT_debug_report, KHR_android_surface, KHR_surface, KHR_swapchain, EXTENSION_CORE, // valid bit EXTENSION_COUNT, EXTENSION_UNKNOWN, }; const char* name; Type type; Extension extension; PFN_vkVoidFunction proc; PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks }; struct InstanceDriverTable { // clang-format off PFN_vkDestroyInstance DestroyInstance; PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices; PFN_vkGetInstanceProcAddr GetInstanceProcAddr; PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; PFN_vkDebugReportMessageEXT DebugReportMessageEXT; // clang-format on }; struct DeviceDriverTable { // clang-format off PFN_vkGetDeviceProcAddr GetDeviceProcAddr; PFN_vkDestroyDevice DestroyDevice; PFN_vkGetDeviceQueue GetDeviceQueue; PFN_vkCreateImage CreateImage; PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID; PFN_vkAcquireImageANDROID AcquireImageANDROID; PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID; // clang-format on }; const ProcHook* GetProcHook(const char* name); ProcHook::Extension GetProcHookExtension(const char* name); bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, const std::bitset& extensions); bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, const std::bitset& extensions); } // namespace driver } // namespace vulkan #endif // LIBVULKAN_DRIVER_TABLE_H vulkan/libvulkan/layers_extensions.cpp0100644 0000000 0000000 00000044270 13077405420 017367 0ustar000000000 0000000 /* * Copyright 2016 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 "layers_extensions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and // not a good long-term solution. Having a hard-coded enum of extensions is // bad, of course. Representing sets of extensions (requested, supported, etc.) // as a bitset isn't necessarily bad, if the mapping from extension to bit were // dynamic. Need to rethink this completely when there's a little more time. // TODO(jessehall): This file currently builds up global data structures as it // loads, and never cleans them up. This means we're doing heap allocations // without going through an app-provided allocator, but worse, we'll leak those // allocations if the loader is unloaded. // // We should allocate "enough" BSS space, and suballocate from there. Will // probably want to intern strings, etc., and will need some custom/manual data // structures. namespace vulkan { namespace api { struct Layer { VkLayerProperties properties; size_t library_idx; // true if the layer intercepts vkCreateDevice and device commands bool is_global; std::vector instance_extensions; std::vector device_extensions; }; namespace { const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan"; class LayerLibrary { public: LayerLibrary(const std::string& path) : path_(path), dlhandle_(nullptr), refcount_(0) {} LayerLibrary(LayerLibrary&& other) : path_(std::move(other.path_)), dlhandle_(other.dlhandle_), refcount_(other.refcount_) { other.dlhandle_ = nullptr; other.refcount_ = 0; } LayerLibrary(const LayerLibrary&) = delete; LayerLibrary& operator=(const LayerLibrary&) = delete; // these are thread-safe bool Open(); void Close(); bool EnumerateLayers(size_t library_idx, std::vector& instance_layers) const; void* GetGPA(const Layer& layer, const char* gpa_name, size_t gpa_name_len) const; private: const std::string path_; std::mutex mutex_; void* dlhandle_; size_t refcount_; }; bool LayerLibrary::Open() { std::lock_guard lock(mutex_); if (refcount_++ == 0) { ALOGV("opening layer library '%s'", path_.c_str()); // Libraries in the system layer library dir can't be loaded into // the application namespace. That causes compatibility problems, since // any symbol dependencies will be resolved by system libraries. They // can't safely use libc++_shared, for example. Which is one reason // (among several) we only allow them in non-user builds. auto app_namespace = LoaderData::GetInstance().app_namespace; if (app_namespace && !android::base::StartsWith(path_, kSystemLayerLibraryDir)) { android_dlextinfo dlextinfo = {}; dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; dlextinfo.library_namespace = app_namespace; dlhandle_ = android_dlopen_ext(path_.c_str(), RTLD_NOW | RTLD_LOCAL, &dlextinfo); } else { dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL); } if (!dlhandle_) { ALOGE("failed to load layer library '%s': %s", path_.c_str(), dlerror()); refcount_ = 0; return false; } } return true; } void LayerLibrary::Close() { std::lock_guard lock(mutex_); if (--refcount_ == 0) { ALOGV("closing layer library '%s'", path_.c_str()); dlclose(dlhandle_); dlhandle_ = nullptr; } } bool LayerLibrary::EnumerateLayers(size_t library_idx, std::vector& instance_layers) const { PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers = reinterpret_cast( dlsym(dlhandle_, "vkEnumerateInstanceLayerProperties")); PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions = reinterpret_cast( dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties")); if (!enumerate_instance_layers || !enumerate_instance_extensions) { ALOGE("layer library '%s' missing some instance enumeration functions", path_.c_str()); return false; } // device functions are optional PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers = reinterpret_cast( dlsym(dlhandle_, "vkEnumerateDeviceLayerProperties")); PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions = reinterpret_cast( dlsym(dlhandle_, "vkEnumerateDeviceExtensionProperties")); // get layer counts uint32_t num_instance_layers = 0; uint32_t num_device_layers = 0; VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr); if (result != VK_SUCCESS || !num_instance_layers) { if (result != VK_SUCCESS) { ALOGE( "vkEnumerateInstanceLayerProperties failed for library '%s': " "%d", path_.c_str(), result); } return false; } if (enumerate_device_layers) { result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, nullptr); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceLayerProperties failed for library '%s': %d", path_.c_str(), result); return false; } } // get layer properties VkLayerProperties* properties = static_cast(alloca( (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); result = enumerate_instance_layers(&num_instance_layers, properties); if (result != VK_SUCCESS) { ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d", path_.c_str(), result); return false; } if (num_device_layers > 0) { result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, properties + num_instance_layers); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceLayerProperties failed for library '%s': %d", path_.c_str(), result); return false; } } // append layers to instance_layers size_t prev_num_instance_layers = instance_layers.size(); instance_layers.reserve(prev_num_instance_layers + num_instance_layers); for (size_t i = 0; i < num_instance_layers; i++) { const VkLayerProperties& props = properties[i]; Layer layer; layer.properties = props; layer.library_idx = library_idx; layer.is_global = false; uint32_t count = 0; result = enumerate_instance_extensions(props.layerName, &count, nullptr); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateInstanceExtensionProperties(\"%s\") failed for " "library '%s': %d", props.layerName, path_.c_str(), result); instance_layers.resize(prev_num_instance_layers); return false; } layer.instance_extensions.resize(count); result = enumerate_instance_extensions( props.layerName, &count, layer.instance_extensions.data()); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateInstanceExtensionProperties(\"%s\") failed for " "library '%s': %d", props.layerName, path_.c_str(), result); instance_layers.resize(prev_num_instance_layers); return false; } for (size_t j = 0; j < num_device_layers; j++) { const auto& dev_props = properties[num_instance_layers + j]; if (memcmp(&props, &dev_props, sizeof(props)) == 0) { layer.is_global = true; break; } } if (layer.is_global && enumerate_device_extensions) { result = enumerate_device_extensions( VK_NULL_HANDLE, props.layerName, &count, nullptr); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceExtensionProperties(\"%s\") failed for " "library '%s': %d", props.layerName, path_.c_str(), result); instance_layers.resize(prev_num_instance_layers); return false; } layer.device_extensions.resize(count); result = enumerate_device_extensions( VK_NULL_HANDLE, props.layerName, &count, layer.device_extensions.data()); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceExtensionProperties(\"%s\") failed for " "library '%s': %d", props.layerName, path_.c_str(), result); instance_layers.resize(prev_num_instance_layers); return false; } } instance_layers.push_back(layer); ALOGD("added %s layer '%s' from library '%s'", (layer.is_global) ? "global" : "instance", props.layerName, path_.c_str()); } return true; } void* LayerLibrary::GetGPA(const Layer& layer, const char* gpa_name, size_t gpa_name_len) const { void* gpa; size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName)); char* name = static_cast(alloca(layer_name_len + gpa_name_len + 1)); strcpy(name, layer.properties.layerName); strcpy(name + layer_name_len, gpa_name); if (!(gpa = dlsym(dlhandle_, name))) { strcpy(name, "vk"); strcpy(name + 2, gpa_name); gpa = dlsym(dlhandle_, name); } return gpa; } // ---------------------------------------------------------------------------- std::vector g_layer_libraries; std::vector g_instance_layers; void AddLayerLibrary(const std::string& path) { LayerLibrary library(path); if (!library.Open()) return; if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) { library.Close(); return; } library.Close(); g_layer_libraries.emplace_back(std::move(library)); } template void ForEachFileInDir(const std::string& dirname, Functor functor) { auto dir_deleter = [](DIR* handle) { closedir(handle); }; std::unique_ptr dir(opendir(dirname.c_str()), dir_deleter); if (!dir) { // It's normal for some search directories to not exist, especially // /data/local/debug/vulkan. int err = errno; ALOGW_IF(err != ENOENT, "failed to open layer directory '%s': %s", dirname.c_str(), strerror(err)); return; } ALOGD("searching for layers in '%s'", dirname.c_str()); dirent* entry; while ((entry = readdir(dir.get())) != nullptr) functor(entry->d_name); } template void ForEachFileInZip(const std::string& zipname, const std::string& dir_in_zip, Functor functor) { int32_t err; ZipArchiveHandle zip = nullptr; if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) { ALOGE("failed to open apk '%s': %d", zipname.c_str(), err); return; } std::string prefix(dir_in_zip + "/"); const ZipString prefix_str(prefix.c_str()); void* iter_cookie = nullptr; if ((err = StartIteration(zip, &iter_cookie, &prefix_str, nullptr)) != 0) { ALOGE("failed to iterate entries in apk '%s': %d", zipname.c_str(), err); CloseArchive(zip); return; } ALOGD("searching for layers in '%s!/%s'", zipname.c_str(), dir_in_zip.c_str()); ZipEntry entry; ZipString name; while (Next(iter_cookie, &entry, &name) == 0) { std::string filename( reinterpret_cast(name.name) + prefix.length(), name.name_length - prefix.length()); // only enumerate direct entries of the directory, not subdirectories if (filename.find('/') != filename.npos) continue; // Check whether it *may* be possible to load the library directly from // the APK. Loading still may fail for other reasons, but this at least // lets us avoid failed-to-load log messages in the typical case of // compressed and/or unaligned libraries. if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0) continue; functor(filename); } EndIteration(iter_cookie); CloseArchive(zip); } template void ForEachFileInPath(const std::string& path, Functor functor) { size_t zip_pos = path.find("!/"); if (zip_pos == std::string::npos) { ForEachFileInDir(path, functor); } else { ForEachFileInZip(path.substr(0, zip_pos), path.substr(zip_pos + 2), functor); } } void DiscoverLayersInPathList(const std::string& pathstr) { std::vector paths = android::base::Split(pathstr, ":"); for (const auto& path : paths) { ForEachFileInPath(path, [&](const std::string& filename) { if (android::base::StartsWith(filename, "libVkLayer") && android::base::EndsWith(filename, ".so")) { AddLayerLibrary(path + "/" + filename); } }); } } const VkExtensionProperties* FindExtension( const std::vector& extensions, const char* name) { auto it = std::find_if(extensions.cbegin(), extensions.cend(), [=](const VkExtensionProperties& ext) { return (strcmp(ext.extensionName, name) == 0); }); return (it != extensions.cend()) ? &*it : nullptr; } void* GetLayerGetProcAddr(const Layer& layer, const char* gpa_name, size_t gpa_name_len) { const LayerLibrary& library = g_layer_libraries[layer.library_idx]; return library.GetGPA(layer, gpa_name, gpa_name_len); } } // anonymous namespace void DiscoverLayers() { if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { DiscoverLayersInPathList(kSystemLayerLibraryDir); } if (!LoaderData::GetInstance().layer_path.empty()) DiscoverLayersInPathList(LoaderData::GetInstance().layer_path); } uint32_t GetLayerCount() { return static_cast(g_instance_layers.size()); } const Layer& GetLayer(uint32_t index) { return g_instance_layers[index]; } const Layer* FindLayer(const char* name) { auto layer = std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(), [=](const Layer& entry) { return strcmp(entry.properties.layerName, name) == 0; }); return (layer != g_instance_layers.cend()) ? &*layer : nullptr; } const VkLayerProperties& GetLayerProperties(const Layer& layer) { return layer.properties; } bool IsLayerGlobal(const Layer& layer) { return layer.is_global; } const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer, uint32_t& count) { count = static_cast(layer.instance_extensions.size()); return layer.instance_extensions.data(); } const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer, uint32_t& count) { count = static_cast(layer.device_extensions.size()); return layer.device_extensions.data(); } const VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer, const char* name) { return FindExtension(layer.instance_extensions, name); } const VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer, const char* name) { return FindExtension(layer.device_extensions, name); } LayerRef GetLayerRef(const Layer& layer) { LayerLibrary& library = g_layer_libraries[layer.library_idx]; return LayerRef((library.Open()) ? &layer : nullptr); } LayerRef::LayerRef(const Layer* layer) : layer_(layer) {} LayerRef::~LayerRef() { if (layer_) { LayerLibrary& library = g_layer_libraries[layer_->library_idx]; library.Close(); } } LayerRef::LayerRef(LayerRef&& other) : layer_(other.layer_) { other.layer_ = nullptr; } PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { return layer_ ? reinterpret_cast( GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) : nullptr; } PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { return layer_ ? reinterpret_cast( GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) : nullptr; } } // namespace api } // namespace vulkan vulkan/libvulkan/layers_extensions.h0100644 0000000 0000000 00000004216 13077405420 017030 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBVULKAN_LAYERS_EXTENSIONS_H #define LIBVULKAN_LAYERS_EXTENSIONS_H 1 #include namespace vulkan { namespace api { struct Layer; class LayerRef { public: LayerRef(const Layer* layer); LayerRef(LayerRef&& other); ~LayerRef(); LayerRef(const LayerRef&) = delete; LayerRef& operator=(const LayerRef&) = delete; // provides bool-like behavior operator const Layer*() const { return layer_; } PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const; PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const; private: const Layer* layer_; }; void DiscoverLayers(); uint32_t GetLayerCount(); const Layer& GetLayer(uint32_t index); const Layer* FindLayer(const char* name); const VkLayerProperties& GetLayerProperties(const Layer& layer); bool IsLayerGlobal(const Layer& layer); const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer, uint32_t& count); const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer, uint32_t& count); const VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer, const char* name); const VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer, const char* name); LayerRef GetLayerRef(const Layer& layer); } // namespace api } // namespace vulkan #endif // LIBVULKAN_LAYERS_EXTENSIONS_H vulkan/libvulkan/stubhal.cpp0100644 0000000 0000000 00000011500 13077405420 015241 0ustar000000000 0000000 /* * Copyright 2016 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. */ /* NOTE: * This stub HAL is only used internally by the loader when a real HAL * implementation is not present, in order to avoid needing "null HAL" checks * throughout the loader. It does not enumerate any physical devices, and is * only as conformant to the Vulkan and Android HAL interfaces as the loader * needs it to be. Do not use it as an example of a correct implementation; the * code in ../null_driver is better for that. */ #undef LOG_TAG #define LOG_TAG "vkstub" #include #include #include #include #include #include "stubhal.h" namespace vulkan { namespace stubhal { namespace { const size_t kMaxInstances = 32; static std::mutex g_instance_mutex; static std::bitset g_instance_used(false); static std::array g_instances; [[noreturn]] void NoOp() { LOG_ALWAYS_FATAL("invalid stub function called"); } VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* /*layer_name*/, uint32_t* count, VkExtensionProperties* /*properties*/) { *count = 0; return VK_SUCCESS; } VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* count, VkLayerProperties* /*properties*/) { *count = 0; return VK_SUCCESS; } VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* /*create_info*/, const VkAllocationCallbacks* /*allocator*/, VkInstance* instance) { std::lock_guard lock(g_instance_mutex); for (size_t i = 0; i < kMaxInstances; i++) { if (!g_instance_used[i]) { g_instance_used[i] = true; g_instances[i].magic = HWVULKAN_DISPATCH_MAGIC; *instance = reinterpret_cast(&g_instances[i]); return VK_SUCCESS; } } ALOGE("no more instances available (max=%zu)", kMaxInstances); return VK_ERROR_INITIALIZATION_FAILED; } VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* /*allocator*/) { std::lock_guard lock(g_instance_mutex); ssize_t idx = reinterpret_cast(instance) - &g_instances[0]; ALOG_ASSERT(idx >= 0 && static_cast(idx) < g_instance_used.size(), "DestroyInstance: invalid instance handle"); g_instance_used[static_cast(idx)] = false; } VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance /*instance*/, uint32_t* count, VkPhysicalDevice* /*gpus*/) { *count = 0; return VK_SUCCESS; } VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/, const char* name) { if (strcmp(name, "vkCreateInstance") == 0) return reinterpret_cast(CreateInstance); if (strcmp(name, "vkDestroyInstance") == 0) return reinterpret_cast(DestroyInstance); if (strcmp(name, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast( EnumerateInstanceExtensionProperties); if (strcmp(name, "vkEnumeratePhysicalDevices") == 0) return reinterpret_cast(EnumeratePhysicalDevices); if (strcmp(name, "vkGetInstanceProcAddr") == 0) return reinterpret_cast(GetInstanceProcAddr); // None of the other Vulkan functions should ever be called, as they all // take a VkPhysicalDevice or other object obtained from a physical device. return reinterpret_cast(NoOp); } } // anonymous namespace const hwvulkan_device_t kDevice = { .common = { .tag = HARDWARE_DEVICE_TAG, .version = HWVULKAN_DEVICE_API_VERSION_0_1, .module = nullptr, .close = nullptr, }, .EnumerateInstanceExtensionProperties = EnumerateInstanceExtensionProperties, .CreateInstance = CreateInstance, .GetInstanceProcAddr = GetInstanceProcAddr, }; } // namespace stubhal } // namespace vulkan vulkan/libvulkan/stubhal.h0100644 0000000 0000000 00000001537 13077405420 014717 0ustar000000000 0000000 /* * Copyright 2016 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 LIBVULKAN_STUBHAL_H #define LIBVULKAN_STUBHAL_H 1 struct hwvulkan_device_t; namespace vulkan { namespace stubhal { extern const hwvulkan_device_t kDevice; } // namespace stubhal } // namespace vulkan #endif // LIBVULKAN_STUBHAL_H vulkan/libvulkan/swapchain.cpp0100644 0000000 0000000 00000113236 13077405420 015565 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "driver.h" // TODO(jessehall): Currently we don't have a good error code for when a native // window operation fails. Just returning INITIALIZATION_FAILED for now. Later // versions (post SDK 0.9) of the API/extension have a better error code. // When updating to that version, audit all error returns. namespace vulkan { namespace driver { namespace { const VkSurfaceTransformFlagsKHR kSupportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { // Native and Vulkan transforms are isomorphic, but are represented // differently. Vulkan transforms are built up of an optional horizontal // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native // transforms are built up from a horizontal flip, vertical flip, and // 90-degree rotation, all optional but always in that order. // TODO(jessehall): For now, only support pure rotations, not // flip or flip-and-rotate, until I have more time to test them and build // sample code. As far as I know we never actually use anything besides // pure rotations anyway. switch (native) { case 0: // 0x0 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2 // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4 return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90 return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY: default: return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } } int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { switch (transform) { case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: return NATIVE_WINDOW_TRANSFORM_ROT_270; case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: return NATIVE_WINDOW_TRANSFORM_ROT_180; case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: return NATIVE_WINDOW_TRANSFORM_ROT_90; // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: // return NATIVE_WINDOW_TRANSFORM_FLIP_H; // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: // return NATIVE_WINDOW_TRANSFORM_FLIP_H | // NATIVE_WINDOW_TRANSFORM_ROT_90; // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: // return NATIVE_WINDOW_TRANSFORM_FLIP_V; // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: // return NATIVE_WINDOW_TRANSFORM_FLIP_V | // NATIVE_WINDOW_TRANSFORM_ROT_90; case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: default: return 0; } } // ---------------------------------------------------------------------------- struct Surface { android::sp window; VkSwapchainKHR swapchain_handle; }; VkSurfaceKHR HandleFromSurface(Surface* surface) { return VkSurfaceKHR(reinterpret_cast(surface)); } Surface* SurfaceFromHandle(VkSurfaceKHR handle) { return reinterpret_cast(handle); } struct Swapchain { Swapchain(Surface& surface_, uint32_t num_images_) : surface(surface_), num_images(num_images_) {} Surface& surface; uint32_t num_images; struct Image { Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {} VkImage image; android::sp buffer; // The fence is only valid when the buffer is dequeued, and should be // -1 any other time. When valid, we own the fd, and must ensure it is // closed: either by closing it explicitly when queueing the buffer, // or by passing ownership e.g. to ANativeWindow::cancelBuffer(). int dequeue_fence; bool dequeued; } images[android::BufferQueue::NUM_BUFFER_SLOTS]; }; VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { return VkSwapchainKHR(reinterpret_cast(swapchain)); } Swapchain* SwapchainFromHandle(VkSwapchainKHR handle) { return reinterpret_cast(handle); } void ReleaseSwapchainImage(VkDevice device, ANativeWindow* window, int release_fence, Swapchain::Image& image) { ALOG_ASSERT(release_fence == -1 || image.dequeued, "ReleaseSwapchainImage: can't provide a release fence for " "non-dequeued images"); if (image.dequeued) { if (release_fence >= 0) { // We get here from vkQueuePresentKHR. The application is // responsible for creating an execution dependency chain from // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR // (release_fence), so we can drop the dequeue_fence here. if (image.dequeue_fence >= 0) close(image.dequeue_fence); } else { // We get here during swapchain destruction, or various serious // error cases e.g. when we can't create the release_fence during // vkQueuePresentKHR. In non-error cases, the dequeue_fence should // have already signalled, since the swapchain images are supposed // to be idle before the swapchain is destroyed. In error cases, // there may be rendering in flight to the image, but since we // weren't able to create a release_fence, waiting for the // dequeue_fence is about the best we can do. release_fence = image.dequeue_fence; } image.dequeue_fence = -1; if (window) { window->cancelBuffer(window, image.buffer.get(), release_fence); } else { if (release_fence >= 0) { sync_wait(release_fence, -1 /* forever */); close(release_fence); } } image.dequeued = false; } if (image.image) { GetData(device).driver.DestroyImage(device, image.image, nullptr); image.image = VK_NULL_HANDLE; } image.buffer.clear(); } void OrphanSwapchain(VkDevice device, Swapchain* swapchain) { if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain)) return; for (uint32_t i = 0; i < swapchain->num_images; i++) { if (!swapchain->images[i].dequeued) ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]); } swapchain->surface.swapchain_handle = VK_NULL_HANDLE; } } // anonymous namespace VKAPI_ATTR VkResult CreateAndroidSurfaceKHR( VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface) { if (!allocator) allocator = &GetData(instance).allocator; void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface), alignof(Surface), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!mem) return VK_ERROR_OUT_OF_HOST_MEMORY; Surface* surface = new (mem) Surface; surface->window = pCreateInfo->window; surface->swapchain_handle = VK_NULL_HANDLE; // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. int err = native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), err); surface->~Surface(); allocator->pfnFree(allocator->pUserData, surface); return VK_ERROR_INITIALIZATION_FAILED; } *out_surface = HandleFromSurface(surface); return VK_SUCCESS; } VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface_handle, const VkAllocationCallbacks* allocator) { Surface* surface = SurfaceFromHandle(surface_handle); if (!surface) return; native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL); ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE, "destroyed VkSurfaceKHR 0x%" PRIx64 " has active VkSwapchainKHR 0x%" PRIx64, reinterpret_cast(surface_handle), reinterpret_cast(surface->swapchain_handle)); surface->~Surface(); if (!allocator) allocator = &GetData(instance).allocator; allocator->pfnFree(allocator->pUserData, surface); } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, uint32_t /*queue_family*/, VkSurfaceKHR /*surface*/, VkBool32* supported) { *supported = VK_TRUE; return VK_SUCCESS; } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( VkPhysicalDevice /*pdev*/, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities) { int err; ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); int width, height; err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); if (err != 0) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); if (err != 0) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } int transform_hint; err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); if (err != 0) { ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } // TODO(jessehall): Figure out what the min/max values should be. capabilities->minImageCount = 2; capabilities->maxImageCount = 3; capabilities->currentExtent = VkExtent2D{static_cast(width), static_cast(height)}; // TODO(jessehall): Figure out what the max extent should be. Maximum // texture dimension maybe? capabilities->minImageExtent = VkExtent2D{1, 1}; capabilities->maxImageExtent = VkExtent2D{4096, 4096}; capabilities->maxImageArrayLayers = 1; capabilities->supportedTransforms = kSupportedTransforms; capabilities->currentTransform = TranslateNativeToVulkanTransform(transform_hint); // On Android, window composition is a WindowManager property, not something // associated with the bufferqueue. It can't be changed from here. capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; // TODO(jessehall): I think these are right, but haven't thought hard about // it. Do we need to query the driver for support of any of these? // Currently not included: // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable? // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not capabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; return VK_SUCCESS; } VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/, VkSurfaceKHR /*surface*/, uint32_t* count, VkSurfaceFormatKHR* formats) { // TODO(jessehall): Fill out the set of supported formats. Longer term, add // a new gralloc method to query whether a (format, usage) pair is // supported, and check that for each gralloc format that corresponds to a // Vulkan format. Shorter term, just add a few more formats to the ones // hardcoded below. const VkSurfaceFormatKHR kFormats[] = { {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, }; const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); VkResult result = VK_SUCCESS; if (formats) { if (*count < kNumFormats) result = VK_INCOMPLETE; std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats); } *count = kNumFormats; return result; } VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/, VkSurfaceKHR /*surface*/, uint32_t* count, VkPresentModeKHR* modes) { const VkPresentModeKHR kModes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, }; const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]); VkResult result = VK_SUCCESS; if (modes) { if (*count < kNumModes) result = VK_INCOMPLETE; std::copy(kModes, kModes + std::min(*count, kNumModes), modes); } *count = kNumModes; return result; } VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle) { int err; VkResult result = VK_SUCCESS; ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64 " minImageCount=%u imageFormat=%u imageColorSpace=%u" " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u" " oldSwapchain=0x%" PRIx64, reinterpret_cast(create_info->surface), create_info->minImageCount, create_info->imageFormat, create_info->imageColorSpace, create_info->imageExtent.width, create_info->imageExtent.height, create_info->imageUsage, create_info->preTransform, create_info->presentMode, reinterpret_cast(create_info->oldSwapchain)); if (!allocator) allocator = &GetData(device).allocator; ALOGV_IF(create_info->imageArrayLayers != 1, "swapchain imageArrayLayers=%u not supported", create_info->imageArrayLayers); ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, "swapchain imageColorSpace=%u not supported", create_info->imageColorSpace); ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0, "swapchain preTransform=%#x not supported", create_info->preTransform); ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR || create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR), "swapchain presentMode=%u not supported", create_info->presentMode); Surface& surface = *SurfaceFromHandle(create_info->surface); if (surface.swapchain_handle != create_info->oldSwapchain) { ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64 " because it already has active swapchain 0x%" PRIx64 " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64, reinterpret_cast(create_info->surface), reinterpret_cast(surface.swapchain_handle), reinterpret_cast(create_info->oldSwapchain)); return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; } if (create_info->oldSwapchain != VK_NULL_HANDLE) OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain)); // -- Reset the native window -- // The native window might have been used previously, and had its properties // changed from defaults. That will affect the answer we get for queries // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we // attempt such queries. // The native window only allows dequeueing all buffers before any have // been queued, since after that point at least one is assumed to be in // non-FREE state at any given time. Disconnecting and re-connecting // orphans the previous buffers, getting us back to the state where we can // dequeue all buffers. err = native_window_api_disconnect(surface.window.get(), NATIVE_WINDOW_API_EGL); ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err); err = native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL); ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)", strerror(-err), err); err = native_window_set_buffer_count(surface.window.get(), 0); if (err != 0) { ALOGE("native_window_set_buffer_count(0) failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } err = surface.window->setSwapInterval(surface.window.get(), 1); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } // -- Configure the native window -- const auto& dispatch = GetData(device).driver; int native_format = HAL_PIXEL_FORMAT_RGBA_8888; switch (create_info->imageFormat) { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: native_format = HAL_PIXEL_FORMAT_RGBA_8888; break; case VK_FORMAT_R5G6B5_UNORM_PACK16: native_format = HAL_PIXEL_FORMAT_RGB_565; break; default: ALOGV("unsupported swapchain format %d", create_info->imageFormat); break; } err = native_window_set_buffers_format(surface.window.get(), native_format); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", native_format, strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } err = native_window_set_buffers_data_space(surface.window.get(), HAL_DATASPACE_SRGB_LINEAR); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } err = native_window_set_buffers_dimensions( surface.window.get(), static_cast(create_info->imageExtent.width), static_cast(create_info->imageExtent.height)); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", create_info->imageExtent.width, create_info->imageExtent.height, strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } // VkSwapchainCreateInfo::preTransform indicates the transformation the app // applied during rendering. native_window_set_transform() expects the // inverse: the transform the app is requesting that the compositor perform // during composition. With native windows, pre-transform works by rendering // with the same transform the compositor is applying (as in Vulkan), but // then requesting the inverse transform, so that when the compositor does // it's job the two transforms cancel each other out and the compositor ends // up applying an identity transform to the app's buffer. err = native_window_set_buffers_transform( surface.window.get(), InvertTransformToNative(create_info->preTransform)); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", InvertTransformToNative(create_info->preTransform), strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } err = native_window_set_scaling_mode( surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } int query_value; err = surface.window->query(surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_INITIALIZATION_FAILED; } uint32_t min_undequeued_buffers = static_cast(query_value); // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using // async mode or not, and assumes not. But in async mode, the BufferQueue // requires an extra undequeued buffer. // See BufferQueueCore::getMinUndequeuedBufferCountLocked(). if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) min_undequeued_buffers += 1; uint32_t num_images = (create_info->minImageCount - 1) + min_undequeued_buffers; err = native_window_set_buffer_count(surface.window.get(), num_images); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } int gralloc_usage = 0; // TODO(jessehall): Remove conditional once all drivers have been updated if (dispatch.GetSwapchainGrallocUsageANDROID) { result = dispatch.GetSwapchainGrallocUsageANDROID( device, create_info->imageFormat, create_info->imageUsage, &gralloc_usage); if (result != VK_SUCCESS) { ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); return VK_ERROR_INITIALIZATION_FAILED; } } else { gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; } err = native_window_set_usage(surface.window.get(), gralloc_usage); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } int swap_interval = create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; err = surface.window->setSwapInterval(surface.window.get(), swap_interval); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)", swap_interval, strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } // -- Allocate our Swapchain object -- // After this point, we must deallocate the swapchain on error. void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Swapchain), alignof(Swapchain), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!mem) return VK_ERROR_OUT_OF_HOST_MEMORY; Swapchain* swapchain = new (mem) Swapchain(surface, num_images); // -- Dequeue all buffers and create a VkImage for each -- // Any failures during or after this must cancel the dequeued buffers. VkNativeBufferANDROID image_native_buffer = { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID, #pragma clang diagnostic pop .pNext = nullptr, }; VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = &image_native_buffer, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, .extent = {0, 0, 1}, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = create_info->imageUsage, .flags = 0, .sharingMode = create_info->imageSharingMode, .queueFamilyIndexCount = create_info->queueFamilyIndexCount, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, }; for (uint32_t i = 0; i < num_images; i++) { Swapchain::Image& img = swapchain->images[i]; ANativeWindowBuffer* buffer; err = surface.window->dequeueBuffer(surface.window.get(), &buffer, &img.dequeue_fence); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate // possible errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); result = VK_ERROR_INITIALIZATION_FAILED; break; } img.buffer = buffer; img.dequeued = true; image_create.extent = VkExtent3D{static_cast(img.buffer->width), static_cast(img.buffer->height), 1}; image_native_buffer.handle = img.buffer->handle; image_native_buffer.stride = img.buffer->stride; image_native_buffer.format = img.buffer->format; image_native_buffer.usage = img.buffer->usage; result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); if (result != VK_SUCCESS) { ALOGD("vkCreateImage w/ native buffer failed: %u", result); break; } } // -- Cancel all buffers, returning them to the queue -- // If an error occurred before, also destroy the VkImage and release the // buffer reference. Otherwise, we retain a strong reference to the buffer. // // TODO(jessehall): The error path here is the same as DestroySwapchain, // but not the non-error path. Should refactor/unify. for (uint32_t i = 0; i < num_images; i++) { Swapchain::Image& img = swapchain->images[i]; if (img.dequeued) { surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), img.dequeue_fence); img.dequeue_fence = -1; img.dequeued = false; } if (result != VK_SUCCESS) { if (img.image) dispatch.DestroyImage(device, img.image, nullptr); } } if (result != VK_SUCCESS) { swapchain->~Swapchain(); allocator->pfnFree(allocator->pUserData, swapchain); return result; } surface.swapchain_handle = HandleFromSwapchain(swapchain); *swapchain_handle = surface.swapchain_handle; return VK_SUCCESS; } VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator) { const auto& dispatch = GetData(device).driver; Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); bool active = swapchain->surface.swapchain_handle == swapchain_handle; ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; for (uint32_t i = 0; i < swapchain->num_images; i++) ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); if (active) swapchain->surface.swapchain_handle = VK_NULL_HANDLE; if (!allocator) allocator = &GetData(device).allocator; swapchain->~Swapchain(); allocator->pfnFree(allocator->pUserData, swapchain); } VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images) { Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle, "getting images for non-active swapchain 0x%" PRIx64 "; only dequeued image handles are valid", reinterpret_cast(swapchain_handle)); VkResult result = VK_SUCCESS; if (images) { uint32_t n = swapchain.num_images; if (*count < swapchain.num_images) { n = *count; result = VK_INCOMPLETE; } for (uint32_t i = 0; i < n; i++) images[i] = swapchain.images[i].image; } *count = swapchain.num_images; return result; } VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence vk_fence, uint32_t* image_index) { Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); ANativeWindow* window = swapchain.surface.window.get(); VkResult result; int err; if (swapchain.surface.swapchain_handle != swapchain_handle) return VK_ERROR_OUT_OF_DATE_KHR; ALOGW_IF( timeout != UINT64_MAX, "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); ANativeWindowBuffer* buffer; int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); return VK_ERROR_INITIALIZATION_FAILED; } uint32_t idx; for (idx = 0; idx < swapchain.num_images; idx++) { if (swapchain.images[idx].buffer.get() == buffer) { swapchain.images[idx].dequeued = true; swapchain.images[idx].dequeue_fence = fence_fd; break; } } if (idx == swapchain.num_images) { ALOGE("dequeueBuffer returned unrecognized buffer"); window->cancelBuffer(window, buffer, fence_fd); return VK_ERROR_OUT_OF_DATE_KHR; } int fence_clone = -1; if (fence_fd != -1) { fence_clone = dup(fence_fd); if (fence_clone == -1) { ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno); sync_wait(fence_fd, -1 /* forever */); } } result = GetData(device).driver.AcquireImageANDROID( device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence); if (result != VK_SUCCESS) { // NOTE: we're relying on AcquireImageANDROID to close fence_clone, // even if the call fails. We could close it ourselves on failure, but // that would create a race condition if the driver closes it on a // failure path: some other thread might create an fd with the same // number between the time the driver closes it and the time we close // it. We must assume one of: the driver *always* closes it even on // failure, or *never* closes it on failure. window->cancelBuffer(window, buffer, fence_fd); swapchain.images[idx].dequeued = false; swapchain.images[idx].dequeue_fence = -1; return result; } *image_index = idx; return VK_SUCCESS; } static VkResult WorstPresentResult(VkResult a, VkResult b) { // See the error ranking for vkQueuePresentKHR at the end of section 29.6 // (in spec version 1.0.14). static const VkResult kWorstToBest[] = { VK_ERROR_DEVICE_LOST, VK_ERROR_SURFACE_LOST_KHR, VK_ERROR_OUT_OF_DATE_KHR, VK_ERROR_OUT_OF_DEVICE_MEMORY, VK_ERROR_OUT_OF_HOST_MEMORY, VK_SUBOPTIMAL_KHR, }; for (auto result : kWorstToBest) { if (a == result || b == result) return result; } ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a); ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b); return a != VK_SUCCESS ? a : b; } VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d", present_info->sType); ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL"); VkDevice device = GetData(queue).driver_device; const auto& dispatch = GetData(queue).driver; VkResult final_result = VK_SUCCESS; for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) { Swapchain& swapchain = *SwapchainFromHandle(present_info->pSwapchains[sc]); uint32_t image_idx = present_info->pImageIndices[sc]; Swapchain::Image& img = swapchain.images[image_idx]; VkResult swapchain_result = VK_SUCCESS; VkResult result; int err; int fence = -1; result = dispatch.QueueSignalReleaseImageANDROID( queue, present_info->waitSemaphoreCount, present_info->pWaitSemaphores, img.image, &fence); if (result != VK_SUCCESS) { ALOGE("QueueSignalReleaseImageANDROID failed: %d", result); swapchain_result = result; } if (swapchain.surface.swapchain_handle == present_info->pSwapchains[sc]) { ANativeWindow* window = swapchain.surface.window.get(); if (swapchain_result == VK_SUCCESS) { err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error if (err != 0) { // TODO(jessehall): What now? We should probably cancel the // buffer, I guess? ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult( swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); } if (img.dequeue_fence >= 0) { close(img.dequeue_fence); img.dequeue_fence = -1; } img.dequeued = false; } if (swapchain_result != VK_SUCCESS) { ReleaseSwapchainImage(device, window, fence, img); OrphanSwapchain(device, &swapchain); } } else { ReleaseSwapchainImage(device, nullptr, fence, img); swapchain_result = VK_ERROR_OUT_OF_DATE_KHR; } if (present_info->pResults) present_info->pResults[sc] = swapchain_result; if (swapchain_result != final_result) final_result = WorstPresentResult(final_result, swapchain_result); } return final_result; } } // namespace driver } // namespace vulkan vulkan/libvulkan/swapchain.h0100644 0000000 0000000 00000004611 13077405420 015226 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBVULKAN_SWAPCHAIN_H #define LIBVULKAN_SWAPCHAIN_H 1 #include namespace vulkan { namespace driver { // clang-format off VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats); VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes); VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle); VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator); VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images); VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index); VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info); // clang-format on } // namespace driver } // namespace vulkan #endif // LIBVULKAN_SWAPCHAIN_H vulkan/libvulkan/vulkan_loader_data.cpp0100644 0000000 0000000 00000001424 13077405420 017422 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include using namespace vulkan; LoaderData& LoaderData::GetInstance() { static LoaderData loader_data = {}; return loader_data; } vulkan/nulldrv/0040755 0000000 0000000 00000000000 13077405420 012600 5ustar000000000 0000000 vulkan/nulldrv/Android.mk0100644 0000000 0000000 00000002462 13077405420 014512 0ustar000000000 0000000 # Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_CFLAGS := -std=c99 -fvisibility=hidden -fstrict-aliasing \ -DLOG_TAG=\"vknulldrv\" \ -Weverything -Werror \ -Wno-padded \ -Wno-undef \ -Wno-zero-length-array #LOCAL_CFLAGS += -DLOG_NDEBUG=0 LOCAL_CPPFLAGS := -std=c++1y \ -Wno-c++98-compat-pedantic \ -Wno-c99-extensions LOCAL_C_INCLUDES := \ frameworks/native/vulkan/include LOCAL_SRC_FILES := \ null_driver.cpp \ null_driver_gen.cpp LOCAL_SHARED_LIBRARIES := liblog # Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE := vulkan.default LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) vulkan/nulldrv/null_driver.cpp0100644 0000000 0000000 00000153076 13077405420 015642 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "null_driver_gen.h" using namespace null_driver; struct VkPhysicalDevice_T { hwvulkan_dispatch_t dispatch; }; struct VkInstance_T { hwvulkan_dispatch_t dispatch; VkAllocationCallbacks allocator; VkPhysicalDevice_T physical_device; uint64_t next_callback_handle; }; struct VkQueue_T { hwvulkan_dispatch_t dispatch; }; struct VkCommandBuffer_T { hwvulkan_dispatch_t dispatch; }; namespace { // Handles for non-dispatchable objects are either pointers, or arbitrary // 64-bit non-zero values. We only use pointers when we need to keep state for // the object even in a null driver. For the rest, we form a handle as: // [63:63] = 1 to distinguish from pointer handles* // [62:56] = non-zero handle type enum value // [55: 0] = per-handle-type incrementing counter // * This works because virtual addresses with the high bit set are reserved // for kernel data in all ABIs we run on. // // We never reclaim handles on vkDestroy*. It's not even necessary for us to // have distinct handles for live objects, and practically speaking we won't // ever create 2^56 objects of the same type from a single VkDevice in a null // driver. // // Using a namespace here instead of 'enum class' since we want scoped // constants but also want implicit conversions to integral types. namespace HandleType { enum Enum { kBufferView, kDebugReportCallbackEXT, kDescriptorPool, kDescriptorSet, kDescriptorSetLayout, kEvent, kFence, kFramebuffer, kImageView, kPipeline, kPipelineCache, kPipelineLayout, kQueryPool, kRenderPass, kSampler, kSemaphore, kShaderModule, kNumTypes }; } // namespace HandleType const VkDeviceSize kMaxDeviceMemory = 0x10000000; // 256 MiB, arbitrary } // anonymous namespace struct VkDevice_T { hwvulkan_dispatch_t dispatch; VkAllocationCallbacks allocator; VkInstance_T* instance; VkQueue_T queue; std::array next_handle; }; // ----------------------------------------------------------------------------- // Declare HAL_MODULE_INFO_SYM early so it can be referenced by nulldrv_device // later. namespace { int OpenDevice(const hw_module_t* module, const char* id, hw_device_t** device); hw_module_methods_t nulldrv_module_methods = {.open = OpenDevice}; } // namespace #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-variable-declarations" __attribute__((visibility("default"))) hwvulkan_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = HWVULKAN_HARDWARE_MODULE_ID, .name = "Null Vulkan Driver", .author = "The Android Open Source Project", .methods = &nulldrv_module_methods, }, }; #pragma clang diagnostic pop // ----------------------------------------------------------------------------- namespace { int CloseDevice(struct hw_device_t* /*device*/) { // nothing to do - opening a device doesn't allocate any resources return 0; } hwvulkan_device_t nulldrv_device = { .common = { .tag = HARDWARE_DEVICE_TAG, .version = HWVULKAN_DEVICE_API_VERSION_0_1, .module = &HAL_MODULE_INFO_SYM.common, .close = CloseDevice, }, .EnumerateInstanceExtensionProperties = EnumerateInstanceExtensionProperties, .CreateInstance = CreateInstance, .GetInstanceProcAddr = GetInstanceProcAddr}; int OpenDevice(const hw_module_t* /*module*/, const char* id, hw_device_t** device) { if (strcmp(id, HWVULKAN_DEVICE_0) == 0) { *device = &nulldrv_device.common; return 0; } return -ENOENT; } VkInstance_T* GetInstanceFromPhysicalDevice( VkPhysicalDevice_T* physical_device) { return reinterpret_cast( reinterpret_cast(physical_device) - offsetof(VkInstance_T, physical_device)); } uint64_t AllocHandle(uint64_t type, uint64_t* next_handle) { const uint64_t kHandleMask = (UINT64_C(1) << 56) - 1; ALOGE_IF(*next_handle == kHandleMask, "non-dispatchable handles of type=%" PRIu64 " are about to overflow", type); return (UINT64_C(1) << 63) | ((type & 0x7) << 56) | ((*next_handle)++ & kHandleMask); } template Handle AllocHandle(VkInstance instance, HandleType::Enum type) { return reinterpret_cast( AllocHandle(type, &instance->next_callback_handle)); } template Handle AllocHandle(VkDevice device, HandleType::Enum type) { return reinterpret_cast( AllocHandle(type, &device->next_handle[type])); } VKAPI_ATTR void* DefaultAllocate(void*, size_t size, size_t alignment, VkSystemAllocationScope) { void* ptr = nullptr; // Vulkan requires 'alignment' to be a power of two, but posix_memalign // additionally requires that it be at least sizeof(void*). int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); return ret == 0 ? ptr : nullptr; } VKAPI_ATTR void* DefaultReallocate(void*, void* ptr, size_t size, size_t alignment, VkSystemAllocationScope) { if (size == 0) { free(ptr); return nullptr; } // TODO(jessehall): Right now we never shrink allocations; if the new // request is smaller than the existing chunk, we just continue using it. // The null driver never reallocs, so this doesn't matter. If that changes, // or if this code is copied into some other project, this should probably // have a heuristic to allocate-copy-free when doing so will save "enough" // space. size_t old_size = ptr ? malloc_usable_size(ptr) : 0; if (size <= old_size) return ptr; void* new_ptr = nullptr; if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) return nullptr; if (ptr) { memcpy(new_ptr, ptr, std::min(old_size, size)); free(ptr); } return new_ptr; } VKAPI_ATTR void DefaultFree(void*, void* ptr) { free(ptr); } const VkAllocationCallbacks kDefaultAllocCallbacks = { .pUserData = nullptr, .pfnAllocation = DefaultAllocate, .pfnReallocation = DefaultReallocate, .pfnFree = DefaultFree, }; } // namespace namespace null_driver { #define DEFINE_OBJECT_HANDLE_CONVERSION(T) \ T* Get##T##FromHandle(Vk##T h); \ T* Get##T##FromHandle(Vk##T h) { \ return reinterpret_cast(uintptr_t(h)); \ } \ Vk##T GetHandleTo##T(const T* obj); \ Vk##T GetHandleTo##T(const T* obj) { \ return Vk##T(reinterpret_cast(obj)); \ } // ----------------------------------------------------------------------------- // Global VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties( const char* layer_name, uint32_t* count, VkExtensionProperties* properties) { if (layer_name) { ALOGW( "Driver vkEnumerateInstanceExtensionProperties shouldn't be called " "with a layer name ('%s')", layer_name); } // NOTE: Change this to zero to report and extension, which can be useful // for testing changes to the loader. #if 1 (void)properties; // unused *count = 0; return VK_SUCCESS; #else const VkExtensionProperties kExtensions[] = { {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}}; const uint32_t kExtensionsCount = sizeof(kExtensions) / sizeof(kExtensions[0]); if (!properties || *count > kExtensionsCount) *count = kExtensionsCount; if (properties) std::copy(kExtensions, kExtensions + *count, properties); return *count < kExtensionsCount ? VK_INCOMPLETE : VK_SUCCESS; #endif } VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* out_instance) { if (!allocator) allocator = &kDefaultAllocCallbacks; VkInstance_T* instance = static_cast(allocator->pfnAllocation( allocator->pUserData, sizeof(VkInstance_T), alignof(VkInstance_T), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)); if (!instance) return VK_ERROR_OUT_OF_HOST_MEMORY; instance->dispatch.magic = HWVULKAN_DISPATCH_MAGIC; instance->allocator = *allocator; instance->physical_device.dispatch.magic = HWVULKAN_DISPATCH_MAGIC; instance->next_callback_handle = 0; for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) { if (strcmp(create_info->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { ALOGV("instance extension '%s' requested", create_info->ppEnabledExtensionNames[i]); } else { ALOGW("unsupported extension '%s' requested", create_info->ppEnabledExtensionNames[i]); } } *out_instance = instance; return VK_SUCCESS; } VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) { return instance ? GetInstanceProcAddr(name) : GetGlobalProcAddr(name); } VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice, const char* name) { return GetInstanceProcAddr(name); } // ----------------------------------------------------------------------------- // Instance void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* /*allocator*/) { instance->allocator.pfnFree(instance->allocator.pUserData, instance); } // ----------------------------------------------------------------------------- // PhysicalDevice VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* physical_device_count, VkPhysicalDevice* physical_devices) { if (physical_devices && *physical_device_count >= 1) physical_devices[0] = &instance->physical_device; *physical_device_count = 1; return VK_SUCCESS; } VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice /*gpu*/, uint32_t* count, VkLayerProperties* /*properties*/) { ALOGW("Driver vkEnumerateDeviceLayerProperties shouldn't be called"); *count = 0; return VK_SUCCESS; } VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice /*gpu*/, const char* layer_name, uint32_t* count, VkExtensionProperties* properties) { if (layer_name) { ALOGW( "Driver vkEnumerateDeviceExtensionProperties shouldn't be called " "with a layer name ('%s')", layer_name); *count = 0; return VK_SUCCESS; } const VkExtensionProperties kExtensions[] = { {VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME, VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION}}; const uint32_t kExtensionsCount = sizeof(kExtensions) / sizeof(kExtensions[0]); if (!properties || *count > kExtensionsCount) *count = kExtensionsCount; if (properties) std::copy(kExtensions, kExtensions + *count, properties); return *count < kExtensionsCount ? VK_INCOMPLETE : VK_SUCCESS; } void GetPhysicalDeviceProperties(VkPhysicalDevice, VkPhysicalDeviceProperties* properties) { properties->apiVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION); properties->driverVersion = VK_MAKE_VERSION(0, 0, 1); properties->vendorID = 0; properties->deviceID = 0; properties->deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER; strcpy(properties->deviceName, "Android Vulkan Null Driver"); memset(properties->pipelineCacheUUID, 0, sizeof(properties->pipelineCacheUUID)); properties->limits = VkPhysicalDeviceLimits{ 4096, // maxImageDimension1D 4096, // maxImageDimension2D 256, // maxImageDimension3D 4096, // maxImageDimensionCube 256, // maxImageArrayLayers 65536, // maxTexelBufferElements 16384, // maxUniformBufferRange 1 << 27, // maxStorageBufferRange 128, // maxPushConstantsSize 4096, // maxMemoryAllocationCount 4000, // maxSamplerAllocationCount 1, // bufferImageGranularity 0, // sparseAddressSpaceSize 4, // maxBoundDescriptorSets 16, // maxPerStageDescriptorSamplers 12, // maxPerStageDescriptorUniformBuffers 4, // maxPerStageDescriptorStorageBuffers 16, // maxPerStageDescriptorSampledImages 4, // maxPerStageDescriptorStorageImages 4, // maxPerStageDescriptorInputAttachments 128, // maxPerStageResources 96, // maxDescriptorSetSamplers 72, // maxDescriptorSetUniformBuffers 8, // maxDescriptorSetUniformBuffersDynamic 24, // maxDescriptorSetStorageBuffers 4, // maxDescriptorSetStorageBuffersDynamic 96, // maxDescriptorSetSampledImages 24, // maxDescriptorSetStorageImages 4, // maxDescriptorSetInputAttachments 16, // maxVertexInputAttributes 16, // maxVertexInputBindings 2047, // maxVertexInputAttributeOffset 2048, // maxVertexInputBindingStride 64, // maxVertexOutputComponents 0, // maxTessellationGenerationLevel 0, // maxTessellationPatchSize 0, // maxTessellationControlPerVertexInputComponents 0, // maxTessellationControlPerVertexOutputComponents 0, // maxTessellationControlPerPatchOutputComponents 0, // maxTessellationControlTotalOutputComponents 0, // maxTessellationEvaluationInputComponents 0, // maxTessellationEvaluationOutputComponents 0, // maxGeometryShaderInvocations 0, // maxGeometryInputComponents 0, // maxGeometryOutputComponents 0, // maxGeometryOutputVertices 0, // maxGeometryTotalOutputComponents 64, // maxFragmentInputComponents 4, // maxFragmentOutputAttachments 0, // maxFragmentDualSrcAttachments 4, // maxFragmentCombinedOutputResources 16384, // maxComputeSharedMemorySize {65536, 65536, 65536}, // maxComputeWorkGroupCount[3] 128, // maxComputeWorkGroupInvocations {128, 128, 64}, // maxComputeWorkGroupSize[3] 4, // subPixelPrecisionBits 4, // subTexelPrecisionBits 4, // mipmapPrecisionBits UINT32_MAX, // maxDrawIndexedIndexValue 1, // maxDrawIndirectCount 2, // maxSamplerLodBias 1, // maxSamplerAnisotropy 1, // maxViewports {4096, 4096}, // maxViewportDimensions[2] {-8192.0f, 8191.0f}, // viewportBoundsRange[2] 0, // viewportSubPixelBits 64, // minMemoryMapAlignment 256, // minTexelBufferOffsetAlignment 256, // minUniformBufferOffsetAlignment 256, // minStorageBufferOffsetAlignment -8, // minTexelOffset 7, // maxTexelOffset 0, // minTexelGatherOffset 0, // maxTexelGatherOffset 0.0f, // minInterpolationOffset 0.0f, // maxInterpolationOffset 0, // subPixelInterpolationOffsetBits 4096, // maxFramebufferWidth 4096, // maxFramebufferHeight 256, // maxFramebufferLayers VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // framebufferColorSampleCounts VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // framebufferDepthSampleCounts VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // framebufferStencilSampleCounts VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // framebufferNoAttachmentsSampleCounts 4, // maxColorAttachments VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // sampledImageColorSampleCounts VK_SAMPLE_COUNT_1_BIT, // sampledImageIntegerSampleCounts VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // sampledImageDepthSampleCounts VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT, // sampledImageStencilSampleCounts VK_SAMPLE_COUNT_1_BIT, // storageImageSampleCounts 1, // maxSampleMaskWords VK_TRUE, // timestampComputeAndGraphics 1, // timestampPeriod 0, // maxClipDistances 0, // maxCullDistances 0, // maxCombinedClipAndCullDistances 2, // discreteQueuePriorities {1.0f, 1.0f}, // pointSizeRange[2] {1.0f, 1.0f}, // lineWidthRange[2] 0.0f, // pointSizeGranularity 0.0f, // lineWidthGranularity VK_TRUE, // strictLines VK_TRUE, // standardSampleLocations 1, // optimalBufferCopyOffsetAlignment 1, // optimalBufferCopyRowPitchAlignment 64, // nonCoherentAtomSize }; } void GetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice, uint32_t* count, VkQueueFamilyProperties* properties) { if (!properties || *count > 1) *count = 1; if (properties && *count == 1) { properties->queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; properties->queueCount = 1; properties->timestampValidBits = 64; properties->minImageTransferGranularity = VkExtent3D{1, 1, 1}; } } void GetPhysicalDeviceMemoryProperties( VkPhysicalDevice, VkPhysicalDeviceMemoryProperties* properties) { properties->memoryTypeCount = 1; properties->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; properties->memoryTypes[0].heapIndex = 0; properties->memoryHeapCount = 1; properties->memoryHeaps[0].size = kMaxDeviceMemory; properties->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; } void GetPhysicalDeviceFeatures(VkPhysicalDevice /*gpu*/, VkPhysicalDeviceFeatures* features) { *features = VkPhysicalDeviceFeatures{ VK_TRUE, // robustBufferAccess VK_FALSE, // fullDrawIndexUint32 VK_FALSE, // imageCubeArray VK_FALSE, // independentBlend VK_FALSE, // geometryShader VK_FALSE, // tessellationShader VK_FALSE, // sampleRateShading VK_FALSE, // dualSrcBlend VK_FALSE, // logicOp VK_FALSE, // multiDrawIndirect VK_FALSE, // drawIndirectFirstInstance VK_FALSE, // depthClamp VK_FALSE, // depthBiasClamp VK_FALSE, // fillModeNonSolid VK_FALSE, // depthBounds VK_FALSE, // wideLines VK_FALSE, // largePoints VK_FALSE, // alphaToOne VK_FALSE, // multiViewport VK_FALSE, // samplerAnisotropy VK_FALSE, // textureCompressionETC2 VK_FALSE, // textureCompressionASTC_LDR VK_FALSE, // textureCompressionBC VK_FALSE, // occlusionQueryPrecise VK_FALSE, // pipelineStatisticsQuery VK_FALSE, // vertexPipelineStoresAndAtomics VK_FALSE, // fragmentStoresAndAtomics VK_FALSE, // shaderTessellationAndGeometryPointSize VK_FALSE, // shaderImageGatherExtended VK_FALSE, // shaderStorageImageExtendedFormats VK_FALSE, // shaderStorageImageMultisample VK_FALSE, // shaderStorageImageReadWithoutFormat VK_FALSE, // shaderStorageImageWriteWithoutFormat VK_FALSE, // shaderUniformBufferArrayDynamicIndexing VK_FALSE, // shaderSampledImageArrayDynamicIndexing VK_FALSE, // shaderStorageBufferArrayDynamicIndexing VK_FALSE, // shaderStorageImageArrayDynamicIndexing VK_FALSE, // shaderClipDistance VK_FALSE, // shaderCullDistance VK_FALSE, // shaderFloat64 VK_FALSE, // shaderInt64 VK_FALSE, // shaderInt16 VK_FALSE, // shaderResourceResidency VK_FALSE, // shaderResourceMinLod VK_FALSE, // sparseBinding VK_FALSE, // sparseResidencyBuffer VK_FALSE, // sparseResidencyImage2D VK_FALSE, // sparseResidencyImage3D VK_FALSE, // sparseResidency2Samples VK_FALSE, // sparseResidency4Samples VK_FALSE, // sparseResidency8Samples VK_FALSE, // sparseResidency16Samples VK_FALSE, // sparseResidencyAliased VK_FALSE, // variableMultisampleRate VK_FALSE, // inheritedQueries }; } // ----------------------------------------------------------------------------- // Device VkResult CreateDevice(VkPhysicalDevice physical_device, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* out_device) { VkInstance_T* instance = GetInstanceFromPhysicalDevice(physical_device); if (!allocator) allocator = &instance->allocator; VkDevice_T* device = static_cast(allocator->pfnAllocation( allocator->pUserData, sizeof(VkDevice_T), alignof(VkDevice_T), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE)); if (!device) return VK_ERROR_OUT_OF_HOST_MEMORY; device->dispatch.magic = HWVULKAN_DISPATCH_MAGIC; device->allocator = *allocator; device->instance = instance; device->queue.dispatch.magic = HWVULKAN_DISPATCH_MAGIC; std::fill(device->next_handle.begin(), device->next_handle.end(), UINT64_C(0)); for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) { if (strcmp(create_info->ppEnabledExtensionNames[i], VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0) { ALOGV("Enabling " VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME); } } *out_device = device; return VK_SUCCESS; } void DestroyDevice(VkDevice device, const VkAllocationCallbacks* /*allocator*/) { if (!device) return; device->allocator.pfnFree(device->allocator.pUserData, device); } void GetDeviceQueue(VkDevice device, uint32_t, uint32_t, VkQueue* queue) { *queue = &device->queue; } // ----------------------------------------------------------------------------- // CommandPool struct CommandPool { typedef VkCommandPool HandleType; VkAllocationCallbacks allocator; }; DEFINE_OBJECT_HANDLE_CONVERSION(CommandPool) VkResult CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* /*create_info*/, const VkAllocationCallbacks* allocator, VkCommandPool* cmd_pool) { if (!allocator) allocator = &device->allocator; CommandPool* pool = static_cast(allocator->pfnAllocation( allocator->pUserData, sizeof(CommandPool), alignof(CommandPool), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); if (!pool) return VK_ERROR_OUT_OF_HOST_MEMORY; pool->allocator = *allocator; *cmd_pool = GetHandleToCommandPool(pool); return VK_SUCCESS; } void DestroyCommandPool(VkDevice /*device*/, VkCommandPool cmd_pool, const VkAllocationCallbacks* /*allocator*/) { CommandPool* pool = GetCommandPoolFromHandle(cmd_pool); pool->allocator.pfnFree(pool->allocator.pUserData, pool); } // ----------------------------------------------------------------------------- // CmdBuffer VkResult AllocateCommandBuffers(VkDevice /*device*/, const VkCommandBufferAllocateInfo* alloc_info, VkCommandBuffer* cmdbufs) { VkResult result = VK_SUCCESS; CommandPool& pool = *GetCommandPoolFromHandle(alloc_info->commandPool); std::fill(cmdbufs, cmdbufs + alloc_info->commandBufferCount, nullptr); for (uint32_t i = 0; i < alloc_info->commandBufferCount; i++) { cmdbufs[i] = static_cast(pool.allocator.pfnAllocation( pool.allocator.pUserData, sizeof(VkCommandBuffer_T), alignof(VkCommandBuffer_T), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); if (!cmdbufs[i]) { result = VK_ERROR_OUT_OF_HOST_MEMORY; break; } cmdbufs[i]->dispatch.magic = HWVULKAN_DISPATCH_MAGIC; } if (result != VK_SUCCESS) { for (uint32_t i = 0; i < alloc_info->commandBufferCount; i++) { if (!cmdbufs[i]) break; pool.allocator.pfnFree(pool.allocator.pUserData, cmdbufs[i]); } } return result; } void FreeCommandBuffers(VkDevice /*device*/, VkCommandPool cmd_pool, uint32_t count, const VkCommandBuffer* cmdbufs) { CommandPool& pool = *GetCommandPoolFromHandle(cmd_pool); for (uint32_t i = 0; i < count; i++) pool.allocator.pfnFree(pool.allocator.pUserData, cmdbufs[i]); } // ----------------------------------------------------------------------------- // DeviceMemory struct DeviceMemory { typedef VkDeviceMemory HandleType; VkDeviceSize size; alignas(16) uint8_t data[0]; }; DEFINE_OBJECT_HANDLE_CONVERSION(DeviceMemory) VkResult AllocateMemory(VkDevice device, const VkMemoryAllocateInfo* alloc_info, const VkAllocationCallbacks* allocator, VkDeviceMemory* mem_handle) { if (SIZE_MAX - sizeof(DeviceMemory) <= alloc_info->allocationSize) return VK_ERROR_OUT_OF_HOST_MEMORY; if (!allocator) allocator = &device->allocator; size_t size = sizeof(DeviceMemory) + size_t(alloc_info->allocationSize); DeviceMemory* mem = static_cast(allocator->pfnAllocation( allocator->pUserData, size, alignof(DeviceMemory), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); if (!mem) return VK_ERROR_OUT_OF_HOST_MEMORY; mem->size = size; *mem_handle = GetHandleToDeviceMemory(mem); return VK_SUCCESS; } void FreeMemory(VkDevice device, VkDeviceMemory mem_handle, const VkAllocationCallbacks* allocator) { if (!allocator) allocator = &device->allocator; DeviceMemory* mem = GetDeviceMemoryFromHandle(mem_handle); allocator->pfnFree(allocator->pUserData, mem); } VkResult MapMemory(VkDevice, VkDeviceMemory mem_handle, VkDeviceSize offset, VkDeviceSize, VkMemoryMapFlags, void** out_ptr) { DeviceMemory* mem = GetDeviceMemoryFromHandle(mem_handle); *out_ptr = &mem->data[0] + offset; return VK_SUCCESS; } // ----------------------------------------------------------------------------- // Buffer struct Buffer { typedef VkBuffer HandleType; VkDeviceSize size; }; DEFINE_OBJECT_HANDLE_CONVERSION(Buffer) VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkBuffer* buffer_handle) { ALOGW_IF(create_info->size > kMaxDeviceMemory, "CreateBuffer: requested size 0x%" PRIx64 " exceeds max device memory size 0x%" PRIx64, create_info->size, kMaxDeviceMemory); if (!allocator) allocator = &device->allocator; Buffer* buffer = static_cast(allocator->pfnAllocation( allocator->pUserData, sizeof(Buffer), alignof(Buffer), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); if (!buffer) return VK_ERROR_OUT_OF_HOST_MEMORY; buffer->size = create_info->size; *buffer_handle = GetHandleToBuffer(buffer); return VK_SUCCESS; } void GetBufferMemoryRequirements(VkDevice, VkBuffer buffer_handle, VkMemoryRequirements* requirements) { Buffer* buffer = GetBufferFromHandle(buffer_handle); requirements->size = buffer->size; requirements->alignment = 16; // allow fast Neon/SSE memcpy requirements->memoryTypeBits = 0x1; } void DestroyBuffer(VkDevice device, VkBuffer buffer_handle, const VkAllocationCallbacks* allocator) { if (!allocator) allocator = &device->allocator; Buffer* buffer = GetBufferFromHandle(buffer_handle); allocator->pfnFree(allocator->pUserData, buffer); } // ----------------------------------------------------------------------------- // Image struct Image { typedef VkImage HandleType; VkDeviceSize size; }; DEFINE_OBJECT_HANDLE_CONVERSION(Image) VkResult CreateImage(VkDevice device, const VkImageCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkImage* image_handle) { if (create_info->imageType != VK_IMAGE_TYPE_2D || create_info->format != VK_FORMAT_R8G8B8A8_UNORM || create_info->mipLevels != 1) { ALOGE("CreateImage: not yet implemented: type=%d format=%d mips=%u", create_info->imageType, create_info->format, create_info->mipLevels); return VK_ERROR_OUT_OF_HOST_MEMORY; } VkDeviceSize size = VkDeviceSize(create_info->extent.width * create_info->extent.height) * create_info->arrayLayers * create_info->samples * 4u; ALOGW_IF(size > kMaxDeviceMemory, "CreateImage: image size 0x%" PRIx64 " exceeds max device memory size 0x%" PRIx64, size, kMaxDeviceMemory); if (!allocator) allocator = &device->allocator; Image* image = static_cast(allocator->pfnAllocation( allocator->pUserData, sizeof(Image), alignof(Image), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); if (!image) return VK_ERROR_OUT_OF_HOST_MEMORY; image->size = size; *image_handle = GetHandleToImage(image); return VK_SUCCESS; } void GetImageMemoryRequirements(VkDevice, VkImage image_handle, VkMemoryRequirements* requirements) { Image* image = GetImageFromHandle(image_handle); requirements->size = image->size; requirements->alignment = 16; // allow fast Neon/SSE memcpy requirements->memoryTypeBits = 0x1; } void DestroyImage(VkDevice device, VkImage image_handle, const VkAllocationCallbacks* allocator) { if (!allocator) allocator = &device->allocator; Image* image = GetImageFromHandle(image_handle); allocator->pfnFree(allocator->pUserData, image); } VkResult GetSwapchainGrallocUsageANDROID(VkDevice, VkFormat, VkImageUsageFlags, int* grallocUsage) { // The null driver never reads or writes the gralloc buffer *grallocUsage = 0; return VK_SUCCESS; } VkResult AcquireImageANDROID(VkDevice, VkImage, int fence, VkSemaphore, VkFence) { close(fence); return VK_SUCCESS; } VkResult QueueSignalReleaseImageANDROID(VkQueue, uint32_t, const VkSemaphore*, VkImage, int* fence) { *fence = -1; return VK_SUCCESS; } // ----------------------------------------------------------------------------- // No-op types VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkBufferView* view) { *view = AllocHandle(device, HandleType::kBufferView); return VK_SUCCESS; } VkResult CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkDescriptorPool* pool) { *pool = AllocHandle(device, HandleType::kDescriptorPool); return VK_SUCCESS; } VkResult AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* alloc_info, VkDescriptorSet* descriptor_sets) { for (uint32_t i = 0; i < alloc_info->descriptorSetCount; i++) descriptor_sets[i] = AllocHandle(device, HandleType::kDescriptorSet); return VK_SUCCESS; } VkResult CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkDescriptorSetLayout* layout) { *layout = AllocHandle( device, HandleType::kDescriptorSetLayout); return VK_SUCCESS; } VkResult CreateEvent(VkDevice device, const VkEventCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkEvent* event) { *event = AllocHandle(device, HandleType::kEvent); return VK_SUCCESS; } VkResult CreateFence(VkDevice device, const VkFenceCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkFence* fence) { *fence = AllocHandle(device, HandleType::kFence); return VK_SUCCESS; } VkResult CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkFramebuffer* framebuffer) { *framebuffer = AllocHandle(device, HandleType::kFramebuffer); return VK_SUCCESS; } VkResult CreateImageView(VkDevice device, const VkImageViewCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkImageView* view) { *view = AllocHandle(device, HandleType::kImageView); return VK_SUCCESS; } VkResult CreateGraphicsPipelines(VkDevice device, VkPipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkPipeline* pipelines) { for (uint32_t i = 0; i < count; i++) pipelines[i] = AllocHandle(device, HandleType::kPipeline); return VK_SUCCESS; } VkResult CreateComputePipelines(VkDevice device, VkPipelineCache, uint32_t count, const VkComputePipelineCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkPipeline* pipelines) { for (uint32_t i = 0; i < count; i++) pipelines[i] = AllocHandle(device, HandleType::kPipeline); return VK_SUCCESS; } VkResult CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkPipelineCache* cache) { *cache = AllocHandle(device, HandleType::kPipelineCache); return VK_SUCCESS; } VkResult CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkPipelineLayout* layout) { *layout = AllocHandle(device, HandleType::kPipelineLayout); return VK_SUCCESS; } VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkQueryPool* pool) { *pool = AllocHandle(device, HandleType::kQueryPool); return VK_SUCCESS; } VkResult CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkRenderPass* renderpass) { *renderpass = AllocHandle(device, HandleType::kRenderPass); return VK_SUCCESS; } VkResult CreateSampler(VkDevice device, const VkSamplerCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkSampler* sampler) { *sampler = AllocHandle(device, HandleType::kSampler); return VK_SUCCESS; } VkResult CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkSemaphore* semaphore) { *semaphore = AllocHandle(device, HandleType::kSemaphore); return VK_SUCCESS; } VkResult CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo*, const VkAllocationCallbacks* /*allocator*/, VkShaderModule* module) { *module = AllocHandle(device, HandleType::kShaderModule); return VK_SUCCESS; } VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugReportCallbackEXT* callback) { *callback = AllocHandle( instance, HandleType::kDebugReportCallbackEXT); return VK_SUCCESS; } // ----------------------------------------------------------------------------- // No-op entrypoints // clang-format off #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" void GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) { ALOGV("TODO: vk%s", __FUNCTION__); } VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult EnumerateInstanceLayerProperties(uint32_t* pCount, VkLayerProperties* pProperties) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmitInfo, VkFence fence) { return VK_SUCCESS; } VkResult QueueWaitIdle(VkQueue queue) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult DeviceWaitIdle(VkDevice device) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void UnmapMemory(VkDevice device, VkDeviceMemory mem) { } VkResult FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) { ALOGV("TODO: vk%s", __FUNCTION__); } VkResult BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) { return VK_SUCCESS; } VkResult BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) { return VK_SUCCESS; } void GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { ALOGV("TODO: vk%s", __FUNCTION__); } void GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pNumProperties, VkSparseImageFormatProperties* pProperties) { ALOGV("TODO: vk%s", __FUNCTION__); } VkResult QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* allocator) { } VkResult ResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences) { return VK_SUCCESS; } VkResult GetFenceStatus(VkDevice device, VkFence fence) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout) { return VK_SUCCESS; } void DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* allocator) { } void DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* allocator) { } VkResult GetEventStatus(VkDevice device, VkEvent event) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult SetEvent(VkDevice device, VkEvent event) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult ResetEvent(VkDevice device, VkEvent event) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* allocator) { } VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t startQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* allocator) { } void GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { ALOGV("TODO: vk%s", __FUNCTION__); } void DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* allocator) { } void DestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* allocator) { } void DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* allocator) { } VkResult GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult MergePipelineCaches(VkDevice device, VkPipelineCache destCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* allocator) { } void DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* allocator) { } void DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* allocator) { } void DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* allocator) { } void DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* allocator) { } VkResult ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void UpdateDescriptorSets(VkDevice device, uint32_t writeCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t copyCount, const VkCopyDescriptorSet* pDescriptorCopies) { ALOGV("TODO: vk%s", __FUNCTION__); } VkResult FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet* pDescriptorSets) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* allocator) { } void DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* allocator) { } void GetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) { ALOGV("TODO: vk%s", __FUNCTION__); } VkResult ResetCommandPool(VkDevice device, VkCommandPool cmdPool, VkCommandPoolResetFlags flags) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } VkResult BeginCommandBuffer(VkCommandBuffer cmdBuffer, const VkCommandBufferBeginInfo* pBeginInfo) { return VK_SUCCESS; } VkResult EndCommandBuffer(VkCommandBuffer cmdBuffer) { return VK_SUCCESS; } VkResult ResetCommandBuffer(VkCommandBuffer cmdBuffer, VkCommandBufferResetFlags flags) { ALOGV("TODO: vk%s", __FUNCTION__); return VK_SUCCESS; } void CmdBindPipeline(VkCommandBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { } void CmdSetViewport(VkCommandBuffer cmdBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports) { } void CmdSetScissor(VkCommandBuffer cmdBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors) { } void CmdSetLineWidth(VkCommandBuffer cmdBuffer, float lineWidth) { } void CmdSetDepthBias(VkCommandBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias) { } void CmdSetBlendConstants(VkCommandBuffer cmdBuffer, const float blendConst[4]) { } void CmdSetDepthBounds(VkCommandBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds) { } void CmdSetStencilCompareMask(VkCommandBuffer cmdBuffer, VkStencilFaceFlags faceMask, uint32_t stencilCompareMask) { } void CmdSetStencilWriteMask(VkCommandBuffer cmdBuffer, VkStencilFaceFlags faceMask, uint32_t stencilWriteMask) { } void CmdSetStencilReference(VkCommandBuffer cmdBuffer, VkStencilFaceFlags faceMask, uint32_t stencilReference) { } void CmdBindDescriptorSets(VkCommandBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) { } void CmdBindIndexBuffer(VkCommandBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { } void CmdBindVertexBuffers(VkCommandBuffer cmdBuffer, uint32_t startBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) { } void CmdDraw(VkCommandBuffer cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { } void CmdDrawIndexed(VkCommandBuffer cmdBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { } void CmdDrawIndirect(VkCommandBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { } void CmdDrawIndexedIndirect(VkCommandBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { } void CmdDispatch(VkCommandBuffer cmdBuffer, uint32_t x, uint32_t y, uint32_t z) { } void CmdDispatchIndirect(VkCommandBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset) { } void CmdCopyBuffer(VkCommandBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, uint32_t regionCount, const VkBufferCopy* pRegions) { } void CmdCopyImage(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, uint32_t regionCount, const VkImageCopy* pRegions) { } void CmdBlitImage(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter) { } void CmdCopyBufferToImage(VkCommandBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions) { } void CmdCopyImageToBuffer(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) { } void CmdUpdateBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const uint32_t* pData) { } void CmdFillBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, uint32_t data) { } void CmdClearColorImage(VkCommandBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { } void CmdClearDepthStencilImage(VkCommandBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges) { } void CmdClearAttachments(VkCommandBuffer cmdBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { } void CmdResolveImage(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, uint32_t regionCount, const VkImageResolve* pRegions) { } void CmdSetEvent(VkCommandBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) { } void CmdResetEvent(VkCommandBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) { } void CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { } void CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { } void CmdBeginQuery(VkCommandBuffer cmdBuffer, VkQueryPool queryPool, uint32_t slot, VkQueryControlFlags flags) { } void CmdEndQuery(VkCommandBuffer cmdBuffer, VkQueryPool queryPool, uint32_t slot) { } void CmdResetQueryPool(VkCommandBuffer cmdBuffer, VkQueryPool queryPool, uint32_t startQuery, uint32_t queryCount) { } void CmdWriteTimestamp(VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) { } void CmdCopyQueryPoolResults(VkCommandBuffer cmdBuffer, VkQueryPool queryPool, uint32_t startQuery, uint32_t queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags) { } void CmdPushConstants(VkCommandBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t start, uint32_t length, const void* values) { } void CmdBeginRenderPass(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { } void CmdNextSubpass(VkCommandBuffer cmdBuffer, VkSubpassContents contents) { } void CmdEndRenderPass(VkCommandBuffer cmdBuffer) { } void CmdExecuteCommands(VkCommandBuffer cmdBuffer, uint32_t cmdBuffersCount, const VkCommandBuffer* pCmdBuffers) { } void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { } void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage) { } #pragma clang diagnostic pop // clang-format on } // namespace null_driver vulkan/nulldrv/null_driver.tmpl0100644 0000000 0000000 00000016513 13077405420 016026 0ustar000000000 0000000 {{/* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */}} {{Include "../api/templates/vulkan_common.tmpl"}} {{Global "clang-format" (Strings "clang-format" "-style=file")}} {{Macro "DefineGlobals" $}} {{$ | Macro "null_driver_gen.h" | Format (Global "clang-format") | Write "null_driver_gen.h" }} {{$ | Macro "null_driver_gen.cpp" | Format (Global "clang-format") | Write "null_driver_gen.cpp"}} {{/* ------------------------------------------------------------------------------- null_driver_gen.h ------------------------------------------------------------------------------- */}} {{define "null_driver_gen.h"}} /* •* Copyright 2015 The Android Open Source Project •* •* Licensed under the Apache License, Version 2.0 (the "License"); •* you may not use this file except in compliance with the License. •* You may obtain a copy of the License at •* •* http://www.apache.org/licenses/LICENSE-2.0 •* •* Unless required by applicable law or agreed to in writing, software •* distributed under the License is distributed on an "AS IS" BASIS, •* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. •* See the License for the specific language governing permissions and •* limitations under the License. •*/ ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #ifndef NULLDRV_NULL_DRIVER_H #define NULLDRV_NULL_DRIVER_H 1 ¶ #include #include ¶ namespace null_driver {« ¶ PFN_vkVoidFunction GetGlobalProcAddr(const char* name); PFN_vkVoidFunction GetInstanceProcAddr(const char* name); ¶ // clang-format off {{range $f := AllCommands $}} {{if (Macro "IsDriverFunction" $f)}} VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}); {{end}} {{end}} VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); // clang-format on ¶ »} // namespace null_driver ¶ #endif // NULLDRV_NULL_DRIVER_H ¶{{end}} {{/* ------------------------------------------------------------------------------- null_driver_gen.cpp ------------------------------------------------------------------------------- */}} {{define "null_driver_gen.cpp"}} /* •* Copyright 2015 The Android Open Source Project •* •* Licensed under the Apache License, Version 2.0 (the "License"); •* you may not use this file except in compliance with the License. •* You may obtain a copy of the License at •* •* http://www.apache.org/licenses/LICENSE-2.0 •* •* Unless required by applicable law or agreed to in writing, software •* distributed under the License is distributed on an "AS IS" BASIS, •* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. •* See the License for the specific language governing permissions and •* limitations under the License. •*/ ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ #include "null_driver_gen.h" #include ¶ using namespace null_driver; ¶ namespace { ¶ struct NameProc { const char* name; PFN_vkVoidFunction proc; }; ¶ PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) { const auto& entry = std::lower_bound( begin, end, name, [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; }); if (entry == end || strcmp(entry->name, name) != 0) return nullptr; return entry->proc; } ¶ template PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) { return Lookup(name, procs, procs + N); } ¶ const NameProc kGlobalProcs[] = {« // clang-format off {{range $f := SortBy (AllCommands $) "FunctionName"}} {{if and (Macro "IsDriverFunction" $f) (eq (Macro "Vtbl" $f) "Global")}} {"{{$f.Name}}", reinterpret_cast(§ static_cast<{{Macro "FunctionPtrName" $f}}>(§ {{Macro "BaseName" $f}}))}, {{end}} {{end}} // clang-format on »}; ¶ const NameProc kInstanceProcs[] = {« // clang-format off {{range $f := SortBy (AllCommands $) "FunctionName"}} {{if (Macro "IsDriverFunction" $f)}} {"{{$f.Name}}", reinterpret_cast(§ static_cast<{{Macro "FunctionPtrName" $f}}>(§ {{Macro "BaseName" $f}}))}, {{end}} {{end}} // clang-format on »}; ¶ } // namespace ¶ namespace null_driver { ¶ PFN_vkVoidFunction GetGlobalProcAddr(const char* name) { return Lookup(name, kGlobalProcs); } ¶ PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {« PFN_vkVoidFunction pfn; if ((pfn = Lookup(name, kInstanceProcs))) return pfn; if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0) return reinterpret_cast(static_cast(GetSwapchainGrallocUsageANDROID)); if (strcmp(name, "vkAcquireImageANDROID") == 0) return reinterpret_cast(static_cast(AcquireImageANDROID)); if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0) return reinterpret_cast(static_cast(QueueSignalReleaseImageANDROID)); return nullptr; »} ¶ } // namespace null_driver ¶ {{end}} {{/* ------------------------------------------------------------------------------- Emits a function name without the "vk" prefix. ------------------------------------------------------------------------------- */}} {{define "BaseName"}} {{AssertType $ "Function"}} {{TrimPrefix "vk" $.Name}} {{end}} {{/* ------------------------------------------------------------------------------ Emits 'true' if the API function is implemented by the driver. ------------------------------------------------------------------------------ */}} {{define "IsDriverFunction"}} {{AssertType $ "Function"}} {{if not (GetAnnotation $ "pfn")}} {{$ext := GetAnnotation $ "extension"}} {{if $ext}} {{Macro "IsDriverExtension" $ext}} {{else}} true {{end}} {{end}} {{end}} {{/* ------------------------------------------------------------------------------ Reports whether an extension is implemented by the driver. ------------------------------------------------------------------------------ */}} {{define "IsDriverExtension"}} {{$ext := index $.Arguments 0}} {{ if eq $ext "VK_ANDROID_native_buffer"}}true {{else if eq $ext "VK_EXT_debug_report"}}true {{end}} {{end}} vulkan/nulldrv/null_driver_gen.cpp0100644 0000000 0000000 00000050730 13077405420 016464 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // WARNING: This file is generated. See ../README.md for instructions. #include "null_driver_gen.h" #include using namespace null_driver; namespace { struct NameProc { const char* name; PFN_vkVoidFunction proc; }; PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) { const auto& entry = std::lower_bound( begin, end, name, [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; }); if (entry == end || strcmp(entry->name, name) != 0) return nullptr; return entry->proc; } template PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) { return Lookup(name, procs, procs + N); } const NameProc kGlobalProcs[] = { // clang-format off {"vkCreateInstance", reinterpret_cast(static_cast(CreateInstance))}, {"vkEnumerateInstanceExtensionProperties", reinterpret_cast(static_cast(EnumerateInstanceExtensionProperties))}, {"vkEnumerateInstanceLayerProperties", reinterpret_cast(static_cast(EnumerateInstanceLayerProperties))}, // clang-format on }; const NameProc kInstanceProcs[] = { // clang-format off {"vkAllocateCommandBuffers", reinterpret_cast(static_cast(AllocateCommandBuffers))}, {"vkAllocateDescriptorSets", reinterpret_cast(static_cast(AllocateDescriptorSets))}, {"vkAllocateMemory", reinterpret_cast(static_cast(AllocateMemory))}, {"vkBeginCommandBuffer", reinterpret_cast(static_cast(BeginCommandBuffer))}, {"vkBindBufferMemory", reinterpret_cast(static_cast(BindBufferMemory))}, {"vkBindImageMemory", reinterpret_cast(static_cast(BindImageMemory))}, {"vkCmdBeginQuery", reinterpret_cast(static_cast(CmdBeginQuery))}, {"vkCmdBeginRenderPass", reinterpret_cast(static_cast(CmdBeginRenderPass))}, {"vkCmdBindDescriptorSets", reinterpret_cast(static_cast(CmdBindDescriptorSets))}, {"vkCmdBindIndexBuffer", reinterpret_cast(static_cast(CmdBindIndexBuffer))}, {"vkCmdBindPipeline", reinterpret_cast(static_cast(CmdBindPipeline))}, {"vkCmdBindVertexBuffers", reinterpret_cast(static_cast(CmdBindVertexBuffers))}, {"vkCmdBlitImage", reinterpret_cast(static_cast(CmdBlitImage))}, {"vkCmdClearAttachments", reinterpret_cast(static_cast(CmdClearAttachments))}, {"vkCmdClearColorImage", reinterpret_cast(static_cast(CmdClearColorImage))}, {"vkCmdClearDepthStencilImage", reinterpret_cast(static_cast(CmdClearDepthStencilImage))}, {"vkCmdCopyBuffer", reinterpret_cast(static_cast(CmdCopyBuffer))}, {"vkCmdCopyBufferToImage", reinterpret_cast(static_cast(CmdCopyBufferToImage))}, {"vkCmdCopyImage", reinterpret_cast(static_cast(CmdCopyImage))}, {"vkCmdCopyImageToBuffer", reinterpret_cast(static_cast(CmdCopyImageToBuffer))}, {"vkCmdCopyQueryPoolResults", reinterpret_cast(static_cast(CmdCopyQueryPoolResults))}, {"vkCmdDispatch", reinterpret_cast(static_cast(CmdDispatch))}, {"vkCmdDispatchIndirect", reinterpret_cast(static_cast(CmdDispatchIndirect))}, {"vkCmdDraw", reinterpret_cast(static_cast(CmdDraw))}, {"vkCmdDrawIndexed", reinterpret_cast(static_cast(CmdDrawIndexed))}, {"vkCmdDrawIndexedIndirect", reinterpret_cast(static_cast(CmdDrawIndexedIndirect))}, {"vkCmdDrawIndirect", reinterpret_cast(static_cast(CmdDrawIndirect))}, {"vkCmdEndQuery", reinterpret_cast(static_cast(CmdEndQuery))}, {"vkCmdEndRenderPass", reinterpret_cast(static_cast(CmdEndRenderPass))}, {"vkCmdExecuteCommands", reinterpret_cast(static_cast(CmdExecuteCommands))}, {"vkCmdFillBuffer", reinterpret_cast(static_cast(CmdFillBuffer))}, {"vkCmdNextSubpass", reinterpret_cast(static_cast(CmdNextSubpass))}, {"vkCmdPipelineBarrier", reinterpret_cast(static_cast(CmdPipelineBarrier))}, {"vkCmdPushConstants", reinterpret_cast(static_cast(CmdPushConstants))}, {"vkCmdResetEvent", reinterpret_cast(static_cast(CmdResetEvent))}, {"vkCmdResetQueryPool", reinterpret_cast(static_cast(CmdResetQueryPool))}, {"vkCmdResolveImage", reinterpret_cast(static_cast(CmdResolveImage))}, {"vkCmdSetBlendConstants", reinterpret_cast(static_cast(CmdSetBlendConstants))}, {"vkCmdSetDepthBias", reinterpret_cast(static_cast(CmdSetDepthBias))}, {"vkCmdSetDepthBounds", reinterpret_cast(static_cast(CmdSetDepthBounds))}, {"vkCmdSetEvent", reinterpret_cast(static_cast(CmdSetEvent))}, {"vkCmdSetLineWidth", reinterpret_cast(static_cast(CmdSetLineWidth))}, {"vkCmdSetScissor", reinterpret_cast(static_cast(CmdSetScissor))}, {"vkCmdSetStencilCompareMask", reinterpret_cast(static_cast(CmdSetStencilCompareMask))}, {"vkCmdSetStencilReference", reinterpret_cast(static_cast(CmdSetStencilReference))}, {"vkCmdSetStencilWriteMask", reinterpret_cast(static_cast(CmdSetStencilWriteMask))}, {"vkCmdSetViewport", reinterpret_cast(static_cast(CmdSetViewport))}, {"vkCmdUpdateBuffer", reinterpret_cast(static_cast(CmdUpdateBuffer))}, {"vkCmdWaitEvents", reinterpret_cast(static_cast(CmdWaitEvents))}, {"vkCmdWriteTimestamp", reinterpret_cast(static_cast(CmdWriteTimestamp))}, {"vkCreateBuffer", reinterpret_cast(static_cast(CreateBuffer))}, {"vkCreateBufferView", reinterpret_cast(static_cast(CreateBufferView))}, {"vkCreateCommandPool", reinterpret_cast(static_cast(CreateCommandPool))}, {"vkCreateComputePipelines", reinterpret_cast(static_cast(CreateComputePipelines))}, {"vkCreateDebugReportCallbackEXT", reinterpret_cast(static_cast(CreateDebugReportCallbackEXT))}, {"vkCreateDescriptorPool", reinterpret_cast(static_cast(CreateDescriptorPool))}, {"vkCreateDescriptorSetLayout", reinterpret_cast(static_cast(CreateDescriptorSetLayout))}, {"vkCreateDevice", reinterpret_cast(static_cast(CreateDevice))}, {"vkCreateEvent", reinterpret_cast(static_cast(CreateEvent))}, {"vkCreateFence", reinterpret_cast(static_cast(CreateFence))}, {"vkCreateFramebuffer", reinterpret_cast(static_cast(CreateFramebuffer))}, {"vkCreateGraphicsPipelines", reinterpret_cast(static_cast(CreateGraphicsPipelines))}, {"vkCreateImage", reinterpret_cast(static_cast(CreateImage))}, {"vkCreateImageView", reinterpret_cast(static_cast(CreateImageView))}, {"vkCreateInstance", reinterpret_cast(static_cast(CreateInstance))}, {"vkCreatePipelineCache", reinterpret_cast(static_cast(CreatePipelineCache))}, {"vkCreatePipelineLayout", reinterpret_cast(static_cast(CreatePipelineLayout))}, {"vkCreateQueryPool", reinterpret_cast(static_cast(CreateQueryPool))}, {"vkCreateRenderPass", reinterpret_cast(static_cast(CreateRenderPass))}, {"vkCreateSampler", reinterpret_cast(static_cast(CreateSampler))}, {"vkCreateSemaphore", reinterpret_cast(static_cast(CreateSemaphore))}, {"vkCreateShaderModule", reinterpret_cast(static_cast(CreateShaderModule))}, {"vkDebugReportMessageEXT", reinterpret_cast(static_cast(DebugReportMessageEXT))}, {"vkDestroyBuffer", reinterpret_cast(static_cast(DestroyBuffer))}, {"vkDestroyBufferView", reinterpret_cast(static_cast(DestroyBufferView))}, {"vkDestroyCommandPool", reinterpret_cast(static_cast(DestroyCommandPool))}, {"vkDestroyDebugReportCallbackEXT", reinterpret_cast(static_cast(DestroyDebugReportCallbackEXT))}, {"vkDestroyDescriptorPool", reinterpret_cast(static_cast(DestroyDescriptorPool))}, {"vkDestroyDescriptorSetLayout", reinterpret_cast(static_cast(DestroyDescriptorSetLayout))}, {"vkDestroyDevice", reinterpret_cast(static_cast(DestroyDevice))}, {"vkDestroyEvent", reinterpret_cast(static_cast(DestroyEvent))}, {"vkDestroyFence", reinterpret_cast(static_cast(DestroyFence))}, {"vkDestroyFramebuffer", reinterpret_cast(static_cast(DestroyFramebuffer))}, {"vkDestroyImage", reinterpret_cast(static_cast(DestroyImage))}, {"vkDestroyImageView", reinterpret_cast(static_cast(DestroyImageView))}, {"vkDestroyInstance", reinterpret_cast(static_cast(DestroyInstance))}, {"vkDestroyPipeline", reinterpret_cast(static_cast(DestroyPipeline))}, {"vkDestroyPipelineCache", reinterpret_cast(static_cast(DestroyPipelineCache))}, {"vkDestroyPipelineLayout", reinterpret_cast(static_cast(DestroyPipelineLayout))}, {"vkDestroyQueryPool", reinterpret_cast(static_cast(DestroyQueryPool))}, {"vkDestroyRenderPass", reinterpret_cast(static_cast(DestroyRenderPass))}, {"vkDestroySampler", reinterpret_cast(static_cast(DestroySampler))}, {"vkDestroySemaphore", reinterpret_cast(static_cast(DestroySemaphore))}, {"vkDestroyShaderModule", reinterpret_cast(static_cast(DestroyShaderModule))}, {"vkDeviceWaitIdle", reinterpret_cast(static_cast(DeviceWaitIdle))}, {"vkEndCommandBuffer", reinterpret_cast(static_cast(EndCommandBuffer))}, {"vkEnumerateDeviceExtensionProperties", reinterpret_cast(static_cast(EnumerateDeviceExtensionProperties))}, {"vkEnumerateDeviceLayerProperties", reinterpret_cast(static_cast(EnumerateDeviceLayerProperties))}, {"vkEnumerateInstanceExtensionProperties", reinterpret_cast(static_cast(EnumerateInstanceExtensionProperties))}, {"vkEnumerateInstanceLayerProperties", reinterpret_cast(static_cast(EnumerateInstanceLayerProperties))}, {"vkEnumeratePhysicalDevices", reinterpret_cast(static_cast(EnumeratePhysicalDevices))}, {"vkFlushMappedMemoryRanges", reinterpret_cast(static_cast(FlushMappedMemoryRanges))}, {"vkFreeCommandBuffers", reinterpret_cast(static_cast(FreeCommandBuffers))}, {"vkFreeDescriptorSets", reinterpret_cast(static_cast(FreeDescriptorSets))}, {"vkFreeMemory", reinterpret_cast(static_cast(FreeMemory))}, {"vkGetBufferMemoryRequirements", reinterpret_cast(static_cast(GetBufferMemoryRequirements))}, {"vkGetDeviceMemoryCommitment", reinterpret_cast(static_cast(GetDeviceMemoryCommitment))}, {"vkGetDeviceProcAddr", reinterpret_cast(static_cast(GetDeviceProcAddr))}, {"vkGetDeviceQueue", reinterpret_cast(static_cast(GetDeviceQueue))}, {"vkGetEventStatus", reinterpret_cast(static_cast(GetEventStatus))}, {"vkGetFenceStatus", reinterpret_cast(static_cast(GetFenceStatus))}, {"vkGetImageMemoryRequirements", reinterpret_cast(static_cast(GetImageMemoryRequirements))}, {"vkGetImageSparseMemoryRequirements", reinterpret_cast(static_cast(GetImageSparseMemoryRequirements))}, {"vkGetImageSubresourceLayout", reinterpret_cast(static_cast(GetImageSubresourceLayout))}, {"vkGetInstanceProcAddr", reinterpret_cast(static_cast(GetInstanceProcAddr))}, {"vkGetPhysicalDeviceFeatures", reinterpret_cast(static_cast(GetPhysicalDeviceFeatures))}, {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast(static_cast(GetPhysicalDeviceFormatProperties))}, {"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast(static_cast(GetPhysicalDeviceImageFormatProperties))}, {"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast(static_cast(GetPhysicalDeviceMemoryProperties))}, {"vkGetPhysicalDeviceProperties", reinterpret_cast(static_cast(GetPhysicalDeviceProperties))}, {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast(static_cast(GetPhysicalDeviceQueueFamilyProperties))}, {"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast(static_cast(GetPhysicalDeviceSparseImageFormatProperties))}, {"vkGetPipelineCacheData", reinterpret_cast(static_cast(GetPipelineCacheData))}, {"vkGetQueryPoolResults", reinterpret_cast(static_cast(GetQueryPoolResults))}, {"vkGetRenderAreaGranularity", reinterpret_cast(static_cast(GetRenderAreaGranularity))}, {"vkInvalidateMappedMemoryRanges", reinterpret_cast(static_cast(InvalidateMappedMemoryRanges))}, {"vkMapMemory", reinterpret_cast(static_cast(MapMemory))}, {"vkMergePipelineCaches", reinterpret_cast(static_cast(MergePipelineCaches))}, {"vkQueueBindSparse", reinterpret_cast(static_cast(QueueBindSparse))}, {"vkQueueSubmit", reinterpret_cast(static_cast(QueueSubmit))}, {"vkQueueWaitIdle", reinterpret_cast(static_cast(QueueWaitIdle))}, {"vkResetCommandBuffer", reinterpret_cast(static_cast(ResetCommandBuffer))}, {"vkResetCommandPool", reinterpret_cast(static_cast(ResetCommandPool))}, {"vkResetDescriptorPool", reinterpret_cast(static_cast(ResetDescriptorPool))}, {"vkResetEvent", reinterpret_cast(static_cast(ResetEvent))}, {"vkResetFences", reinterpret_cast(static_cast(ResetFences))}, {"vkSetEvent", reinterpret_cast(static_cast(SetEvent))}, {"vkUnmapMemory", reinterpret_cast(static_cast(UnmapMemory))}, {"vkUpdateDescriptorSets", reinterpret_cast(static_cast(UpdateDescriptorSets))}, {"vkWaitForFences", reinterpret_cast(static_cast(WaitForFences))}, // clang-format on }; } // namespace namespace null_driver { PFN_vkVoidFunction GetGlobalProcAddr(const char* name) { return Lookup(name, kGlobalProcs); } PFN_vkVoidFunction GetInstanceProcAddr(const char* name) { PFN_vkVoidFunction pfn; if ((pfn = Lookup(name, kInstanceProcs))) return pfn; if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0) return reinterpret_cast( static_cast( GetSwapchainGrallocUsageANDROID)); if (strcmp(name, "vkAcquireImageANDROID") == 0) return reinterpret_cast( static_cast(AcquireImageANDROID)); if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0) return reinterpret_cast( static_cast( QueueSignalReleaseImageANDROID)); return nullptr; } } // namespace null_driver vulkan/nulldrv/null_driver_gen.h0100644 0000000 0000000 00000052231 13077405420 016127 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // WARNING: This file is generated. See ../README.md for instructions. #ifndef NULLDRV_NULL_DRIVER_H #define NULLDRV_NULL_DRIVER_H 1 #include #include namespace null_driver { PFN_vkVoidFunction GetGlobalProcAddr(const char* name); PFN_vkVoidFunction GetInstanceProcAddr(const char* name); // clang-format off VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName); VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName); VKAPI_ATTR void GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); VKAPI_ATTR void GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); VKAPI_ATTR void GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); VKAPI_ATTR void GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); VKAPI_ATTR VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); VKAPI_ATTR VkResult QueueWaitIdle(VkQueue queue); VKAPI_ATTR VkResult DeviceWaitIdle(VkDevice device); VKAPI_ATTR VkResult AllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); VKAPI_ATTR void FreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult MapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); VKAPI_ATTR void UnmapMemory(VkDevice device, VkDeviceMemory memory); VKAPI_ATTR VkResult FlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR VkResult InvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); VKAPI_ATTR void GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); VKAPI_ATTR void GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR VkResult BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR void GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); VKAPI_ATTR VkResult BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); VKAPI_ATTR void GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); VKAPI_ATTR VkResult QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); VKAPI_ATTR VkResult CreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); VKAPI_ATTR void DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences); VKAPI_ATTR VkResult GetFenceStatus(VkDevice device, VkFence fence); VKAPI_ATTR VkResult WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); VKAPI_ATTR VkResult CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); VKAPI_ATTR void DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); VKAPI_ATTR void DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetEventStatus(VkDevice device, VkEvent event); VKAPI_ATTR VkResult SetEvent(VkDevice device, VkEvent event); VKAPI_ATTR VkResult ResetEvent(VkDevice device, VkEvent event); VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); VKAPI_ATTR void DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); VKAPI_ATTR void DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); VKAPI_ATTR VkResult CreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); VKAPI_ATTR void DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); VKAPI_ATTR void DestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); VKAPI_ATTR void DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); VKAPI_ATTR VkResult MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); VKAPI_ATTR VkResult CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR VkResult CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); VKAPI_ATTR void DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); VKAPI_ATTR void DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); VKAPI_ATTR void DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); VKAPI_ATTR void DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); VKAPI_ATTR void DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); VKAPI_ATTR VkResult AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); VKAPI_ATTR VkResult FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); VKAPI_ATTR void UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); VKAPI_ATTR VkResult CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); VKAPI_ATTR void DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); VKAPI_ATTR void DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void GetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); VKAPI_ATTR VkResult CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); VKAPI_ATTR void DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); VKAPI_ATTR void FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); VKAPI_ATTR VkResult BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); VKAPI_ATTR VkResult EndCommandBuffer(VkCommandBuffer commandBuffer); VKAPI_ATTR VkResult ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); VKAPI_ATTR void CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); VKAPI_ATTR void CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); VKAPI_ATTR void CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); VKAPI_ATTR void CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth); VKAPI_ATTR void CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); VKAPI_ATTR void CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]); VKAPI_ATTR void CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); VKAPI_ATTR void CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); VKAPI_ATTR void CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); VKAPI_ATTR void CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); VKAPI_ATTR void CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); VKAPI_ATTR void CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); VKAPI_ATTR void CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); VKAPI_ATTR void CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); VKAPI_ATTR void CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); VKAPI_ATTR void CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z); VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); VKAPI_ATTR void CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); VKAPI_ATTR void CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData); VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); VKAPI_ATTR void CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); VKAPI_ATTR void CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); VKAPI_ATTR void CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); VKAPI_ATTR void CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); VKAPI_ATTR void CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); VKAPI_ATTR void CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); VKAPI_ATTR void CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); VKAPI_ATTR void CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); VKAPI_ATTR void CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); // clang-format on } // namespace null_driver #endif // NULLDRV_NULL_DRIVER_H vulkan/tools/0040755 0000000 0000000 00000000000 13077405420 012252 5ustar000000000 0000000 vulkan/tools/Android.mk0100644 0000000 0000000 00000002307 13077405420 014162 0ustar000000000 0000000 # Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_CFLAGS := -std=c99 -fvisibility=hidden -fstrict-aliasing LOCAL_CFLAGS += -DLOG_TAG=\"vkinfo\" LOCAL_CFLAGS += -Weverything -Werror -Wno-padded -Wno-undef -Wno-switch-enum LOCAL_CPPFLAGS := -std=c++1y \ -Wno-c++98-compat-pedantic \ -Wno-c99-extensions \ -Wno-old-style-cast LOCAL_C_INCLUDES := \ frameworks/native/vulkan/include LOCAL_SRC_FILES := vkinfo.cpp LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SHARED_LIBRARIES := libvulkan liblog LOCAL_MODULE := vkinfo LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) vulkan/tools/vkinfo.cpp0100644 0000000 0000000 00000073734 13077405420 014265 0ustar000000000 0000000 /* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #define LOG_TAG "vkinfo" #include namespace { struct Options { bool layer_description; bool layer_extensions; bool unsupported_features; bool validate; }; struct GpuInfo { VkPhysicalDeviceProperties properties; VkPhysicalDeviceMemoryProperties memory; VkPhysicalDeviceFeatures features; std::vector queue_families; std::vector extensions; std::vector layers; std::vector> layer_extensions; }; struct VulkanInfo { std::vector extensions; std::vector layers; std::vector> layer_extensions; std::vector gpus; }; // ---------------------------------------------------------------------------- [[noreturn]] void die(const char* proc, VkResult result) { const char* result_str; switch (result) { // clang-format off case VK_SUCCESS: result_str = "VK_SUCCESS"; break; case VK_NOT_READY: result_str = "VK_NOT_READY"; break; case VK_TIMEOUT: result_str = "VK_TIMEOUT"; break; case VK_EVENT_SET: result_str = "VK_EVENT_SET"; break; case VK_EVENT_RESET: result_str = "VK_EVENT_RESET"; break; case VK_INCOMPLETE: result_str = "VK_INCOMPLETE"; break; case VK_ERROR_OUT_OF_HOST_MEMORY: result_str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break; case VK_ERROR_OUT_OF_DEVICE_MEMORY: result_str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break; case VK_ERROR_INITIALIZATION_FAILED: result_str = "VK_ERROR_INITIALIZATION_FAILED"; break; case VK_ERROR_DEVICE_LOST: result_str = "VK_ERROR_DEVICE_LOST"; break; case VK_ERROR_MEMORY_MAP_FAILED: result_str = "VK_ERROR_MEMORY_MAP_FAILED"; break; case VK_ERROR_LAYER_NOT_PRESENT: result_str = "VK_ERROR_LAYER_NOT_PRESENT"; break; case VK_ERROR_EXTENSION_NOT_PRESENT: result_str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break; case VK_ERROR_INCOMPATIBLE_DRIVER: result_str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break; default: result_str = ""; break; // clang-format on } fprintf(stderr, "%s failed: %s (%d)\n", proc, result_str, result); exit(1); } bool HasExtension(const std::vector& extensions, const char* name) { return std::find_if(extensions.cbegin(), extensions.cend(), [=](const VkExtensionProperties& prop) { return strcmp(prop.extensionName, name) == 0; }) != extensions.end(); } void EnumerateInstanceExtensions( const char* layer_name, std::vector* extensions) { VkResult result; uint32_t count; result = vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr); if (result != VK_SUCCESS) die("vkEnumerateInstanceExtensionProperties (count)", result); do { extensions->resize(count); result = vkEnumerateInstanceExtensionProperties(layer_name, &count, extensions->data()); } while (result == VK_INCOMPLETE); if (result != VK_SUCCESS) die("vkEnumerateInstanceExtensionProperties (data)", result); } void EnumerateDeviceExtensions(VkPhysicalDevice gpu, const char* layer_name, std::vector* extensions) { VkResult result; uint32_t count; result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, nullptr); if (result != VK_SUCCESS) die("vkEnumerateDeviceExtensionProperties (count)", result); do { extensions->resize(count); result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, extensions->data()); } while (result == VK_INCOMPLETE); if (result != VK_SUCCESS) die("vkEnumerateDeviceExtensionProperties (data)", result); } void GatherGpuInfo(VkPhysicalDevice gpu, const Options &options, GpuInfo& info) { VkResult result; uint32_t count; vkGetPhysicalDeviceProperties(gpu, &info.properties); vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory); vkGetPhysicalDeviceFeatures(gpu, &info.features); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr); info.queue_families.resize(count); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, info.queue_families.data()); result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr); if (result != VK_SUCCESS) die("vkEnumerateDeviceLayerProperties (count)", result); do { info.layers.resize(count); result = vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data()); } while (result == VK_INCOMPLETE); if (result != VK_SUCCESS) die("vkEnumerateDeviceLayerProperties (data)", result); info.layer_extensions.resize(info.layers.size()); EnumerateDeviceExtensions(gpu, nullptr, &info.extensions); for (size_t i = 0; i < info.layers.size(); i++) { EnumerateDeviceExtensions(gpu, info.layers[i].layerName, &info.layer_extensions[i]); } const std::array kDesiredExtensions = { {VK_KHR_SWAPCHAIN_EXTENSION_NAME}, }; const char* extensions[kDesiredExtensions.size()]; uint32_t num_extensions = 0; for (const auto& desired_ext : kDesiredExtensions) { bool available = HasExtension(info.extensions, desired_ext); if (options.validate) { for (size_t i = 0; !available && i < info.layer_extensions.size(); i++) available = HasExtension(info.layer_extensions[i], desired_ext); } if (available) extensions[num_extensions++] = desired_ext; } VkDevice device; float queue_priorities[] = {0.0}; const VkDeviceQueueCreateInfo queue_create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = 0, .queueCount = 1, queue_priorities }; // clang-format off const char *kValidationLayers[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" }; // clang-format on uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*); const VkDeviceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create_info, .enabledExtensionCount = num_extensions, .ppEnabledExtensionNames = extensions, .enabledLayerCount = (options.validate) ? num_layers : 0, .ppEnabledLayerNames = kValidationLayers, .pEnabledFeatures = &info.features, }; result = vkCreateDevice(gpu, &create_info, nullptr, &device); if (result != VK_SUCCESS) die("vkCreateDevice", result); vkDestroyDevice(device, nullptr); } void GatherInfo(VulkanInfo* info, const Options& options) { VkResult result; uint32_t count; result = vkEnumerateInstanceLayerProperties(&count, nullptr); if (result != VK_SUCCESS) die("vkEnumerateInstanceLayerProperties (count)", result); do { info->layers.resize(count); result = vkEnumerateInstanceLayerProperties(&count, info->layers.data()); } while (result == VK_INCOMPLETE); if (result != VK_SUCCESS) die("vkEnumerateInstanceLayerProperties (data)", result); info->layer_extensions.resize(info->layers.size()); EnumerateInstanceExtensions(nullptr, &info->extensions); for (size_t i = 0; i < info->layers.size(); i++) { EnumerateInstanceExtensions(info->layers[i].layerName, &info->layer_extensions[i]); } const char* kDesiredExtensions[] = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, }; const char* extensions[sizeof(kDesiredExtensions) / sizeof(kDesiredExtensions[0])]; uint32_t num_extensions = 0; for (const auto& desired_ext : kDesiredExtensions) { bool available = HasExtension(info->extensions, desired_ext); if (options.validate) { for (size_t i = 0; !available && i < info->layer_extensions.size(); i++) available = HasExtension(info->layer_extensions[i], desired_ext); } if (available) extensions[num_extensions++] = desired_ext; } // clang-format off const char *kValidationLayers[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" }; // clang-format on uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*); const VkApplicationInfo application_info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "vkinfo", .applicationVersion = 0, .pEngineName = "vkinfo", .engineVersion = 0, .apiVersion = VK_API_VERSION_1_0, }; const VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &application_info, .enabledExtensionCount = num_extensions, .ppEnabledExtensionNames = extensions, .enabledLayerCount = (options.validate) ? num_layers : 0, .ppEnabledLayerNames = kValidationLayers, }; VkInstance instance; result = vkCreateInstance(&create_info, nullptr, &instance); if (result != VK_SUCCESS) die("vkCreateInstance", result); uint32_t num_gpus; result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr); if (result != VK_SUCCESS) die("vkEnumeratePhysicalDevices (count)", result); std::vector gpus(num_gpus, VK_NULL_HANDLE); do { gpus.resize(num_gpus, VK_NULL_HANDLE); result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data()); } while (result == VK_INCOMPLETE); if (result != VK_SUCCESS) die("vkEnumeratePhysicalDevices (data)", result); info->gpus.resize(num_gpus); for (size_t i = 0; i < gpus.size(); i++) GatherGpuInfo(gpus[i], options, info->gpus.at(i)); vkDestroyInstance(instance, nullptr); } // ---------------------------------------------------------------------------- const size_t kMaxIndent = 8; const size_t kIndentSize = 3; std::array kIndent; const char* Indent(size_t n) { static bool initialized = false; if (!initialized) { kIndent.fill(' '); kIndent.back() = '\0'; initialized = true; } return kIndent.data() + (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1)); } const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) { switch (type) { case VK_PHYSICAL_DEVICE_TYPE_OTHER: return "OTHER"; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "INTEGRATED_GPU"; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "DISCRETE_GPU"; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "VIRTUAL_GPU"; case VK_PHYSICAL_DEVICE_TYPE_CPU: return "CPU"; default: return ""; } } void PrintExtensions(const std::vector& extensions, const Options& /*options*/, size_t indent) { for (const auto& e : extensions) printf("%s%s (v%u)\n", Indent(indent), e.extensionName, e.specVersion); } void PrintLayers( const std::vector& layers, const std::vector> extensions, const Options& options, size_t indent) { for (size_t i = 0; i < layers.size(); i++) { printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName, VK_VERSION_MAJOR(layers[i].specVersion), VK_VERSION_MINOR(layers[i].specVersion), VK_VERSION_PATCH(layers[i].specVersion), layers[i].implementationVersion); if (options.layer_description) printf("%s%s\n", Indent(indent + 1), layers[i].description); if (options.layer_extensions && !extensions[i].empty()) { if (!extensions[i].empty()) { printf("%sExtensions [%zu]:\n", Indent(indent + 1), extensions[i].size()); PrintExtensions(extensions[i], options, indent + 2); } } } } void PrintAllFeatures(const char* indent, const VkPhysicalDeviceFeatures& features) { // clang-format off printf("%srobustBufferAccess: %s\n", indent, features.robustBufferAccess ? "YES" : "NO"); printf("%sfullDrawIndexUint32: %s\n", indent, features.fullDrawIndexUint32 ? "YES" : "NO"); printf("%simageCubeArray: %s\n", indent, features.imageCubeArray ? "YES" : "NO"); printf("%sindependentBlend: %s\n", indent, features.independentBlend ? "YES" : "NO"); printf("%sgeometryShader: %s\n", indent, features.geometryShader ? "YES" : "NO"); printf("%stessellationShader: %s\n", indent, features.tessellationShader ? "YES" : "NO"); printf("%ssampleRateShading: %s\n", indent, features.sampleRateShading ? "YES" : "NO"); printf("%sdualSrcBlend: %s\n", indent, features.dualSrcBlend ? "YES" : "NO"); printf("%slogicOp: %s\n", indent, features.logicOp ? "YES" : "NO"); printf("%smultiDrawIndirect: %s\n", indent, features.multiDrawIndirect ? "YES" : "NO"); printf("%sdrawIndirectFirstInstance: %s\n", indent, features.drawIndirectFirstInstance ? "YES" : "NO"); printf("%sdepthClamp: %s\n", indent, features.depthClamp ? "YES" : "NO"); printf("%sdepthBiasClamp: %s\n", indent, features.depthBiasClamp ? "YES" : "NO"); printf("%sfillModeNonSolid: %s\n", indent, features.fillModeNonSolid ? "YES" : "NO"); printf("%sdepthBounds: %s\n", indent, features.depthBounds ? "YES" : "NO"); printf("%swideLines: %s\n", indent, features.wideLines ? "YES" : "NO"); printf("%slargePoints: %s\n", indent, features.largePoints ? "YES" : "NO"); printf("%salphaToOne: %s\n", indent, features.alphaToOne ? "YES" : "NO"); printf("%smultiViewport: %s\n", indent, features.multiViewport ? "YES" : "NO"); printf("%ssamplerAnisotropy: %s\n", indent, features.samplerAnisotropy ? "YES" : "NO"); printf("%stextureCompressionETC2: %s\n", indent, features.textureCompressionETC2 ? "YES" : "NO"); printf("%stextureCompressionASTC_LDR: %s\n", indent, features.textureCompressionASTC_LDR ? "YES" : "NO"); printf("%stextureCompressionBC: %s\n", indent, features.textureCompressionBC ? "YES" : "NO"); printf("%socclusionQueryPrecise: %s\n", indent, features.occlusionQueryPrecise ? "YES" : "NO"); printf("%spipelineStatisticsQuery: %s\n", indent, features.pipelineStatisticsQuery ? "YES" : "NO"); printf("%svertexPipelineStoresAndAtomics: %s\n", indent, features.vertexPipelineStoresAndAtomics ? "YES" : "NO"); printf("%sfragmentStoresAndAtomics: %s\n", indent, features.fragmentStoresAndAtomics ? "YES" : "NO"); printf("%sshaderTessellationAndGeometryPointSize: %s\n", indent, features.shaderTessellationAndGeometryPointSize ? "YES" : "NO"); printf("%sshaderImageGatherExtended: %s\n", indent, features.shaderImageGatherExtended ? "YES" : "NO"); printf("%sshaderStorageImageExtendedFormats: %s\n", indent, features.shaderStorageImageExtendedFormats ? "YES" : "NO"); printf("%sshaderStorageImageMultisample: %s\n", indent, features.shaderStorageImageMultisample ? "YES" : "NO"); printf("%sshaderStorageImageReadWithoutFormat: %s\n", indent, features.shaderStorageImageReadWithoutFormat ? "YES" : "NO"); printf("%sshaderStorageImageWriteWithoutFormat: %s\n", indent, features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO"); printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", indent, features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO"); printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", indent, features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO"); printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", indent, features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO"); printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", indent, features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO"); printf("%sshaderClipDistance: %s\n", indent, features.shaderClipDistance ? "YES" : "NO"); printf("%sshaderCullDistance: %s\n", indent, features.shaderCullDistance ? "YES" : "NO"); printf("%sshaderFloat64: %s\n", indent, features.shaderFloat64 ? "YES" : "NO"); printf("%sshaderInt64: %s\n", indent, features.shaderInt64 ? "YES" : "NO"); printf("%sshaderInt16: %s\n", indent, features.shaderInt16 ? "YES" : "NO"); printf("%sshaderResourceResidency: %s\n", indent, features.shaderResourceResidency ? "YES" : "NO"); printf("%sshaderResourceMinLod: %s\n", indent, features.shaderResourceMinLod ? "YES" : "NO"); printf("%ssparseBinding: %s\n", indent, features.sparseBinding ? "YES" : "NO"); printf("%ssparseResidencyBuffer: %s\n", indent, features.sparseResidencyBuffer ? "YES" : "NO"); printf("%ssparseResidencyImage2D: %s\n", indent, features.sparseResidencyImage2D ? "YES" : "NO"); printf("%ssparseResidencyImage3D: %s\n", indent, features.sparseResidencyImage3D ? "YES" : "NO"); printf("%ssparseResidency2Samples: %s\n", indent, features.sparseResidency2Samples ? "YES" : "NO"); printf("%ssparseResidency4Samples: %s\n", indent, features.sparseResidency4Samples ? "YES" : "NO"); printf("%ssparseResidency8Samples: %s\n", indent, features.sparseResidency8Samples ? "YES" : "NO"); printf("%ssparseResidency16Samples: %s\n", indent, features.sparseResidency16Samples ? "YES" : "NO"); printf("%ssparseResidencyAliased: %s\n", indent, features.sparseResidencyAliased ? "YES" : "NO"); printf("%svariableMultisampleRate: %s\n", indent, features.variableMultisampleRate ? "YES" : "NO"); printf("%sinheritedQueries: %s\n", indent, features.inheritedQueries ? "YES" : "NO"); // clang-format on } void PrintSupportedFeatures(const char* indent, const VkPhysicalDeviceFeatures& features) { // clang-format off if (features.robustBufferAccess) printf("%srobustBufferAccess\n", indent); if (features.fullDrawIndexUint32) printf("%sfullDrawIndexUint32\n", indent); if (features.imageCubeArray) printf("%simageCubeArray\n", indent); if (features.independentBlend) printf("%sindependentBlend\n", indent); if (features.geometryShader) printf("%sgeometryShader\n", indent); if (features.tessellationShader) printf("%stessellationShader\n", indent); if (features.sampleRateShading) printf("%ssampleRateShading\n", indent); if (features.dualSrcBlend) printf("%sdualSrcBlend\n", indent); if (features.logicOp) printf("%slogicOp\n", indent); if (features.multiDrawIndirect) printf("%smultiDrawIndirect\n", indent); if (features.drawIndirectFirstInstance) printf("%sdrawIndirectFirstInstance\n", indent); if (features.depthClamp) printf("%sdepthClamp\n", indent); if (features.depthBiasClamp) printf("%sdepthBiasClamp\n", indent); if (features.fillModeNonSolid) printf("%sfillModeNonSolid\n", indent); if (features.depthBounds) printf("%sdepthBounds\n", indent); if (features.wideLines) printf("%swideLines\n", indent); if (features.largePoints) printf("%slargePoints\n", indent); if (features.alphaToOne) printf("%salphaToOne\n", indent); if (features.multiViewport) printf("%smultiViewport\n", indent); if (features.samplerAnisotropy) printf("%ssamplerAnisotropy\n", indent); if (features.textureCompressionETC2) printf("%stextureCompressionETC2\n", indent); if (features.textureCompressionASTC_LDR) printf("%stextureCompressionASTC_LDR\n", indent); if (features.textureCompressionBC) printf("%stextureCompressionBC\n", indent); if (features.occlusionQueryPrecise) printf("%socclusionQueryPrecise\n", indent); if (features.pipelineStatisticsQuery) printf("%spipelineStatisticsQuery\n", indent); if (features.vertexPipelineStoresAndAtomics) printf("%svertexPipelineStoresAndAtomics\n", indent); if (features.fragmentStoresAndAtomics) printf("%sfragmentStoresAndAtomics\n", indent); if (features.shaderTessellationAndGeometryPointSize) printf("%sshaderTessellationAndGeometryPointSize\n", indent); if (features.shaderImageGatherExtended) printf("%sshaderImageGatherExtended\n", indent); if (features.shaderStorageImageExtendedFormats) printf("%sshaderStorageImageExtendedFormats\n", indent); if (features.shaderStorageImageMultisample) printf("%sshaderStorageImageMultisample\n", indent); if (features.shaderStorageImageReadWithoutFormat) printf("%sshaderStorageImageReadWithoutFormat\n", indent); if (features.shaderStorageImageWriteWithoutFormat) printf("%sshaderStorageImageWriteWithoutFormat\n", indent); if (features.shaderUniformBufferArrayDynamicIndexing) printf("%sshaderUniformBufferArrayDynamicIndexing\n", indent); if (features.shaderSampledImageArrayDynamicIndexing) printf("%sshaderSampledImageArrayDynamicIndexing\n", indent); if (features.shaderStorageBufferArrayDynamicIndexing) printf("%sshaderStorageBufferArrayDynamicIndexing\n", indent); if (features.shaderStorageImageArrayDynamicIndexing) printf("%sshaderStorageImageArrayDynamicIndexing\n", indent); if (features.shaderClipDistance) printf("%sshaderClipDistance\n", indent); if (features.shaderCullDistance) printf("%sshaderCullDistance\n", indent); if (features.shaderFloat64) printf("%sshaderFloat64\n", indent); if (features.shaderInt64) printf("%sshaderInt64\n", indent); if (features.shaderInt16) printf("%sshaderInt16\n", indent); if (features.shaderResourceResidency) printf("%sshaderResourceResidency\n", indent); if (features.shaderResourceMinLod) printf("%sshaderResourceMinLod\n", indent); if (features.sparseBinding) printf("%ssparseBinding\n", indent); if (features.sparseResidencyBuffer) printf("%ssparseResidencyBuffer\n", indent); if (features.sparseResidencyImage2D) printf("%ssparseResidencyImage2D\n", indent); if (features.sparseResidencyImage3D) printf("%ssparseResidencyImage3D\n", indent); if (features.sparseResidency2Samples) printf("%ssparseResidency2Samples\n", indent); if (features.sparseResidency4Samples) printf("%ssparseResidency4Samples\n", indent); if (features.sparseResidency8Samples) printf("%ssparseResidency8Samples\n", indent); if (features.sparseResidency16Samples) printf("%ssparseResidency16Samples\n", indent); if (features.sparseResidencyAliased) printf("%ssparseResidencyAliased\n", indent); if (features.variableMultisampleRate) printf("%svariableMultisampleRate\n", indent); if (features.inheritedQueries) printf("%sinheritedQueries\n", indent); // clang-format on } void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) { VkResult result; std::ostringstream strbuf; printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent), info.properties.deviceName, VkPhysicalDeviceTypeStr(info.properties.deviceType), VK_VERSION_MAJOR(info.properties.apiVersion), VK_VERSION_MINOR(info.properties.apiVersion), VK_VERSION_PATCH(info.properties.apiVersion), info.properties.driverVersion, info.properties.vendorID, info.properties.deviceID); for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) { if ((info.memory.memoryHeaps[heap].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) strbuf << "DEVICE_LOCAL"; printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n", Indent(indent + 1), heap, info.memory.memoryHeaps[heap].size / 0x100000, info.memory.memoryHeaps[heap].size, strbuf.str().c_str()); strbuf.str(std::string()); for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) { if (info.memory.memoryTypes[type].heapIndex != heap) continue; VkMemoryPropertyFlags flags = info.memory.memoryTypes[type].propertyFlags; if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) strbuf << " DEVICE_LOCAL"; if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) strbuf << " HOST_VISIBLE"; if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0) strbuf << " COHERENT"; if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) strbuf << " CACHED"; if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0) strbuf << " LAZILY_ALLOCATED"; printf("%sType %u:%s\n", Indent(indent + 2), type, strbuf.str().c_str()); strbuf.str(std::string()); } } for (uint32_t family = 0; family < info.queue_families.size(); family++) { const VkQueueFamilyProperties& qprops = info.queue_families[family]; VkQueueFlags flags = qprops.queueFlags; char flags_str[5]; flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_'; flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_'; flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_'; flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_'; flags_str[4] = '\0'; printf( "%sQueue Family %u: %ux %s\n" "%stimestampValidBits: %ub\n" "%sminImageTransferGranularity: (%u,%u,%u)\n", Indent(indent + 1), family, qprops.queueCount, flags_str, Indent(indent + 2), qprops.timestampValidBits, Indent(indent + 2), qprops.minImageTransferGranularity.width, qprops.minImageTransferGranularity.height, qprops.minImageTransferGranularity.depth); } printf("%sFeatures:\n", Indent(indent + 1)); if (options.unsupported_features) { PrintAllFeatures(Indent(indent + 2), info.features); } else { PrintSupportedFeatures(Indent(indent + 2), info.features); } printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size()); if (!info.extensions.empty()) PrintExtensions(info.extensions, options, indent + 2); printf("%sLayers [%zu]:\n", Indent(indent + 1), info.layers.size()); if (!info.layers.empty()) PrintLayers(info.layers, info.layer_extensions, options, indent + 2); } void PrintInfo(const VulkanInfo& info, const Options& options) { std::ostringstream strbuf; size_t indent = 0; printf("%sInstance Extensions [%zu]:\n", Indent(indent), info.extensions.size()); PrintExtensions(info.extensions, options, indent + 1); printf("%sInstance Layers [%zu]:\n", Indent(indent), info.layers.size()); if (!info.layers.empty()) PrintLayers(info.layers, info.layer_extensions, options, indent + 1); printf("%sPhysicalDevices [%zu]:\n", Indent(indent), info.gpus.size()); for (const auto& gpu : info.gpus) PrintGpuInfo(gpu, options, indent + 1); } const char kUsageString[] = "usage: vkinfo [options]\n" " -v enable all the following verbose options\n" " -layer_description print layer description strings\n" " -layer_extensions print extensions supported by each layer\n" " -unsupported_features print all physical device features\n" " -validate enable validation layers if present\n" " -debug_pause pause at start until resumed via debugger\n"; } // namespace // ---------------------------------------------------------------------------- int main(int argc, char const* argv[]) { static volatile bool startup_pause = false; Options options = { .layer_description = false, .layer_extensions = false, .unsupported_features = false, .validate = false, }; for (int argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "-h") == 0) { fputs(kUsageString, stdout); return 0; } if (strcmp(argv[argi], "-v") == 0) { options.layer_description = true; options.layer_extensions = true; options.unsupported_features = true; } else if (strcmp(argv[argi], "-layer_description") == 0) { options.layer_description = true; } else if (strcmp(argv[argi], "-layer_extensions") == 0) { options.layer_extensions = true; } else if (strcmp(argv[argi], "-unsupported_features") == 0) { options.unsupported_features = true; } else if (strcmp(argv[argi], "-validate") == 0) { options.validate = true; } else if (strcmp(argv[argi], "-debug_pause") == 0) { startup_pause = true; } } while (startup_pause) { sleep(0); } VulkanInfo info; GatherInfo(&info, options); PrintInfo(info, options); return 0; }