Generate all APIs.

This CL expands the generator to create all the .rsh files, not just
the core_math one.  To do so, processing of types (simple, struct, enums)
and constants was added.  .spec files corresponding to each .rsh file was
created.  Documentation was added.

This CL also generates HTML documentation files.  This generation will soon
be upgraded.

To make the code easier to expand, I've done fairly extensive refactoring.

In a subsequent CL, the APIs will be regrouped in different header files to
simplify learning the APIs.  In an other, the documentation generation will
be futher improved and incorporated in the actual online help.

Also removes rs_path & related functions.

Change-Id: I2c88554c9c6a8625233772b89e055fc6c4ad5da5
diff --git a/api/GenerateHeaderFiles.cpp b/api/GenerateHeaderFiles.cpp
new file mode 100644
index 0000000..4b2ecc7
--- /dev/null
+++ b/api/GenerateHeaderFiles.cpp
@@ -0,0 +1,360 @@
+/*
+ * 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 <iostream>
+#include <sstream>
+
+#include "Generator.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+// Convert a file name into a string that can be used to guard the include file with #ifdef...
+static string makeGuardString(const string& filename) {
+    string s;
+    s.resize(15 + filename.size());
+    s = "RENDERSCRIPT_";
+    for (char c : filename) {
+        if (c == '.') {
+            s += '_';
+        } else {
+            s += toupper(c);
+        }
+    }
+    return s;
+}
+
+// Write #ifdef's that ensure that the specified version is present
+static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info) {
+    if (info.intSize == 32) {
+        *file << "#ifndef __LP64__\n";
+    } else if (info.intSize == 64) {
+        *file << "#ifdef __LP64__\n";
+    }
+
+    if (info.minVersion <= 1) {
+        // No minimum
+        if (info.maxVersion > 0) {
+            *file << "#if !defined(RS_VERSION) || (RS_VERSION <= " << info.maxVersion << ")\n";
+        }
+    } else {
+        if (info.maxVersion == 0) {
+            // No maximum
+            *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << "))\n";
+        } else {
+            *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion
+                  << ") && (RS_VERSION <= " << info.maxVersion << "))\n";
+        }
+    }
+}
+
+static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
+    if (info.minVersion > 1 || info.maxVersion != 0) {
+        *file << "#endif\n";
+    }
+    if (info.intSize != 0) {
+        *file << "#endif\n";
+    }
+}
+
+static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
+                         const vector<string>& comment, bool closeBlock) {
+    if (briefComment.empty() && comment.size() == 0) {
+        return;
+    }
+    *file << "/*\n";
+    if (!briefComment.empty()) {
+        *file << " * " << name << ": " << briefComment << "\n";
+        *file << " *\n";
+    }
+    for (size_t ct = 0; ct < comment.size(); ct++) {
+        string s = stripHtml(comment[ct]);
+        s = stringReplace(s, "@", "");
+        if (!s.empty()) {
+            *file << " * " << s << "\n";
+        } else {
+            *file << " *\n";
+        }
+    }
+    if (closeBlock) {
+        *file << " */\n";
+    }
+}
+
+static void writeConstant(GeneratedFile* file, const Constant& constant) {
+    const string name = constant.getName();
+    writeComment(file, name, constant.getSummary(), constant.getDescription(), true);
+
+    for (auto spec : constant.getSpecifications()) {
+        VersionInfo info = spec->getVersionInfo();
+        writeVersionGuardStart(file, info);
+        *file << "#define " << name << " " << spec->getValue() << "\n";
+        writeVersionGuardEnd(file, info);
+    }
+    *file << "\n";
+}
+
+static void writeTypeSpecification(GeneratedFile* file, const string& typeName,
+                                   const TypeSpecification& spec) {
+    const VersionInfo info = spec.getVersionInfo();
+    writeVersionGuardStart(file, info);
+    switch (spec.getKind()) {
+        case SIMPLE:
+            *file << "typedef " << spec.getSimpleType() << " " << typeName << ";\n";
+            break;
+        case ENUM: {
+            *file << "typedef enum ";
+            const string name = spec.getEnumName();
+            if (!name.empty()) {
+                *file << name << " ";
+            }
+            *file << "{\n";
+
+            const vector<string>& values = spec.getValues();
+            const vector<string>& valueComments = spec.getValueComments();
+            const size_t last = values.size() - 1;
+            for (size_t i = 0; i <= last; i++) {
+                *file << "    " << values[i];
+                if (i != last) {
+                    *file << ",";
+                }
+                if (valueComments.size() > i && !valueComments[i].empty()) {
+                    *file << " // " << valueComments[i];
+                }
+                *file << "\n";
+            }
+            *file << "} " << typeName << ";\n";
+            break;
+        }
+        case STRUCT: {
+            *file << "typedef struct ";
+            const string name = spec.getStructName();
+            if (!name.empty()) {
+                *file << name << " ";
+            }
+            *file << "{\n";
+
+            const vector<string>& fields = spec.getFields();
+            const vector<string>& fieldComments = spec.getFieldComments();
+            for (size_t i = 0; i < fields.size(); i++) {
+                *file << "    " << fields[i] << ";";
+                if (fieldComments.size() > i && !fieldComments[i].empty()) {
+                    *file << " // " << fieldComments[i];
+                }
+                *file << "\n";
+            }
+            *file << "} ";
+            const string attrib = spec.getAttrib();
+            if (!attrib.empty()) {
+                *file << attrib << " ";
+            }
+            *file << typeName << ";\n";
+            break;
+        }
+    }
+    writeVersionGuardEnd(file, info);
+    *file << "\n";
+}
+
+static void writeType(GeneratedFile* file, const Type& type) {
+    const string name = type.getName();
+    writeComment(file, name, type.getSummary(), type.getDescription(), true);
+
+    for (auto spec : type.getSpecifications()) {
+        writeTypeSpecification(file, name, *spec);
+    }
+    *file << "\n";
+}
+
+static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
+                                     const FunctionPermutation& permutation) {
+    writeVersionGuardStart(file, spec.getVersionInfo());
+
+    // Write linkage info.
+    const auto inlineCodeLines = permutation.getInline();
+    if (inlineCodeLines.size() > 0) {
+        *file << "static inline ";
+    } else {
+        *file << "extern ";
+    }
+
+    // Write the return type.
+    auto ret = permutation.getReturn();
+    if (ret) {
+        *file << ret->rsType;
+    } else {
+        *file << "void";
+    }
+
+    // Write the attribute.
+    *file << " __attribute__((";
+    const string attrib = spec.getAttribute();
+    if (attrib.empty()) {
+        *file << "overloadable";
+    } else if (attrib[0] == '=') {
+        /* If starts with an equal, we don't automatically add overloadable.
+         * This is because of the error we made defining rsUnpackColor8888().
+         */
+        *file << attrib.substr(1);
+    } else {
+        *file << attrib << ", overloadable";
+    }
+    *file << "))\n";
+
+    // Write the function name.
+    *file << "    " << permutation.getName() << "(";
+    const int offset = 4 + permutation.getName().size() + 1;  // Size of above
+
+    // Write the arguments.  We wrap on mulitple lines if a line gets too long.
+    int charsOnLine = offset;
+    bool hasGenerated = false;
+    for (auto p : permutation.getParams()) {
+        if (hasGenerated) {
+            *file << ",";
+            charsOnLine++;
+        }
+        ostringstream ps;
+        ps << p->rsType;
+        if (p->isOutParameter) {
+            ps << "*";
+        }
+        if (!p->specName.empty()) {
+            ps << " " << p->specName;
+        }
+        const string s = ps.str();
+        if (charsOnLine + s.size() >= 100) {
+            *file << "\n" << string(offset, ' ');
+            charsOnLine = offset;
+        } else if (hasGenerated) {
+            *file << " ";
+            charsOnLine++;
+        }
+        *file << s;
+        charsOnLine += s.size();
+        hasGenerated = true;
+    }
+    // In C, if no parameters, we need to output void, e.g. fn(void).
+    if (!hasGenerated) {
+        *file << "void";
+    }
+    *file << ")";
+
+    // Write the inline code, if any.
+    if (inlineCodeLines.size() > 0) {
+        *file << " {\n";
+        for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
+            if (inlineCodeLines[ct].empty()) {
+                *file << "\n";
+            } else {
+                *file << "    " << inlineCodeLines[ct] << "\n";
+            }
+        }
+        *file << "}\n";
+    } else {
+        *file << ";\n";
+    }
+
+    writeVersionGuardEnd(file, spec.getVersionInfo());
+    *file << "\n";
+}
+
+static void writeFunction(GeneratedFile* file, const Function& function) {
+    // Write the generic documentation.
+    writeComment(file, function.getName(), function.getSummary(), function.getDescription(), false);
+
+    // Comment the parameters.
+    if (function.someParametersAreDocumented()) {
+        *file << " *\n";
+        *file << " * Parameters:\n";
+        for (auto p : function.getParameters()) {
+            if (!p->documentation.empty()) {
+                *file << " *   " << p->name << " " << p->documentation << "\n";
+            }
+        }
+    }
+
+    // Comment the return type.
+    const string returnDoc = function.getReturnDocumentation();
+    if (!returnDoc.empty()) {
+        *file << " *\n";
+        *file << " * Returns: " << returnDoc << "\n";
+    }
+
+    *file << " */\n";
+
+    // Write all the variants.
+    for (auto spec : function.getSpecifications()) {
+        for (auto permutation : spec->getPermutations()) {
+            writeFunctionPermutation(file, *spec, *permutation);
+        }
+    }
+}
+
+static bool writeHeaderFile(const SpecFile& specFile) {
+    const string headerFileName = specFile.getHeaderFileName();
+
+    // We generate one header file for each spec file.
+    GeneratedFile file;
+    if (!file.start(headerFileName)) {
+        return false;
+    }
+
+    // Write the comments that start the file.
+    file.writeNotices();
+    writeComment(&file, headerFileName, specFile.getBriefDescription(),
+                 specFile.getFullDescription(), true);
+
+    // Write the ifndef that prevents the file from being included twice.
+    const string guard = makeGuardString(headerFileName);
+    file << "#ifndef " << guard << "\n";
+    file << "#define " << guard << "\n\n";
+
+    // Add lines that need to be put in "as is".
+    if (specFile.getVerbatimInclude().size() > 0) {
+        for (auto s : specFile.getVerbatimInclude()) {
+            file << s << "\n";
+        }
+        file << "\n";
+    }
+
+    /* Write the constants, types, and functions in the same order as
+     * encountered in the spec file.
+     */
+    for (auto iter : specFile.getConstantsList()) {
+        writeConstant(&file, *iter);
+    }
+    for (auto iter : specFile.getTypesList()) {
+        writeType(&file, *iter);
+    }
+    for (auto iter : specFile.getFunctionsList()) {
+        writeFunction(&file, *iter);
+    }
+
+    file << "#endif // " << guard << "\n";
+    file.close();
+    return true;
+}
+
+bool GenerateHeaderFiles() {
+    bool success = true;
+    for (auto specFile : systemSpecification.getSpecFiles()) {
+        if (!writeHeaderFile(*specFile)) {
+            success = false;
+        }
+    }
+    return success;
+}
diff --git a/api/GenerateHtmlDocumentation.cpp b/api/GenerateHtmlDocumentation.cpp
new file mode 100644
index 0000000..a7782c8
--- /dev/null
+++ b/api/GenerateHtmlDocumentation.cpp
@@ -0,0 +1,672 @@
+/*
+ * 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 <iostream>
+#include <sstream>
+
+#include "Generator.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+struct DetailedFunctionEntry {
+    VersionInfo info;
+    string htmlDeclaration;
+};
+
+static void writeHtmlHeader(GeneratedFile* file) {
+    *file << "<!DOCTYPE html>\n";
+    *file << "<!-- " << AUTO_GENERATED_WARNING << "-->\n";
+
+    *file << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
+             "<meta name='viewport' content='width=device-width'>\n"
+             "<link rel='shortcut icon' type='image/x-icon' "
+             "href='http://developer.android.com/favicon.ico'>\n"
+             "<title>android.renderscript | Android Developers</title>\n"
+             "<!-- STYLESHEETS -->\n"
+             "<link rel='stylesheet' "
+             "href='http://fonts.googleapis.com/css?family=Roboto+Condensed'>\n"
+             "<link rel='stylesheet' href='http://fonts.googleapis.com/"
+             "css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold' "
+             "title='roboto'>\n"
+             "<link href='./test_files/default.css' rel='stylesheet' type='text/css'>\n"
+             "<!-- FULLSCREEN STYLESHEET -->\n"
+             "<link href='./test_files/fullscreen.css' rel='stylesheet' class='fullscreen' "
+             "type='text/css'>\n"
+             "<!-- JAVASCRIPT -->\n"
+             "<script src='./test_files/cb=gapi.loaded_0' async=''></script><script "
+             "type='text/javascript' async='' src='./test_files/plusone.js' "
+             "gapi_processed='true'></script><script async='' "
+             "src='./test_files/analytics.js'></script><script src='./test_files/jsapi' "
+             "type='text/javascript'></script>\n"
+             "<script src='./test_files/android_3p-bundle.js' type='text/javascript'></script>\n"
+             "<script type='text/javascript'>\n"
+             "  var toRoot = '/';\n"
+             "  var metaTags = [];\n"
+             "  var devsite = false;\n"
+             "</script>\n"
+             "<script src='./test_files/docs.js' type='text/javascript'></script><script "
+             "type='text/javascript' src='./test_files/saved_resource'></script>\n"
+             "<script>\n"
+             "  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
+             "  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n"
+             "  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
+             "  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
+             "  ga('create', 'UA-5831155-1', 'android.com');\n"
+             "  ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'});  // New "
+             "tracker);\n"
+             "  ga('send', 'pageview');\n"
+             "  ga('universal.send', 'pageview'); // Send page view for new tracker.\n"
+             "</script>\n"
+             "<link type='text/css' href='./test_files/default+en.css' rel='stylesheet'><script "
+             "type='text/javascript' src='./test_files/default+en.I.js'></script></head>\n"
+             "<body class='gc-documentation\n"
+             "  develop reference'>\n";
+    //"  <div id='doc-api-level' class='11' style='display:none'></div>\n"
+    //"  <a name='top'></a>\n";
+}
+
+static void writeHtmlFooter(GeneratedFile* file) {
+    *file << "</div> <!-- end body-content -->\n"
+             "</body></html>\n";
+}
+
+// If prefix starts input, copy it to stream and remove it from input.
+static void skipPrefix(ostringstream* stream, string* input, const string& prefix) {
+    size_t size = prefix.size();
+    if (input->compare(0, size, prefix) != 0) {
+        return;
+    }
+    input->erase(0, size);
+    *stream << prefix;
+}
+
+// Merge b into a.  Returns true if successful
+static bool mergeVersionInfo(VersionInfo* a, const VersionInfo& b) {
+    if (a->intSize != b.intSize) {
+        cerr << "Error.  We don't currently support versions that differ based on int size\n";
+        return false;
+    }
+    if (b.minVersion != 0 && a->maxVersion == b.minVersion - 1) {
+        a->maxVersion = b.maxVersion;
+    } else if (b.maxVersion != 0 && a->minVersion == b.maxVersion + 1) {
+        a->minVersion = b.minVersion;
+    } else {
+        cerr << "Error.  This code currently assume that all versions are contiguous.  Don't know "
+                "how to merge versions (" << a->minVersion << " - " << a->maxVersion << ") and ("
+             << b.minVersion << " - " << b.maxVersion << ")\n";
+        return false;
+    }
+    return true;
+}
+
+static string getHtmlStringForType(const ParameterDefinition& parameter) {
+    string s = parameter.rsType;
+    ostringstream stream;
+    skipPrefix(&stream, &s, "const ");
+    skipPrefix(&stream, &s, "volatile ");
+    bool endsWithAsterisk = s.size() > 0 && s[s.size() - 1] == '*';
+    if (endsWithAsterisk) {
+        s.erase(s.size() - 1, 1);
+    }
+
+    string anchor = systemSpecification.getHtmlAnchor(s);
+    if (anchor.empty()) {
+        // Not a RenderScript specific type.
+        return parameter.rsType;
+    } else {
+        stream << anchor;
+    }
+    if (endsWithAsterisk) {
+        stream << "*";
+    }
+    return stream.str();
+}
+
+static string getDetailedHtmlDeclaration(const FunctionPermutation& permutation) {
+    ostringstream stream;
+    auto ret = permutation.getReturn();
+    if (ret) {
+        stream << getHtmlStringForType(*ret);
+    } else {
+        stream << "void";
+    }
+    stream << " " << permutation.getName() << "(";
+    bool needComma = false;
+    for (auto p : permutation.getParams()) {
+        if (needComma) {
+            stream << ", ";
+        }
+        stream << getHtmlStringForType(*p);
+        if (p->isOutParameter) {
+            stream << "*";
+        }
+        if (!p->specName.empty()) {
+            stream << " " << p->specName;
+        }
+        needComma = true;
+    }
+    stream << ");\n";
+    return stream.str();
+}
+
+/* Some functions (like max) have changed implementations but not their
+ * declaration.  We need to unify these so that we don't end up with entries
+ * like:
+ *   char max(char a, char b);  Removed from API level 20
+ *   char max(char a, char b);  Added to API level 20
+ */
+static bool getUnifiedFunctionPrototypes(Function* function,
+                                         map<string, DetailedFunctionEntry>* entries) {
+    for (auto f : function->getSpecifications()) {
+        DetailedFunctionEntry entry;
+        entry.info = f->getVersionInfo();
+        for (auto p : f->getPermutations()) {
+            entry.htmlDeclaration = getDetailedHtmlDeclaration(*p);
+            const string s = stripHtml(entry.htmlDeclaration);
+            auto i = entries->find(s);
+            if (i == entries->end()) {
+                entries->insert(pair<string, DetailedFunctionEntry>(s, entry));
+            } else {
+                if (!mergeVersionInfo(&i->second.info, entry.info)) {
+                    return false;
+                }
+            }
+        }
+    }
+    return true;
+}
+
+// Convert words starting with @ into HTML references.  Returns false if error.
+static bool convertDocumentationRefences(string* s) {
+    bool success = true;
+    size_t end = 0;
+    for (;;) {
+        size_t start = s->find('@', end);
+        if (start == string::npos) {
+            break;
+        }
+        // Find the end of the identifier
+        end = start;
+        char c;
+        do {
+            c = (*s)[++end];
+        } while (isalnum(c) || c == '_');
+
+        const string id = s->substr(start + 1, end - start - 1);
+        string anchor = systemSpecification.getHtmlAnchor(id);
+        if (anchor.empty()) {
+            cerr << "Error:  Can't convert the documentation reference @" << id << "\n";
+            success = false;
+        }
+        s->replace(start, end - start, anchor);
+    }
+    return success;
+}
+
+static bool generateHtmlParagraphs(GeneratedFile* file, const vector<string>& description) {
+    bool inParagraph = false;
+    for (auto s : description) {
+        // Empty lines in the .spec marks paragraphs.
+        if (s.empty()) {
+            if (inParagraph) {
+                *file << "</p>\n";
+                inParagraph = false;
+            }
+        } else {
+            if (!inParagraph) {
+                *file << "<p> ";
+                inParagraph = true;
+            }
+        }
+        if (!convertDocumentationRefences(&s)) {
+            return false;
+        }
+        *file << s << "\n";
+    }
+    if (inParagraph) {
+        *file << "</p>\n";
+    }
+    return true;
+}
+
+static void writeSummaryTableStart(GeneratedFile* file, const char* label, bool labelIsHeading) {
+    if (labelIsHeading) {
+        *file << "<h2 style='margin-bottom: 0px;'>" << label << "</h2><hr>\n";
+    }
+    //#TODO promethods was the id.  implication?
+    *file << "<table id='id" << label << "' class='jd-sumtable'><tbody>\n";
+    if (!labelIsHeading) {
+        *file << "  <tr><th colspan='12'>" << label << "</th></tr>\n";
+    }
+}
+
+static void writeSummaryTableEnd(GeneratedFile* file) {
+    *file << "</tbody></table>\n";
+}
+
+static void writeSummaryTableEntry(GeneratedFile* file, Constant* constant) {
+    if (constant->hidden()) {
+        return;
+    }
+    *file << "  <tr class='alt-color api apilevel-1'>\n";
+    *file << "    <td class='jd-linkcol'><nobr>\n";
+    *file << "      <a href='" << constant->getUrl() << "'>" << constant->getName()
+          << "</a></nobr>\n";
+    *file << "    </td>\n";
+    *file << "    <td class='jd-descrcol' width='100%'><nobr>\n";
+    *file << "        " << constant->getSummary() << "\n";
+    *file << "    </td>\n";
+    *file << "  </tr>\n";
+}
+
+static void writeSummaryTableEntry(GeneratedFile* file, Type* type) {
+    if (type->hidden()) {
+        return;
+    }
+    *file << "  <tr class='alt-color api apilevel-1'>\n";
+    *file << "    <td class='jd-linkcol'><nobr>\n";
+    *file << "      <a href='" << type->getUrl() << "'>" << type->getName() << "</a></nobr>\n";
+    *file << "    </td>\n";
+    *file << "    <td class='jd-descrcol' width='100%'><nobr>\n";
+    *file << "        " << type->getSummary() << "\n";
+    *file << "    </td>\n";
+    *file << "  </tr>\n";
+}
+
+static void writeSummaryTableEntry(GeneratedFile* file, Function* function) {
+    *file << "  <tr class='alt-color api apilevel-1'>\n";
+    *file << "    <td class='jd-linkcol'>\n";
+    *file << "      <a href='" << function->getUrl() << "'>" << function->getName() << "</a>\n";
+    *file << "    </td>\n";
+    *file << "    <td class='jd-linkcol' width='100%'>\n";  // TODO jd-typecol
+    //    *file << "      <nobr><span class='sympad'></span></nobr>\n";
+    *file << "      <div class='jd-descrdiv'>\n";
+    *file << "        " << function->getSummary() << "\n";
+    *file << "      </div>\n";
+    *file << "    </td>\n";
+    *file << "  </tr>\n";
+}
+
+static void writeSummaryTables(GeneratedFile* file, const map<string, Constant*>& constants,
+                               const map<string, Type*>& types,
+                               const map<string, Function*>& functions, bool labelAsHeader) {
+    if (constants.size() > 0) {
+        writeSummaryTableStart(file, "Constants", labelAsHeader);
+        for (auto e : constants) {
+            writeSummaryTableEntry(file, e.second);
+        }
+        writeSummaryTableEnd(file);
+    }
+
+    if (types.size() > 0) {
+        writeSummaryTableStart(file, "Types", labelAsHeader);
+        for (auto e : types) {
+            writeSummaryTableEntry(file, e.second);
+        }
+        writeSummaryTableEnd(file);
+    }
+
+    if (functions.size() > 0) {
+        writeSummaryTableStart(file, "Functions", labelAsHeader);
+        for (auto e : functions) {
+            writeSummaryTableEntry(file, e.second);
+        }
+        writeSummaryTableEnd(file);
+    }
+}
+
+static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info) {
+    if (info.intSize == 32) {
+        *file << "For 32 bits: ";
+    } else if (info.intSize == 64) {
+        *file << "For 64 bits: ";
+    }
+
+    if (info.minVersion > 1 || info.maxVersion) {
+        *file << "<div>";
+        const char* mid =
+                    "<a "
+                    "href='http://developer.android.com/guide/topics/manifest/"
+                    "uses-sdk-element.html#ApiLevels'>API level ";
+        if (info.minVersion <= 1) {
+            // No minimum
+            if (info.maxVersion > 0) {
+                *file << "Removed from " << mid << info.maxVersion + 1;
+            }
+        } else {
+            if (info.maxVersion == 0) {
+                // No maximum
+                *file << "Added in " << mid << info.minVersion;
+            } else {
+                *file << mid << info.minVersion << " - " << info.maxVersion;
+            }
+        }
+        *file << "</a></div>\n";
+    }
+}
+
+static void writeDetailedType(GeneratedFile* file, const TypeSpecification* type) {
+    switch (type->getKind()) {
+        case SIMPLE:
+            *file << "Base type: " << type->getSimpleType() << "\n";
+            break;
+        case ENUM: {
+            *file << "An enum<br>\n";
+            *file << "    <table class='jd-tagtable'><tbody>\n";
+
+            const vector<string>& values = type->getValues();
+            const vector<string>& valueComments = type->getValueComments();
+            for (size_t i = 0; i < values.size(); i++) {
+                *file << "    <tr><th>" << values[i] << "</th>";
+                if (valueComments.size() > i && !valueComments[i].empty()) {
+                    *file << "<td>" << valueComments[i] << "</td>";
+                }
+                *file << "</tr>\n";
+            }
+            *file << "    </tbody></table>\n";
+            break;
+        }
+        case STRUCT: {
+            // TODO string mStructName;             // The name found after the struct keyword
+            *file << "A structure<br>\n";
+            *file << "    <table class='jd-tagtable'><tbody>\n";
+            const vector<string>& fields = type->getFields();
+            const vector<string>& fieldComments = type->getFieldComments();
+            for (size_t i = 0; i < fields.size(); i++) {
+                *file << "    <tr><th>" << fields[i] << "</th>";
+                if (fieldComments.size() > i && !fieldComments[i].empty()) {
+                    *file << "<td>" << fieldComments[i] << "</td>";
+                }
+                *file << "</tr>\n";
+            }
+            *file << "    </tbody></table>\n";
+            break;
+        }
+    }
+    writeHtmlVersionTag(file, type->getVersionInfo());
+}
+
+static void writeDetailedConstant(GeneratedFile* file, ConstantSpecification* c) {
+    *file << "Value: " << c->getValue() << "\n";
+    writeHtmlVersionTag(file, c->getVersionInfo());
+}
+
+static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) {
+    bool success = true;
+    *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n";
+    if (!generateHtmlParagraphs(file, specFile.getFullDescription())) {
+        success = false;
+    }
+
+    // Write the summary tables.
+    // file << "<h2>Summary</h2>\n";
+    const auto& constants = specFile.getConstantsMap();
+    const auto& types = specFile.getTypesMap();
+    const auto& functions = specFile.getFunctionsMap();
+    writeSummaryTables(file, constants, types, functions, false);
+    return success;
+}
+
+static bool generateOverview() {
+    GeneratedFile file;
+    if (!file.start("index.html")) {
+        return false;
+    }
+    bool success = true;
+    writeHtmlHeader(&file);
+
+    file << "<h1 itemprop='name'>Overview</h1>\n";
+    // TODO Have the overview text here!
+
+    for (auto specFile : systemSpecification.getSpecFiles()) {
+        if (!writeOverviewForFile(&file, *specFile)) {
+            success = false;
+        }
+    }
+
+    writeHtmlFooter(&file);
+    file.close();
+    return success;
+}
+
+static bool generateAlphabeticalIndex() {
+    GeneratedFile file;
+    if (!file.start("alpha_index.html")) {
+        return false;
+    }
+    writeHtmlHeader(&file);
+
+    writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
+                       systemSpecification.getFunctions(), true);
+
+    writeHtmlFooter(&file);
+    file.close();
+    return true;
+}
+
+static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) {
+    if (constant->hidden()) {
+        return true;
+    }
+    const string& name = constant->getName();
+
+    // TODO need names that distinguish fn.const. type
+    // TODO had attr_android:...
+    *file << "<a name='android_rs:" << name << "'></a>\n";
+    *file << "<div class='jd-details'>\n";
+    *file << "  <h4 class='jd-details-title'>\n";
+    *file << "    <span class='sympad'>" << name << "</span>\n";
+    *file << "    <span class='normal'>: " << constant->getSummary() << "</span>\n";
+    *file << "  </h4>\n";
+
+    *file << "  <div class='jd-details-descr'>\n";
+    *file << "    <table class='jd-tagtable'><tbody>\n";
+    for (auto f : constant->getSpecifications()) {
+        *file << "      <tr><td>";
+        writeDetailedConstant(file, f);
+        *file << "      </td></tr>\n";
+        *file << "<br/>\n";
+    }
+    *file << "    </tbody></table>\n";
+    *file << "  </div>\n";
+
+    *file << "    <div class='jd-tagdata jd-tagdescr'>\n";
+
+    if (!generateHtmlParagraphs(file, constant->getDescription())) {
+        return false;
+    }
+    *file << "    </div>\n";
+
+    *file << "</div>\n";
+    *file << "\n";
+    return true;
+}
+
+static bool writeDetailedType(GeneratedFile* file, Type* type) {
+    if (type->hidden()) {
+        return true;
+    }
+    const string& name = type->getName();
+
+    // TODO need names that distinguish fn.const. type
+    // TODO had attr_android:...
+    *file << "<a name='android_rs:" << name << "'></a>\n";
+    *file << "<div class='jd-details'>\n";
+    *file << "  <h4 class='jd-details-title'>\n";
+    *file << "    <span class='sympad'>" << name << "</span>\n";
+    *file << "    <span class='normal'>: " << type->getSummary() << "</span>\n";
+    *file << "  </h4>\n";
+
+    *file << "  <div class='jd-details-descr'>\n";
+    *file << "    <h5 class='jd-tagtitle'>Variants</h5>\n";
+    *file << "    <table class='jd-tagtable'><tbody>\n";
+    for (auto f : type->getSpecifications()) {
+        *file << "      <tr><td>";
+        writeDetailedType(file, f);
+        *file << "      </td></tr>\n";
+        *file << "<br/>\n";
+    }
+    *file << "    </tbody></table>\n";
+    *file << "  </div>\n";
+
+    *file << "    <div class='jd-tagdata jd-tagdescr'>\n";
+
+    if (!generateHtmlParagraphs(file, type->getDescription())) {
+        return false;
+    }
+
+    *file << "    </div>\n";
+
+    *file << "</div>\n";
+    *file << "\n";
+    return true;
+}
+
+static bool writeDetailedFunction(GeneratedFile* file, Function* function) {
+    const string& name = function->getName();
+
+    // TODO need names that distinguish fn.const. type
+    // TODO had attr_android:...
+    *file << "<a name='android_rs:" << name << "'></a>\n";
+    *file << "<div class='jd-details'>\n";
+    *file << "  <h4 class='jd-details-title'>\n";
+    *file << "    <span class='sympad'>" << name << "</span>\n";
+    *file << "    <span class='normal'>: " << function->getSummary() << "</span>\n";
+    *file << "  </h4>\n";
+
+    *file << "  <div class='jd-details-descr'>\n";
+    *file << "    <table class='jd-tagtable'><tbody>\n";
+    map<string, DetailedFunctionEntry> entries;
+    if (!getUnifiedFunctionPrototypes(function, &entries)) {
+        return false;
+    }
+    for (auto i : entries) {
+        *file << "      <tr>\n";
+        *file << "        <td>" << i.second.htmlDeclaration << "<td/>\n";
+        *file << "        <td>";
+        writeHtmlVersionTag(file, i.second.info);
+        *file << "</td>\n";
+        *file << "      </tr>\n";
+    }
+    *file << "    </tbody></table>\n";
+    *file << "  </div>\n";
+
+    if (function->someParametersAreDocumented()) {
+        *file << "  <div class='jd-tagdata'>";
+        *file << "    <h5 class='jd-tagtitle'>Parameters</h5>\n";
+        *file << "    <table class='jd-tagtable'><tbody>\n";
+        for (ParameterEntry* p : function->getParameters()) {
+            *file << "    <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n";
+        }
+        *file << "    </tbody></table>\n";
+        *file << "  </div>\n";
+    }
+
+    string ret = function->getReturnDocumentation();
+    if (!ret.empty()) {
+        *file << "  <div class='jd-tagdata'>";
+        *file << "    <h5 class='jd-tagtitle'>Returns</h5>\n";
+        *file << "    <table class='jd-tagtable'><tbody>\n";
+        *file << "    <tr><td>" << ret << "</td></tr>\n";
+        *file << "    </tbody></table>\n";
+        *file << "  </div>\n";
+    }
+
+    *file << "  <div class='jd-tagdata jd-tagdescr'>\n";
+    if (!generateHtmlParagraphs(file, function->getDescription())) {
+        return false;
+    }
+    *file << "  </div>\n";
+
+    *file << "</div>\n";
+    *file << "\n";
+    return true;
+}
+
+static bool writeDetailedDocumentationFile(const SpecFile& specFile) {
+    GeneratedFile file;
+    const string htmlFileName = stringReplace(specFile.getSpecFileName(), ".spec", ".html");
+    if (!file.start(htmlFileName)) {
+        return false;
+    }
+    bool success = true;
+
+    writeHtmlHeader(&file);
+    file << "<br/>";
+
+    // Write the file documentation.
+    file << "<h1 itemprop='name'>" << specFile.getBriefDescription()
+         << "</h1>\n";  // TODO not sure about itemprop
+
+    file << "<h2>Overview</h2>\n";
+    if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) {
+        success = false;
+    }
+
+    // Write the summary tables.
+    file << "<h2>Summary</h2>\n";
+    const auto& constants = specFile.getConstantsMap();
+    const auto& types = specFile.getTypesMap();
+    const auto& functions = specFile.getFunctionsMap();
+    writeSummaryTables(&file, constants, types, functions, false);
+
+    // Write the full details of each constant, type, and function.
+    if (!constants.empty()) {
+        file << "<h2>Constants</h2>\n";
+        for (auto i : constants) {
+            if (!writeDetailedConstant(&file, i.second)) {
+                success = false;
+            }
+        }
+    }
+    if (!types.empty()) {
+        file << "<h2>Types</h2>\n";
+        for (auto i : types) {
+            if (!writeDetailedType(&file, i.second)) {
+                success = false;
+            }
+        }
+    }
+    if (!functions.empty()) {
+        file << "<h2>Functions</h2>\n";
+        for (auto i : functions) {
+            if (!writeDetailedFunction(&file, i.second)) {
+                success = false;
+            }
+        }
+    }
+
+    writeHtmlFooter(&file);
+    file.close();
+
+    if (!success) {
+        // If in error, write a final message to make it easier to figure out which file failed.
+        cerr << htmlFileName << ": Failed due to errors.\n";
+    }
+    return success;
+}
+
+bool generateHtmlDocumentation() {
+    bool success = generateOverview() && generateAlphabeticalIndex();
+    for (auto specFile : systemSpecification.getSpecFiles()) {
+        if (!writeDetailedDocumentationFile(*specFile)) {
+            success = false;
+        }
+    }
+    return success;
+}
diff --git a/api/GenerateTestFiles.cpp b/api/GenerateTestFiles.cpp
new file mode 100644
index 0000000..7cf1099
--- /dev/null
+++ b/api/GenerateTestFiles.cpp
@@ -0,0 +1,1039 @@
+/*
+ * 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 <iomanip>
+#include <iostream>
+#include <cmath>
+#include <sstream>
+
+#include "Generator.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+// Converts float2 to FLOAT_32 and 2, etc.
+static void convertToRsType(const string& name, string* dataType, char* vectorSize) {
+    string s = name;
+    int last = s.size() - 1;
+    char lastChar = s[last];
+    if (lastChar >= '1' && lastChar <= '4') {
+        s.erase(last);
+        *vectorSize = lastChar;
+    } else {
+        *vectorSize = '1';
+    }
+    dataType->clear();
+    for (int i = 0; i < NUM_TYPES; i++) {
+        if (s == TYPES[i].cType) {
+            *dataType = TYPES[i].rsDataType;
+            break;
+        }
+    }
+}
+
+// Returns true if any permutation of the function have tests to b
+static bool needTestFiles(const Function& function, int versionOfTestFiles) {
+    for (auto spec : function.getSpecifications()) {
+        if (spec->hasTests(versionOfTestFiles)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* One instance of this class is generated for each permutation of a function for which
+ * we are generating test code.  This instance will generate both the script and the Java
+ * section of the test files for this permutation.  The class is mostly used to keep track
+ * of the various names shared between script and Java files.
+ * WARNING: Because the constructor keeps a reference to the FunctionPermutation, PermutationWriter
+ * should not exceed the lifetime of FunctionPermutation.
+ */
+class PermutationWriter {
+private:
+    FunctionPermutation& mPermutation;
+
+    string mRsKernelName;
+    string mJavaArgumentsClassName;
+    string mJavaArgumentsNClassName;
+    string mJavaVerifierComputeMethodName;
+    string mJavaVerifierVerifyMethodName;
+    string mJavaCheckMethodName;
+    string mJavaVerifyMethodName;
+
+    // Pointer to the files we are generating.  Handy to avoid always passing them in the calls.
+    GeneratedFile* mRs;
+    GeneratedFile* mJava;
+
+    /* Shortcuts to the return parameter and the first input parameter of the function
+     * specification.
+     */
+    const ParameterDefinition* mReturnParam;      // Can be nullptr.  NOT OWNED.
+    const ParameterDefinition* mFirstInputParam;  // Can be nullptr.  NOT OWNED.
+
+    /* All the parameters plus the return param, if present.  Collecting them together
+     * simplifies code generation.  NOT OWNED.
+     */
+    vector<const ParameterDefinition*> mAllInputsAndOutputs;
+
+    /* We use a class to pass the arguments between the generated code and the CoreVerifier.  This
+     * method generates this class.  The set keeps track if we've generated this class already
+     * for this test file, as more than one permutation may use the same argument class.
+     */
+    void writeJavaArgumentClass(bool scalar, set<string>* javaGeneratedArgumentClasses) const;
+
+    // Generate the Check* method that invokes the script and calls the verifier.
+    void writeJavaCheckMethod(bool generateCallToVerifier) const;
+
+    // Generate code to define and randomly initialize the input allocation.
+    void writeJavaInputAllocationDefinition(const ParameterDefinition& param) const;
+
+    /* Generate code that instantiate an allocation of floats or integers and fills it with
+     * random data. This random data must be compatible with the specified type.  This is
+     * used for the convert_* tests, as converting values that don't fit yield undefined results.
+     */
+    void writeJavaRandomCompatibleFloatAllocation(const string& dataType, const string& seed,
+                                                  char vectorSize,
+                                                  const NumericalType& compatibleType,
+                                                  const NumericalType& generatedType) const;
+    void writeJavaRandomCompatibleIntegerAllocation(const string& dataType, const string& seed,
+                                                    char vectorSize,
+                                                    const NumericalType& compatibleType,
+                                                    const NumericalType& generatedType) const;
+
+    // Generate code that defines an output allocation.
+    void writeJavaOutputAllocationDefinition(const ParameterDefinition& param) const;
+
+    /* Generate the code that verifies the results for RenderScript functions where each entry
+     * of a vector is evaluated independently.  If verifierValidates is true, CoreMathVerifier
+     * does the actual validation instead of more commonly returning the range of acceptable values.
+     */
+    void writeJavaVerifyScalarMethod(bool verifierValidates) const;
+
+    /* Generate the code that verify the results for a RenderScript function where a vector
+     * is a point in n-dimensional space.
+     */
+    void writeJavaVerifyVectorMethod() const;
+
+    // Generate the method header of the verify function.
+    void writeJavaVerifyMethodHeader() const;
+
+    // Generate codes that copies the content of an allocation to an array.
+    void writeJavaArrayInitialization(const ParameterDefinition& p) const;
+
+    // Generate code that tests one value returned from the script.
+    void writeJavaTestAndSetValid(const ParameterDefinition& p, const string& argsIndex,
+                                  const string& actualIndex) const;
+    void writeJavaTestOneValue(const ParameterDefinition& p, const string& argsIndex,
+                               const string& actualIndex) const;
+    // For test:vector cases, generate code that compares returned vector vs. expected value.
+    void writeJavaVectorComparison(const ParameterDefinition& p) const;
+
+    // Muliple functions that generates code to build the error message if an error is found.
+    void writeJavaAppendOutputToMessage(const ParameterDefinition& p, const string& argsIndex,
+                                        const string& actualIndex, bool verifierValidates) const;
+    void writeJavaAppendInputToMessage(const ParameterDefinition& p, const string& actual) const;
+    void writeJavaAppendNewLineToMessage() const;
+    void writeJavaAppendVariableToMessage(const ParameterDefinition& p, const string& value) const;
+    void writeJavaAppendFloatVariableToMessage(const string& value, bool regularFloat) const;
+    void writeJavaAppendVectorInputToMessage(const ParameterDefinition& p) const;
+    void writeJavaAppendVectorOutputToMessage(const ParameterDefinition& p) const;
+
+    // Generate the set of instructions to call the script.
+    void writeJavaCallToRs(bool relaxed, bool generateCallToVerifier) const;
+
+    // Write an allocation definition if not already emitted in the .rs file.
+    void writeRsAllocationDefinition(const ParameterDefinition& param,
+                                     set<string>* rsAllocationsGenerated) const;
+
+public:
+    /* NOTE: We keep pointers to the permutation and the files.  This object should not
+     * outlive the arguments.
+     */
+    PermutationWriter(FunctionPermutation& permutation, GeneratedFile* rsFile,
+                      GeneratedFile* javaFile);
+    string getJavaCheckMethodName() const { return mJavaCheckMethodName; }
+
+    // Write the script test function for this permutation.
+    void writeRsSection(set<string>* rsAllocationsGenerated) const;
+    // Write the section of the Java code that calls the script and validates the results
+    void writeJavaSection(set<string>* javaGeneratedArgumentClasses) const;
+};
+
+PermutationWriter::PermutationWriter(FunctionPermutation& permutation, GeneratedFile* rsFile,
+                                     GeneratedFile* javaFile)
+    : mPermutation(permutation),
+      mRs(rsFile),
+      mJava(javaFile),
+      mReturnParam(nullptr),
+      mFirstInputParam(nullptr) {
+    mRsKernelName = "test" + capitalize(permutation.getName());
+
+    mJavaArgumentsClassName = "Arguments";
+    mJavaArgumentsNClassName = "Arguments";
+    const string trunk = capitalize(permutation.getNameTrunk());
+    mJavaCheckMethodName = "check" + trunk;
+    mJavaVerifyMethodName = "verifyResults" + trunk;
+
+    for (auto p : permutation.getParams()) {
+        mAllInputsAndOutputs.push_back(p);
+        if (mFirstInputParam == nullptr && !p->isOutParameter) {
+            mFirstInputParam = p;
+        }
+    }
+    mReturnParam = permutation.getReturn();
+    if (mReturnParam) {
+        mAllInputsAndOutputs.push_back(mReturnParam);
+    }
+
+    for (auto p : mAllInputsAndOutputs) {
+        const string capitalizedRsType = capitalize(p->rsType);
+        const string capitalizedBaseType = capitalize(p->rsBaseType);
+        mRsKernelName += capitalizedRsType;
+        mJavaArgumentsClassName += capitalizedBaseType;
+        mJavaArgumentsNClassName += capitalizedBaseType;
+        if (p->mVectorSize != "1") {
+            mJavaArgumentsNClassName += "N";
+        }
+        mJavaCheckMethodName += capitalizedRsType;
+        mJavaVerifyMethodName += capitalizedRsType;
+    }
+    mJavaVerifierComputeMethodName = "compute" + trunk;
+    mJavaVerifierVerifyMethodName = "verify" + trunk;
+}
+
+void PermutationWriter::writeJavaSection(set<string>* javaGeneratedArgumentClasses) const {
+    // By default, we test the results using item by item comparison.
+    const string test = mPermutation.getTest();
+    if (test == "scalar" || test == "limited") {
+        writeJavaArgumentClass(true, javaGeneratedArgumentClasses);
+        writeJavaCheckMethod(true);
+        writeJavaVerifyScalarMethod(false);
+    } else if (test == "custom") {
+        writeJavaArgumentClass(true, javaGeneratedArgumentClasses);
+        writeJavaCheckMethod(true);
+        writeJavaVerifyScalarMethod(true);
+    } else if (test == "vector") {
+        writeJavaArgumentClass(false, javaGeneratedArgumentClasses);
+        writeJavaCheckMethod(true);
+        writeJavaVerifyVectorMethod();
+    } else if (test == "noverify") {
+        writeJavaCheckMethod(false);
+    }
+}
+
+void PermutationWriter::writeJavaArgumentClass(bool scalar,
+                                               set<string>* javaGeneratedArgumentClasses) const {
+    string name;
+    if (scalar) {
+        name = mJavaArgumentsClassName;
+    } else {
+        name = mJavaArgumentsNClassName;
+    }
+
+    // Make sure we have not generated the argument class already.
+    if (!testAndSet(name, javaGeneratedArgumentClasses)) {
+        mJava->indent() << "public class " << name;
+        mJava->startBlock();
+
+        for (auto p : mAllInputsAndOutputs) {
+            mJava->indent() << "public ";
+            if (p->isOutParameter && p->isFloatType && mPermutation.getTest() != "custom") {
+                *mJava << "Target.Floaty";
+            } else {
+                *mJava << p->javaBaseType;
+            }
+            if (!scalar && p->mVectorSize != "1") {
+                *mJava << "[]";
+            }
+            *mJava << " " << p->variableName << ";\n";
+        }
+        mJava->endBlock();
+        *mJava << "\n";
+    }
+}
+
+void PermutationWriter::writeJavaCheckMethod(bool generateCallToVerifier) const {
+    mJava->indent() << "private void " << mJavaCheckMethodName << "()";
+    mJava->startBlock();
+
+    // Generate the input allocations and initialization.
+    for (auto p : mAllInputsAndOutputs) {
+        if (!p->isOutParameter) {
+            writeJavaInputAllocationDefinition(*p);
+        }
+    }
+    // Generate code to enforce ordering between two allocations if needed.
+    for (auto p : mAllInputsAndOutputs) {
+        if (!p->isOutParameter && !p->smallerParameter.empty()) {
+            string smallerAlloc = "in" + capitalize(p->smallerParameter);
+            mJava->indent() << "enforceOrdering(" << smallerAlloc << ", " << p->javaAllocName
+                            << ");\n";
+        }
+    }
+
+    // Generate code to check the full and relaxed scripts.
+    writeJavaCallToRs(false, generateCallToVerifier);
+    writeJavaCallToRs(true, generateCallToVerifier);
+
+    mJava->endBlock();
+    *mJava << "\n";
+}
+
+void PermutationWriter::writeJavaInputAllocationDefinition(const ParameterDefinition& param) const {
+    string dataType;
+    char vectorSize;
+    convertToRsType(param.rsType, &dataType, &vectorSize);
+
+    const string seed = hashString(mJavaCheckMethodName + param.javaAllocName);
+    mJava->indent() << "Allocation " << param.javaAllocName << " = ";
+    if (param.compatibleTypeIndex >= 0) {
+        if (TYPES[param.typeIndex].kind == FLOATING_POINT) {
+            writeJavaRandomCompatibleFloatAllocation(dataType, seed, vectorSize,
+                                                     TYPES[param.compatibleTypeIndex],
+                                                     TYPES[param.typeIndex]);
+        } else {
+            writeJavaRandomCompatibleIntegerAllocation(dataType, seed, vectorSize,
+                                                       TYPES[param.compatibleTypeIndex],
+                                                       TYPES[param.typeIndex]);
+        }
+    } else if (!param.minValue.empty()) {
+        *mJava << "createRandomFloatAllocation(mRS, Element.DataType." << dataType << ", "
+               << vectorSize << ", " << seed << ", " << param.minValue << ", " << param.maxValue
+               << ")";
+    } else {
+        /* TODO Instead of passing always false, check whether we are doing a limited test.
+         * Use instead: (mPermutation.getTest() == "limited" ? "false" : "true")
+         */
+        *mJava << "createRandomAllocation(mRS, Element.DataType." << dataType << ", " << vectorSize
+               << ", " << seed << ", false)";
+    }
+    *mJava << ";\n";
+}
+
+void PermutationWriter::writeJavaRandomCompatibleFloatAllocation(
+            const string& dataType, const string& seed, char vectorSize,
+            const NumericalType& compatibleType, const NumericalType& generatedType) const {
+    *mJava << "createRandomFloatAllocation"
+           << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
+    double minValue = 0.0;
+    double maxValue = 0.0;
+    switch (compatibleType.kind) {
+        case FLOATING_POINT: {
+            // We're generating floating point values.  We just worry about the exponent.
+            // Subtract 1 for the exponent sign.
+            int bits = min(compatibleType.exponentBits, generatedType.exponentBits) - 1;
+            maxValue = ldexp(0.95, (1 << bits) - 1);
+            minValue = -maxValue;
+            break;
+        }
+        case UNSIGNED_INTEGER:
+            maxValue = maxDoubleForInteger(compatibleType.significantBits,
+                                           generatedType.significantBits);
+            minValue = 0.0;
+            break;
+        case SIGNED_INTEGER:
+            maxValue = maxDoubleForInteger(compatibleType.significantBits,
+                                           generatedType.significantBits);
+            minValue = -maxValue - 1.0;
+            break;
+    }
+    *mJava << scientific << std::setprecision(19);
+    *mJava << minValue << ", " << maxValue << ")";
+    mJava->unsetf(ios_base::floatfield);
+}
+
+void PermutationWriter::writeJavaRandomCompatibleIntegerAllocation(
+            const string& dataType, const string& seed, char vectorSize,
+            const NumericalType& compatibleType, const NumericalType& generatedType) const {
+    *mJava << "createRandomIntegerAllocation"
+           << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
+
+    if (compatibleType.kind == FLOATING_POINT) {
+        // Currently, all floating points can take any number we generate.
+        bool isSigned = generatedType.kind == SIGNED_INTEGER;
+        *mJava << (isSigned ? "true" : "false") << ", " << generatedType.significantBits;
+    } else {
+        bool isSigned =
+                    compatibleType.kind == SIGNED_INTEGER && generatedType.kind == SIGNED_INTEGER;
+        *mJava << (isSigned ? "true" : "false") << ", "
+               << min(compatibleType.significantBits, generatedType.significantBits);
+    }
+    *mJava << ")";
+}
+
+void PermutationWriter::writeJavaOutputAllocationDefinition(
+            const ParameterDefinition& param) const {
+    string dataType;
+    char vectorSize;
+    convertToRsType(param.rsType, &dataType, &vectorSize);
+    mJava->indent() << "Allocation " << param.javaAllocName << " = Allocation.createSized(mRS, "
+                    << "getElement(mRS, Element.DataType." << dataType << ", " << vectorSize
+                    << "), INPUTSIZE);\n";
+}
+
+void PermutationWriter::writeJavaVerifyScalarMethod(bool verifierValidates) const {
+    writeJavaVerifyMethodHeader();
+    mJava->startBlock();
+
+    string vectorSize = "1";
+    for (auto p : mAllInputsAndOutputs) {
+        writeJavaArrayInitialization(*p);
+        if (p->mVectorSize != "1" && p->mVectorSize != vectorSize) {
+            if (vectorSize == "1") {
+                vectorSize = p->mVectorSize;
+            } else {
+                cerr << "Error.  Had vector " << vectorSize << " and " << p->mVectorSize << "\n";
+            }
+        }
+    }
+
+    mJava->indent() << "for (int i = 0; i < INPUTSIZE; i++)";
+    mJava->startBlock();
+
+    mJava->indent() << "for (int j = 0; j < " << vectorSize << " ; j++)";
+    mJava->startBlock();
+
+    mJava->indent() << "// Extract the inputs.\n";
+    mJava->indent() << mJavaArgumentsClassName << " args = new " << mJavaArgumentsClassName
+                    << "();\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (!p->isOutParameter) {
+            mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName << "[i";
+            if (p->vectorWidth != "1") {
+                *mJava << " * " << p->vectorWidth << " + j";
+            }
+            *mJava << "];\n";
+        }
+    }
+    const bool hasFloat = mPermutation.hasFloatAnswers();
+    if (verifierValidates) {
+        mJava->indent() << "// Extract the outputs.\n";
+        for (auto p : mAllInputsAndOutputs) {
+            if (p->isOutParameter) {
+                mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName
+                                << "[i * " + p->vectorWidth + " + j];\n";
+            }
+        }
+        mJava->indent() << "// Ask the CoreMathVerifier to validate.\n";
+        if (hasFloat) {
+            mJava->indent() << "Target target = new Target(relaxed);\n";
+        }
+        mJava->indent() << "String errorMessage = CoreMathVerifier."
+                        << mJavaVerifierVerifyMethodName << "(args";
+        if (hasFloat) {
+            *mJava << ", target";
+        }
+        *mJava << ");\n";
+        mJava->indent() << "boolean valid = errorMessage == null;\n";
+    } else {
+        mJava->indent() << "// Figure out what the outputs should have been.\n";
+        if (hasFloat) {
+            mJava->indent() << "Target target = new Target(relaxed);\n";
+        }
+        mJava->indent() << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args";
+        if (hasFloat) {
+            *mJava << ", target";
+        }
+        *mJava << ");\n";
+        mJava->indent() << "// Validate the outputs.\n";
+        mJava->indent() << "boolean valid = true;\n";
+        for (auto p : mAllInputsAndOutputs) {
+            if (p->isOutParameter) {
+                writeJavaTestAndSetValid(*p, "", "[i * " + p->vectorWidth + " + j]");
+            }
+        }
+    }
+
+    mJava->indent() << "if (!valid)";
+    mJava->startBlock();
+
+    mJava->indent() << "StringBuilder message = new StringBuilder();\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (p->isOutParameter) {
+            writeJavaAppendOutputToMessage(*p, "", "[i * " + p->vectorWidth + " + j]",
+                                           verifierValidates);
+        } else {
+            writeJavaAppendInputToMessage(*p, "args." + p->variableName);
+        }
+    }
+    if (verifierValidates) {
+        mJava->indent() << "message.append(errorMessage);\n";
+    }
+
+    mJava->indent() << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
+    mJava->indentPlus()
+                << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
+
+    mJava->endBlock();
+    mJava->endBlock();
+    mJava->endBlock();
+    mJava->endBlock();
+    *mJava << "\n";
+}
+
+void PermutationWriter::writeJavaVerifyVectorMethod() const {
+    writeJavaVerifyMethodHeader();
+    mJava->startBlock();
+
+    for (auto p : mAllInputsAndOutputs) {
+        writeJavaArrayInitialization(*p);
+    }
+    mJava->indent() << "for (int i = 0; i < INPUTSIZE; i++)";
+    mJava->startBlock();
+
+    mJava->indent() << mJavaArgumentsNClassName << " args = new " << mJavaArgumentsNClassName
+                    << "();\n";
+
+    mJava->indent() << "// Create the appropriate sized arrays in args\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (p->mVectorSize != "1") {
+            string type = p->javaBaseType;
+            if (p->isOutParameter && p->isFloatType) {
+                type = "Target.Floaty";
+            }
+            mJava->indent() << "args." << p->variableName << " = new " << type << "["
+                            << p->mVectorSize << "];\n";
+        }
+    }
+
+    mJava->indent() << "// Fill args with the input values\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (!p->isOutParameter) {
+            if (p->mVectorSize == "1") {
+                mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName + "[i]"
+                                << ";\n";
+            } else {
+                mJava->indent() << "for (int j = 0; j < " << p->mVectorSize << " ; j++)";
+                mJava->startBlock();
+                mJava->indent() << "args." << p->variableName + "[j] = "
+                                << p->javaArrayName + "[i * " + p->vectorWidth + " + j]"
+                                << ";\n";
+                mJava->endBlock();
+            }
+        }
+    }
+    mJava->indent() << "Target target = new Target(relaxed);\n";
+    mJava->indent() << "CoreMathVerifier." << mJavaVerifierComputeMethodName
+                    << "(args, target);\n\n";
+
+    mJava->indent() << "// Compare the expected outputs to the actual values returned by RS.\n";
+    mJava->indent() << "boolean valid = true;\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (p->isOutParameter) {
+            writeJavaVectorComparison(*p);
+        }
+    }
+
+    mJava->indent() << "if (!valid)";
+    mJava->startBlock();
+
+    mJava->indent() << "StringBuilder message = new StringBuilder();\n";
+    for (auto p : mAllInputsAndOutputs) {
+        if (p->isOutParameter) {
+            writeJavaAppendVectorOutputToMessage(*p);
+        } else {
+            writeJavaAppendVectorInputToMessage(*p);
+        }
+    }
+
+    mJava->indent() << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
+    mJava->indentPlus()
+                << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
+
+    mJava->endBlock();
+    mJava->endBlock();
+    mJava->endBlock();
+    *mJava << "\n";
+}
+
+void PermutationWriter::writeJavaVerifyMethodHeader() const {
+    mJava->indent() << "private void " << mJavaVerifyMethodName << "(";
+    for (auto p : mAllInputsAndOutputs) {
+        *mJava << "Allocation " << p->javaAllocName << ", ";
+    }
+    *mJava << "boolean relaxed)";
+}
+
+void PermutationWriter::writeJavaArrayInitialization(const ParameterDefinition& p) const {
+    mJava->indent() << p.javaBaseType << "[] " << p.javaArrayName << " = new " << p.javaBaseType
+                    << "[INPUTSIZE * " << p.vectorWidth << "];\n";
+    mJava->indent() << p.javaAllocName << ".copyTo(" << p.javaArrayName << ");\n";
+}
+
+void PermutationWriter::writeJavaTestAndSetValid(const ParameterDefinition& p,
+                                                 const string& argsIndex,
+                                                 const string& actualIndex) const {
+    writeJavaTestOneValue(p, argsIndex, actualIndex);
+    mJava->startBlock();
+    mJava->indent() << "valid = false;\n";
+    mJava->endBlock();
+}
+
+void PermutationWriter::writeJavaTestOneValue(const ParameterDefinition& p, const string& argsIndex,
+                                              const string& actualIndex) const {
+    mJava->indent() << "if (";
+    if (p.isFloatType) {
+        *mJava << "!args." << p.variableName << argsIndex << ".couldBe(" << p.javaArrayName
+               << actualIndex;
+        const string s = mPermutation.getPrecisionLimit();
+        if (!s.empty()) {
+            *mJava << ", " << s;
+        }
+        *mJava << ")";
+    } else {
+        *mJava << "args." << p.variableName << argsIndex << " != " << p.javaArrayName
+               << actualIndex;
+    }
+
+    if (p.undefinedIfOutIsNan && mReturnParam) {
+        *mJava << " && !args." << mReturnParam->variableName << argsIndex << ".isNaN()";
+    }
+    *mJava << ")";
+}
+
+void PermutationWriter::writeJavaVectorComparison(const ParameterDefinition& p) const {
+    if (p.mVectorSize == "1") {
+        writeJavaTestAndSetValid(p, "", "[i]");
+    } else {
+        mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
+        mJava->startBlock();
+        writeJavaTestAndSetValid(p, "[j]", "[i * " + p.vectorWidth + " + j]");
+        mJava->endBlock();
+    }
+}
+
+void PermutationWriter::writeJavaAppendOutputToMessage(const ParameterDefinition& p,
+                                                       const string& argsIndex,
+                                                       const string& actualIndex,
+                                                       bool verifierValidates) const {
+    if (verifierValidates) {
+        const string actual = "args." + p.variableName + argsIndex;
+        mJava->indent() << "message.append(\"Output " + p.variableName + ": \");\n";
+        if (p.isFloatType) {
+            writeJavaAppendFloatVariableToMessage(actual, true);
+        } else {
+            writeJavaAppendVariableToMessage(p, actual);
+        }
+        writeJavaAppendNewLineToMessage();
+    } else {
+        const string expected = "args." + p.variableName + argsIndex;
+        const string actual = p.javaArrayName + actualIndex;
+        mJava->indent() << "message.append(\"Expected output " + p.variableName + ": \");\n";
+        if (p.isFloatType) {
+            writeJavaAppendFloatVariableToMessage(expected, false);
+        } else {
+            writeJavaAppendVariableToMessage(p, expected);
+        }
+        writeJavaAppendNewLineToMessage();
+        mJava->indent() << "message.append(\"Actual   output " + p.variableName + ": \");\n";
+        writeJavaAppendVariableToMessage(p, actual);
+
+        writeJavaTestOneValue(p, argsIndex, actualIndex);
+        mJava->startBlock();
+        mJava->indent() << "message.append(\" FAIL\");\n";
+        mJava->endBlock();
+        writeJavaAppendNewLineToMessage();
+    }
+}
+
+void PermutationWriter::writeJavaAppendInputToMessage(const ParameterDefinition& p,
+                                                      const string& actual) const {
+    mJava->indent() << "message.append(\"Input " + p.variableName + ": \");\n";
+    writeJavaAppendVariableToMessage(p, actual);
+    writeJavaAppendNewLineToMessage();
+}
+
+void PermutationWriter::writeJavaAppendNewLineToMessage() const {
+    mJava->indent() << "message.append(\"\\n\");\n";
+}
+
+void PermutationWriter::writeJavaAppendVariableToMessage(const ParameterDefinition& p,
+                                                         const string& value) const {
+    if (p.specType == "f16" || p.specType == "f32") {
+        mJava->indent() << "message.append(String.format(\"%14.8g {%8x} %15a\",\n";
+        mJava->indentPlus() << value << ", "
+                            << "Float.floatToRawIntBits(" << value << "), " << value << "));\n";
+    } else if (p.specType == "f64") {
+        mJava->indent() << "message.append(String.format(\"%24.8g {%16x} %31a\",\n";
+        mJava->indentPlus() << value << ", "
+                            << "Double.doubleToRawLongBits(" << value << "), " << value << "));\n";
+    } else if (p.specType[0] == 'u') {
+        mJava->indent() << "message.append(String.format(\"0x%x\", " << value << "));\n";
+    } else {
+        mJava->indent() << "message.append(String.format(\"%d\", " << value << "));\n";
+    }
+}
+
+void PermutationWriter::writeJavaAppendFloatVariableToMessage(const string& value,
+                                                              bool regularFloat) const {
+    mJava->indent() << "message.append(";
+    if (regularFloat) {
+        *mJava << "Float.toString(" << value << ")";
+    } else {
+        *mJava << value << ".toString()";
+    }
+    *mJava << ");\n";
+}
+
+void PermutationWriter::writeJavaAppendVectorInputToMessage(const ParameterDefinition& p) const {
+    if (p.mVectorSize == "1") {
+        writeJavaAppendInputToMessage(p, p.javaArrayName + "[i]");
+    } else {
+        mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
+        mJava->startBlock();
+        writeJavaAppendInputToMessage(p, p.javaArrayName + "[i * " + p.vectorWidth + " + j]");
+        mJava->endBlock();
+    }
+}
+
+void PermutationWriter::writeJavaAppendVectorOutputToMessage(const ParameterDefinition& p) const {
+    if (p.mVectorSize == "1") {
+        writeJavaAppendOutputToMessage(p, "", "[i]", false);
+    } else {
+        mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
+        mJava->startBlock();
+        writeJavaAppendOutputToMessage(p, "[j]", "[i * " + p.vectorWidth + " + j]", false);
+        mJava->endBlock();
+    }
+}
+
+void PermutationWriter::writeJavaCallToRs(bool relaxed, bool generateCallToVerifier) const {
+    string script = "script";
+    if (relaxed) {
+        script += "Relaxed";
+    }
+
+    mJava->indent() << "try";
+    mJava->startBlock();
+
+    for (auto p : mAllInputsAndOutputs) {
+        if (p->isOutParameter) {
+            writeJavaOutputAllocationDefinition(*p);
+        }
+    }
+
+    for (auto p : mPermutation.getParams()) {
+        if (p != mFirstInputParam) {
+            mJava->indent() << script << ".set_" << p->rsAllocName << "(" << p->javaAllocName
+                            << ");\n";
+        }
+    }
+
+    mJava->indent() << script << ".forEach_" << mRsKernelName << "(";
+    bool needComma = false;
+    if (mFirstInputParam) {
+        *mJava << mFirstInputParam->javaAllocName;
+        needComma = true;
+    }
+    if (mReturnParam) {
+        if (needComma) {
+            *mJava << ", ";
+        }
+        *mJava << mReturnParam->variableName << ");\n";
+    }
+
+    if (generateCallToVerifier) {
+        mJava->indent() << mJavaVerifyMethodName << "(";
+        for (auto p : mAllInputsAndOutputs) {
+            *mJava << p->variableName << ", ";
+        }
+
+        if (relaxed) {
+            *mJava << "true";
+        } else {
+            *mJava << "false";
+        }
+        *mJava << ");\n";
+    }
+    mJava->decreaseIndent();
+    mJava->indent() << "} catch (Exception e) {\n";
+    mJava->increaseIndent();
+    mJava->indent() << "throw new RSRuntimeException(\"RenderScript. Can't invoke forEach_"
+                    << mRsKernelName << ": \" + e.toString());\n";
+    mJava->endBlock();
+}
+
+/* Write the section of the .rs file for this permutation.
+ *
+ * We communicate the extra input and output parameters via global allocations.
+ * For example, if we have a function that takes three arguments, two for input
+ * and one for output:
+ *
+ * start:
+ * name: gamn
+ * ret: float3
+ * arg: float3 a
+ * arg: int b
+ * arg: float3 *c
+ * end:
+ *
+ * We'll produce:
+ *
+ * rs_allocation gAllocInB;
+ * rs_allocation gAllocOutC;
+ *
+ * float3 __attribute__((kernel)) test_gamn_float3_int_float3(float3 inA, unsigned int x) {
+ *    int inB;
+ *    float3 outC;
+ *    float2 out;
+ *    inB = rsGetElementAt_int(gAllocInB, x);
+ *    out = gamn(a, in_b, &outC);
+ *    rsSetElementAt_float4(gAllocOutC, &outC, x);
+ *    return out;
+ * }
+ *
+ * We avoid re-using x and y from the definition because these have reserved
+ * meanings in a .rs file.
+ */
+void PermutationWriter::writeRsSection(set<string>* rsAllocationsGenerated) const {
+    // Write the allocation declarations we'll need.
+    for (auto p : mPermutation.getParams()) {
+        // Don't need allocation for one input and one return value.
+        if (p != mFirstInputParam) {
+            writeRsAllocationDefinition(*p, rsAllocationsGenerated);
+        }
+    }
+    *mRs << "\n";
+
+    // Write the function header.
+    if (mReturnParam) {
+        *mRs << mReturnParam->rsType;
+    } else {
+        *mRs << "void";
+    }
+    *mRs << " __attribute__((kernel)) " << mRsKernelName;
+    *mRs << "(";
+    bool needComma = false;
+    if (mFirstInputParam) {
+        *mRs << mFirstInputParam->rsType << " " << mFirstInputParam->variableName;
+        needComma = true;
+    }
+    if (mPermutation.getOutputCount() > 1 || mPermutation.getInputCount() > 1) {
+        if (needComma) {
+            *mRs << ", ";
+        }
+        *mRs << "unsigned int x";
+    }
+    *mRs << ")";
+    mRs->startBlock();
+
+    // Write the local variable declarations and initializations.
+    for (auto p : mPermutation.getParams()) {
+        if (p == mFirstInputParam) {
+            continue;
+        }
+        mRs->indent() << p->rsType << " " << p->variableName;
+        if (p->isOutParameter) {
+            *mRs << " = 0;\n";
+        } else {
+            *mRs << " = rsGetElementAt_" << p->rsType << "(" << p->rsAllocName << ", x);\n";
+        }
+    }
+
+    // Write the function call.
+    if (mReturnParam) {
+        if (mPermutation.getOutputCount() > 1) {
+            mRs->indent() << mReturnParam->rsType << " " << mReturnParam->variableName << " = ";
+        } else {
+            mRs->indent() << "return ";
+        }
+    }
+    *mRs << mPermutation.getName() << "(";
+    needComma = false;
+    for (auto p : mPermutation.getParams()) {
+        if (needComma) {
+            *mRs << ", ";
+        }
+        if (p->isOutParameter) {
+            *mRs << "&";
+        }
+        *mRs << p->variableName;
+        needComma = true;
+    }
+    *mRs << ");\n";
+
+    if (mPermutation.getOutputCount() > 1) {
+        // Write setting the extra out parameters into the allocations.
+        for (auto p : mPermutation.getParams()) {
+            if (p->isOutParameter) {
+                mRs->indent() << "rsSetElementAt_" << p->rsType << "(" << p->rsAllocName << ", ";
+                // Check if we need to use '&' for this type of argument.
+                char lastChar = p->variableName.back();
+                if (lastChar >= '0' && lastChar <= '9') {
+                    *mRs << "&";
+                }
+                *mRs << p->variableName << ", x);\n";
+            }
+        }
+        if (mReturnParam) {
+            mRs->indent() << "return " << mReturnParam->variableName << ";\n";
+        }
+    }
+    mRs->endBlock();
+}
+
+void PermutationWriter::writeRsAllocationDefinition(const ParameterDefinition& param,
+                                                    set<string>* rsAllocationsGenerated) const {
+    if (!testAndSet(param.rsAllocName, rsAllocationsGenerated)) {
+        *mRs << "rs_allocation " << param.rsAllocName << ";\n";
+    }
+}
+
+// Open the mJavaFile and writes the header.
+static bool startJavaFile(GeneratedFile* file, const Function& function, const string& testName,
+                          const string& relaxedTestName) {
+    const string fileName = testName + ".java";
+    if (!file->start(fileName)) {
+        return false;
+    }
+    file->writeNotices();
+
+    *file << "package android.renderscript.cts;\n\n";
+
+    *file << "import android.renderscript.Allocation;\n";
+    *file << "import android.renderscript.RSRuntimeException;\n";
+    *file << "import android.renderscript.Element;\n\n";
+
+    *file << "public class " << testName << " extends RSBaseCompute";
+    file->startBlock();  // The corresponding endBlock() is in finishJavaFile()
+    *file << "\n";
+
+    file->indent() << "private ScriptC_" << testName << " script;\n";
+    file->indent() << "private ScriptC_" << relaxedTestName << " scriptRelaxed;\n\n";
+
+    file->indent() << "@Override\n";
+    file->indent() << "protected void setUp() throws Exception";
+    file->startBlock();
+
+    file->indent() << "super.setUp();\n";
+    file->indent() << "script = new ScriptC_" << testName << "(mRS);\n";
+    file->indent() << "scriptRelaxed = new ScriptC_" << relaxedTestName << "(mRS);\n";
+
+    file->endBlock();
+    *file << "\n";
+    return true;
+}
+
+// Write the test method that calls all the generated Check methods.
+static void finishJavaFile(GeneratedFile* file, const Function& function,
+                           const vector<string>& javaCheckMethods) {
+    file->indent() << "public void test" << function.getCapitalizedName() << "()";
+    file->startBlock();
+    for (auto m : javaCheckMethods) {
+        file->indent() << m << "();\n";
+    }
+    file->endBlock();
+
+    file->endBlock();
+}
+
+// Open the script file and write its header.
+static bool startRsFile(GeneratedFile* file, const Function& function, const string& testName) {
+    string fileName = testName + ".rs";
+    if (!file->start(fileName)) {
+        return false;
+    }
+    file->writeNotices();
+
+    *file << "#pragma version(1)\n";
+    *file << "#pragma rs java_package_name(android.renderscript.cts)\n\n";
+    return true;
+}
+
+// Write the entire *Relaxed.rs test file, as it only depends on the name.
+static bool writeRelaxedRsFile(const Function& function, const string& testName,
+                               const string& relaxedTestName) {
+    string name = relaxedTestName + ".rs";
+
+    GeneratedFile file;
+    if (!file.start(name)) {
+        return false;
+    }
+    file.writeNotices();
+
+    file << "#include \"" << testName << ".rs\"\n";
+    file << "#pragma rs_fp_relaxed\n";
+    file.close();
+    return true;
+}
+
+/* Write the .java and the two .rs test files.  versionOfTestFiles is used to restrict which API
+ * to test.
+ */
+static bool writeTestFilesForFunction(const Function& function, int versionOfTestFiles) {
+    // Avoid creating empty files if we're not testing this function.
+    if (!needTestFiles(function, versionOfTestFiles)) {
+        return true;
+    }
+
+    const string testName = "GeneratedTest" + function.getCapitalizedName();
+    const string relaxedTestName = testName + "Relaxed";
+
+    if (!writeRelaxedRsFile(function, testName, relaxedTestName)) {
+        return false;
+    }
+
+    GeneratedFile rsFile;    // The Renderscript test file we're generating.
+    GeneratedFile javaFile;  // The Jave test file we're generating.
+    if (!startRsFile(&rsFile, function, testName)) {
+        return false;
+    }
+
+    if (!startJavaFile(&javaFile, function, testName, relaxedTestName)) {
+        return false;
+    }
+
+    /* We keep track of the allocations generated in the .rs file and the argument classes defined
+     * in the Java file, as we share these between the functions created for each specification.
+     */
+    set<string> rsAllocationsGenerated;
+    set<string> javaGeneratedArgumentClasses;
+    // Lines of Java code to invoke the check methods.
+    vector<string> javaCheckMethods;
+
+    for (auto spec : function.getSpecifications()) {
+        if (spec->hasTests(versionOfTestFiles)) {
+            for (auto permutation : spec->getPermutations()) {
+                PermutationWriter w(*permutation, &rsFile, &javaFile);
+                w.writeRsSection(&rsAllocationsGenerated);
+                w.writeJavaSection(&javaGeneratedArgumentClasses);
+
+                // Store the check method to be called.
+                javaCheckMethods.push_back(w.getJavaCheckMethodName());
+            }
+        }
+    }
+
+    finishJavaFile(&javaFile, function, javaCheckMethods);
+    // There's no work to wrap-up in the .rs file.
+
+    rsFile.close();
+    javaFile.close();
+    return true;
+}
+
+bool GenerateTestFiles(int versionOfTestFiles) {
+    bool success = true;
+    for (auto specFile : systemSpecification.getSpecFiles()) {
+        for (auto f : specFile->getFunctionsMap()) {
+            if (!writeTestFilesForFunction(*f.second, versionOfTestFiles)) {
+                success = false;
+            }
+        }
+    }
+    return success;
+}
diff --git a/api/Generator.cpp b/api/Generator.cpp
new file mode 100644
index 0000000..376364c
--- /dev/null
+++ b/api/Generator.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+/* This program processes Renderscript function definitions described in spec files.
+ * For each spec file provided on the command line, it generates a corresponding
+ * Renderscript header (*.rsh) which is meant for inclusion in client scripts.
+ *
+ * This program also generates Junit test files to automatically test each of the
+ * functions using randomly generated data.  We create two files for each function:
+ * - a Renderscript file named Test{Function}.rs,
+ * - a Junit file named Test{function}.java, which calls the above RS file.
+ *
+ * Finally, this program generates HTML documentation files.
+ *
+ * This program takes an optional -v parameter, the RS version to target the
+ * test files for.  The header file will always contain all the functions.
+ *
+ * This program contains five main classes:
+ * - SpecFile: Represents on spec file.
+ * - Function: Each instance represents a function, like clamp.  Even though the
+ *      spec file contains many entries for clamp, we'll only have one clamp instance.
+ * - FunctionSpecification: Defines one of the many variations of the function.  There's
+ *      a one to one correspondance between FunctionSpecification objects and entries in the
+ *      spec file.  Strings that are parts of a FunctionSpecification can include placeholders,
+ *      which are "#1", "#2", "#3", and "#4".  We'll replace these by values before
+ *      generating the files.
+ * - Permutation: A concrete version of a specification, where all placeholders have
+ *      been replaced by actual values.
+ * - ParameterDefinition: A definition of a parameter of a concrete function.
+ *
+ * The format of the .spec files is described below.  Line that starts with # are comments.
+ * Replace the {} sections with your own contents.  [] indicates optional parts.
+ *
+ * It should start with a header as follows:
+ *
+ * header:
+ * summary:  {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * [include:
+ *     { Multiline code lines to be included as-is in the generated header file.}]
+ * end:
+ *
+ * Constants are defined as follows:
+ *
+ * constant:  {The name of the constant.}
+ * [version: {Starting API level} [ {Last API level that supports this.}]
+ * [size: {32 or 64.  Used if this is available only for 32 or 64 bit code.}]
+ * value: {The value of the constant.}
+ * [hidden:]   ...If present, don't document the constant.  Omit the following two fields.
+ * summary: {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * end:
+ *
+ * Types can either be simple types, structs, or enums.  They have the format:
+ *
+ * type:  {The typedef name of the type.}
+ * [version: {Starting API level} [ {Last API level that supports this.}]
+ * [size: {32 or 64.  Used if this is available only for 32 or 64 bit code.}]
+ * simple: {The C declaration that this type is the typedef equivalent.}
+ * [hidden:]   ...If present, don't document the type.  Omit the following two fields.
+ * summary: {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * end:
+ *
+ * type:  {The typedef name of the type.}
+ * [version: {Starting API level} [ {Last API level that supports this.}]
+ * [size: {32 or 64.  Used if this is available only for 32 or 64 bit code.}]
+ * struct: [{The name that will appear right after the struct keyword}]
+ * field: {Type and name of the field}[, "{One line documentation of the field}"]
+ * field:   ... Same for all the other fields of the struct.
+ * [attrib: {Attributes of the struct.}]
+ * [hidden:]   ...If present, don't document the type.  Omit the following two fields.
+ * summary: {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * end:
+ *
+ * type:  {The typedef name of the type.}
+ * [version: {Starting API level} [ {Last API level that supports this.}]
+ * [size: {32 or 64.  Used if this is available only for 32 or 64 bit code.}]
+ * enum: [{The name that will appear right after the enum keyword}]
+ * value: {Type and name of the field}[, "{One line documentation of the field}"]
+ * value:   ... Same for all the other values of the enum.
+ * [hidden:]   ...If present, don't document the type.  Omit the following two fields.
+ * summary: {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * end:
+
+ * Functions have the following format:
+ *
+ * function:  {The name of the function.}
+ * [version: {Starting API level} [ {Last API level that supports this.}]
+ * [size: {32 or 64.  Used if this is available only for 32 or 64 bit code.}]
+ * [attrib: {Attributes of the function.}]
+ * [w: {A comma separated list of width supported.  Only 1, 2, 3, 4 are supported.
+ * [t: {A comma separated list of the types supported.}]]
+ * ... Up to four w: or t: can be defined.  The order matter.  These will be replace
+ * ... the #1, #2, #3, #4 that can be found in the rest of the specification.
+ * ret: [{The return type} [, "{One line documentation of the return}"]]
+ * [arg: {Type}[, {Name}][, {ParameterEntry.testOption}][, "{One line documentation of the field}"]]
+ * [arg:   ... Same for all the other arguments of the function.]
+ * [hidden:]   ... If present, don't include in the HTML documentation.
+ * summary: {A one line string describing this section.}
+ * description:
+ *     {Multiline description.  Can include HTML.  References to constants, types,
+ *      and functions can be created by prefixing with a '@'.}
+ * [inline:
+ *     {Multiline code that implements this function inline.}]
+ * [test: {How to test this function.  See FunctionSpecification::mTest.}]
+ * end:
+ */
+
+#include <stdio.h>
+#include <cctype>
+#include <cstdlib>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <strings.h>
+
+#include "Generator.h"
+#include "Scanner.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+static bool parseCommandLine(int argc, char* argv[], int* versionOfTestFiles,
+                             vector<string>* specFileNames) {
+    for (int i = 1; i < argc; i++) {
+        if (argv[i][0] == '-') {
+            if (argv[i][1] == 'v') {
+                i++;
+                if (i < argc) {
+                    char* end;
+                    *versionOfTestFiles = strtol(argv[i], &end, 10);
+                    if (*end != '\0') {
+                        cerr << "Error. Can't parse the version number" << argv[i] << "\n";
+                        return false;
+                    }
+                } else {
+                    cerr << "Missing version number after -v\n";
+                    return false;
+                }
+            } else {
+                cerr << "Unrecognized flag %s\n" << argv[i] << "\n";
+                return false;
+            }
+        } else {
+            specFileNames->push_back(argv[i]);
+        }
+    }
+    if (specFileNames->size() == 0) {
+        cerr << "No spec file specified\n";
+        return false;
+    }
+    return true;
+}
+
+int main(int argc, char* argv[]) {
+    // If there's no restriction, generated test files for the very highest version.
+    int versionOfTestFiles = 999999;
+    vector<string> specFileNames;
+    if (!parseCommandLine(argc, argv, &versionOfTestFiles, &specFileNames)) {
+        cout << "Usage: gen_runtime spec_file [spec_file...] [-v version_of_test_files]\n";
+        return -1;
+    }
+    bool success = true;
+    for (auto i : specFileNames) {
+        if (!systemSpecification.readSpecFile(i)) {
+            success = false;
+        }
+    }
+    if (success) {
+        success = systemSpecification.generateFiles(versionOfTestFiles);
+    }
+    return success ? 0 : -2;
+}
diff --git a/api/Generator.h b/api/Generator.h
new file mode 100644
index 0000000..21ce5f9
--- /dev/null
+++ b/api/Generator.h
@@ -0,0 +1,29 @@
+/*
+ * 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_RS_API_GENERATOR_GENERATOR_H
+#define ANDROID_RS_API_GENERATOR_GENERATOR_H
+
+// Generates the RenderScript header files.  The implementation is in GenerateHeaderFiles.cpp.
+bool GenerateHeaderFiles();
+
+// Generates the Java and RenderScript test files.  The implementation is in GenerateTestFiles.cpp.
+bool GenerateTestFiles(int versionOfTestFiles);
+
+// Generates all HTML documentation files.  The implementation is in GenerateHtmlDocumentation.cpp.
+bool generateHtmlDocumentation();
+
+#endif  // ANDROID_RS_API_GENERATOR_GENERATOR_H
diff --git a/api/Scanner.cpp b/api/Scanner.cpp
new file mode 100644
index 0000000..660dd24
--- /dev/null
+++ b/api/Scanner.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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 <iostream>
+#include <sstream>
+
+#include "Scanner.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+// Maximum of errors we'll report before bailing out.
+const int MAX_ERRORS = 10;
+
+Scanner::Scanner(const string& fileName, FILE* file)
+    : mFileName(fileName), mFile(file), mLineNumber(0), mTagConsumed(true), mErrorCount(0) {
+}
+
+bool Scanner::atEnd() {
+    return (mTagConsumed && feof(mFile)) || mErrorCount > MAX_ERRORS;
+}
+
+int Scanner::getChar() {
+    int c = fgetc(mFile);
+    if (c == '\n') {
+        mLineNumber++;
+    }
+    return c;
+}
+
+void Scanner::readUpTo(char delimiter, string* segment) {
+    for (;;) {
+        int c = getChar();
+        if (c == EOF || c == '\n') {
+            break;
+        }
+        segment->push_back((char)c);
+        if (c == delimiter) {
+            break;
+        }
+    }
+}
+
+void Scanner::readRestOfLine(string* segment) {
+    for (;;) {
+        int c = getChar();
+        if (c == EOF || c == '\n') {
+            return;
+        }
+        segment->push_back((char)c);
+    }
+}
+
+bool Scanner::getNextEntry() {
+    mTag.clear();
+    mValue.clear();
+    for (;;) {
+        int c = getChar();
+        if (c == EOF) {
+            return false;
+        }
+        if (c == '#') {
+            // Skip the comment
+            string comment;
+            readRestOfLine(&comment);
+            continue;
+        }
+        if (c == ' ') {
+            readRestOfLine(&mValue);
+            break;
+        } else if (c == '\n') {
+            break;
+        } else {
+            mTag = c;
+            readUpTo(':', &mTag);
+            readRestOfLine(&mValue);
+            trimSpaces(&mValue);
+            break;
+        }
+    }
+    return true;
+}
+
+ostream& Scanner::error() {
+    return error(mLineNumber);
+}
+
+ostream& Scanner::error(int lineNumber) {
+    if (++mErrorCount <= MAX_ERRORS) {
+        cerr << mFileName << ":" << lineNumber << ": error: ";
+    }
+    return cerr;
+}
+
+void Scanner::skipBlankEntries() {
+    while (findOptionalTag("")) {
+        if (!mValue.empty()) {
+            error() << "Unexpected: \" " << mValue << "\".\n";
+        }
+    }
+}
+
+bool Scanner::findTag(const char* tag) {
+    bool found = findOptionalTag(tag);
+    if (!found) {
+        error() << "Found \"" << mTag << "\" while looking for \"" << tag << "\".\n";
+    }
+    mTagConsumed = true;
+    return found;
+}
+
+bool Scanner::findOptionalTag(const char* tag) {
+    if (mTagConsumed) {
+        if (!getNextEntry()) {
+            return false;
+        }
+    }
+    mTagConsumed = (mTag == tag);
+    return mTagConsumed;
+}
+
+void Scanner::checkNoValue() {
+    if (!mValue.empty()) {
+        error() << "Did not expect \"" << mValue << "\" after \"" << mTag << "\".\n";
+    }
+}
+
+void Scanner::parseDocumentation(string* s, string* documentation) {
+    size_t docStart = s->find(", \"");
+    if (docStart == string::npos) {
+        documentation->erase();
+    } else {
+        size_t first = docStart + 3;
+        size_t last = s->find('\"', first);
+        if (last == string::npos) {
+            error() << "Missing closing double quote\n";
+        }
+        *documentation = s->substr(first, last - first);
+        s->erase(docStart);
+    }
+}
+
+ParameterEntry* Scanner::parseArgString(bool isReturn) {
+    string s = mValue;
+    ParameterEntry* p = new ParameterEntry();
+    parseDocumentation(&s, &p->documentation);
+
+    size_t optionStart = s.find(", ");
+    if (optionStart != string::npos) {
+        p->testOption = s.substr(optionStart + 2);
+        s.erase(optionStart);
+    }
+
+    trimSpaces(&s);
+    if (!isReturn) {
+        size_t nameStart = s.rfind(' ');
+        if (nameStart == string::npos) {
+            error() << "Missing variable name\n";
+        } else {
+            p->name = s.substr(nameStart + 1);
+            s.erase(nameStart);
+            if (p->name.find('*') != string::npos) {
+                error() << "The '*' should be attached to the type\n";
+            }
+        }
+    }
+
+    if (s == "void" && !isReturn) {
+        error() << "void is only allowed for ret:\n";
+    }
+    p->type = s;
+    p->lineNumber = mLineNumber;
+    return p;
+}
diff --git a/api/Scanner.h b/api/Scanner.h
new file mode 100644
index 0000000..593ff49
--- /dev/null
+++ b/api/Scanner.h
@@ -0,0 +1,102 @@
+/*
+ * 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_RS_API_GENERATOR_SCANNER_H
+#define ANDROID_RS_API_GENERATOR_SCANNER_H
+
+#include <fstream>
+#include <string>
+
+class ParameterEntry;
+
+class Scanner {
+private:
+    std::string mFileName;
+    // The file being parsed
+    FILE* mFile;
+    // The line number of the current entry.
+    int mLineNumber;
+    // The tag of the current entry to be processed.  See FindTag().
+    std::string mTag;
+    // The value of this entry.  See FindTag().
+    std::string mValue;
+    // Was the current tag processed?
+    bool mTagConsumed;
+    // Number of errors encountered.
+    int mErrorCount;
+
+    /* Returns the next character from the file, incrementing the line count
+     * if \n is found.
+     */
+    int getChar();
+    /* Reads from the file, adding the characters to "segment" until
+     * the delimiter is found, a new line, or the eof.  The delimiter is added.
+     */
+    void readUpTo(char delimiter, std::string* segment);
+    /* Reads from the file, adding the characters to "segment" until
+     * the end of the line.
+     */
+    void readRestOfLine(std::string* segment);
+
+    /* Finds the next line that's not a comment (a line that starts with #).
+     * This line is parsed into a tag and a value.
+     * A line that starts with a space (or is empty) is considered to have
+     * a null tag and all but the first character are the value.
+     * Lines that start with a non-space charcter should have a ": " to
+     * separate the tag from the value.
+     * Returns false if no more entries.
+     */
+    bool getNextEntry();
+
+public:
+    Scanner(const std::string& fileName, FILE* file);
+    bool atEnd();
+    std::string getValue() { return mValue; }
+    std::string getNextTag() {
+        mTagConsumed = true;
+        return mTag;
+    }
+
+    // Skips over blank entries, reporting errors that start with a space.
+    void skipBlankEntries();
+    /* Finds the next unprocessed tag.  This entry should start with the specified tag.
+     * Returns false if the tag is not found and prints an error.
+     */
+    bool findTag(const char* tag);
+    // Same as findTag but does not print an error if the tag is not found.
+    bool findOptionalTag(const char* tag);
+    // Verifies there's no value.
+    void checkNoValue();
+
+    std::ostream& error();
+    std::ostream& error(int lineNumber);
+
+    /* Removes an optional double quoted "documentation" found at the end of a line.
+     * Erases that documention from the input string.
+     */
+    void parseDocumentation(std::string* s, std::string* documentation);
+    /* Parse an arg: definition.  It's of the form:
+     *    type[*] name [, test_option] [, "documentation"]
+     * The type and name are required.  The * indicates it's an output parameter.
+     * The test_option specifiies restrictions on values used when generating the test cases.
+     * It's one of range(), compatible(), conditional(), above().
+     * The documentation is enclosed in double quotes.
+     */
+    ParameterEntry* parseArgString(bool isReturn);
+    bool getErrorCount() const { return mErrorCount; }
+};
+
+#endif  // ANDROID_RS_API_GENERATOR_SCANNER_H
diff --git a/api/Specification.cpp b/api/Specification.cpp
new file mode 100644
index 0000000..36f406c
--- /dev/null
+++ b/api/Specification.cpp
@@ -0,0 +1,809 @@
+/*
+ * 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 <stdio.h>
+#include <cctype>
+#include <cstdlib>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <strings.h>
+
+#include "Generator.h"
+#include "Scanner.h"
+#include "Specification.h"
+#include "Utilities.h"
+
+using namespace std;
+
+// API level when RenderScript was added.
+const int MIN_API_LEVEL = 9;
+
+const NumericalType TYPES[] = {
+            {"f16", "FLOAT_16", "half", "half", FLOATING_POINT, 11, 5},
+            {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8},
+            {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11},
+            {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0},
+            {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0},
+            {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0},
+            {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0},
+            {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0},
+            {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0},
+            {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0},
+            {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0},
+};
+
+const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]);
+
+const char BASE_URL[] = "http://developer.android.com/reference/android/graphics/drawable/";
+
+// The singleton of the collected information of all the spec files.
+SystemSpecification systemSpecification;
+
+// Returns the index in TYPES for the provided cType
+static int findCType(const string& cType) {
+    for (int i = 0; i < NUM_TYPES; i++) {
+        if (cType == TYPES[i].cType) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+/* Converts a string like "u8, u16" to a vector of "ushort", "uint".
+ * For non-numerical types, we don't need to convert the abbreviation.
+ */
+static vector<string> convertToTypeVector(const string& input) {
+    // First convert the string to an array of strings.
+    vector<string> entries;
+    stringstream stream(input);
+    string entry;
+    while (getline(stream, entry, ',')) {
+        trimSpaces(&entry);
+        entries.push_back(entry);
+    }
+
+    /* Second, we look for present numerical types. We do it this way
+     * so the order of numerical types is always the same, no matter
+     * how specified in the spec file.
+     */
+    vector<string> result;
+    for (auto t : TYPES) {
+        for (auto i = entries.begin(); i != entries.end(); ++i) {
+            if (*i == t.specType) {
+                result.push_back(t.cType);
+                entries.erase(i);
+                break;
+            }
+        }
+    }
+
+    // Add the remaining; they are not numerical types.
+    for (auto s : entries) {
+        result.push_back(s);
+    }
+
+    return result;
+}
+
+void ParameterDefinition::parseParameterDefinition(const string& type, const string& name,
+                                                   const string& testOption, int lineNumber,
+                                                   bool isReturn, Scanner* scanner) {
+    rsType = type;
+    specName = name;
+
+    // Determine if this is an output.
+    isOutParameter = isReturn || charRemoved('*', &rsType);
+
+    // Extract the vector size out of the type.
+    int last = rsType.size() - 1;
+    char lastChar = rsType[last];
+    if (lastChar >= '0' && lastChar <= '9') {
+        rsBaseType = rsType.substr(0, last);
+        mVectorSize = lastChar;
+    } else {
+        rsBaseType = rsType;
+        mVectorSize = "1";
+    }
+    if (mVectorSize == "3") {
+        vectorWidth = "4";
+    } else {
+        vectorWidth = mVectorSize;
+    }
+
+    /* Create variable names to be used in the java and .rs files.  Because x and
+     * y are reserved in .rs files, we prefix variable names with "in" or "out".
+     */
+    if (isOutParameter) {
+        variableName = "out";
+        if (!specName.empty()) {
+            variableName += capitalize(specName);
+        } else if (!isReturn) {
+            scanner->error(lineNumber) << "Should have a name.\n";
+        }
+    } else {
+        variableName = "in";
+        if (specName.empty()) {
+            scanner->error(lineNumber) << "Should have a name.\n";
+        }
+        variableName += capitalize(specName);
+    }
+    rsAllocName = "gAlloc" + capitalize(variableName);
+    javaAllocName = variableName;
+    javaArrayName = "array" + capitalize(javaAllocName);
+
+    // Process the option.
+    undefinedIfOutIsNan = false;
+    compatibleTypeIndex = -1;
+    if (!testOption.empty()) {
+        if (testOption.compare(0, 6, "range(") == 0) {
+            size_t pComma = testOption.find(',');
+            size_t pParen = testOption.find(')');
+            if (pComma == string::npos || pParen == string::npos) {
+                scanner->error(lineNumber) << "Incorrect range " << testOption << "\n";
+            } else {
+                minValue = testOption.substr(6, pComma - 6);
+                maxValue = testOption.substr(pComma + 1, pParen - pComma - 1);
+            }
+        } else if (testOption.compare(0, 6, "above(") == 0) {
+            size_t pParen = testOption.find(')');
+            if (pParen == string::npos) {
+                scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
+            } else {
+                smallerParameter = testOption.substr(6, pParen - 6);
+            }
+        } else if (testOption.compare(0, 11, "compatible(") == 0) {
+            size_t pParen = testOption.find(')');
+            if (pParen == string::npos) {
+                scanner->error(lineNumber) << "Incorrect testOption " << testOption << "\n";
+            } else {
+                compatibleTypeIndex = findCType(testOption.substr(11, pParen - 11));
+            }
+        } else if (testOption.compare(0, 11, "conditional") == 0) {
+            undefinedIfOutIsNan = true;
+        } else {
+            scanner->error(lineNumber) << "Unrecognized testOption " << testOption << "\n";
+        }
+    }
+
+    typeIndex = findCType(rsBaseType);
+    isFloatType = false;
+    if (typeIndex >= 0) {
+        javaBaseType = TYPES[typeIndex].javaType;
+        specType = TYPES[typeIndex].specType;
+        isFloatType = TYPES[typeIndex].exponentBits > 0;
+    }
+    if (!minValue.empty()) {
+        if (typeIndex < 0 || TYPES[typeIndex].kind != FLOATING_POINT) {
+            scanner->error(lineNumber) << "range(,) is only supported for floating point\n";
+        }
+    }
+}
+
+void VersionInfo::scan(Scanner* scanner) {
+    if (scanner->findOptionalTag("version:")) {
+        const string s = scanner->getValue();
+        sscanf(s.c_str(), "%i %i", &minVersion, &maxVersion);
+        if (minVersion && minVersion < MIN_API_LEVEL) {
+            scanner->error() << "Minimum version must >= 9\n";
+        }
+        if (minVersion == MIN_API_LEVEL) {
+            minVersion = 0;
+        }
+        if (maxVersion && maxVersion < MIN_API_LEVEL) {
+            scanner->error() << "Maximum version must >= 9\n";
+        }
+    }
+    if (scanner->findOptionalTag("size:")) {
+        sscanf(scanner->getValue().c_str(), "%i", &intSize);
+    }
+}
+
+Definition::Definition(const std::string& name, SpecFile* specFile) : mName(name), mHidden(false) {
+    mSpecFileName = specFile->getSpecFileName();
+    mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + name;
+}
+
+void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence) {
+    if (scanner->findOptionalTag("hidden:")) {
+        scanner->checkNoValue();
+        mHidden = true;
+    }
+    if (firstOccurence) {
+        if (scanner->findTag("summary:")) {
+            mSummary = scanner->getValue();
+        }
+        if (scanner->findTag("description:")) {
+            scanner->checkNoValue();
+            while (scanner->findOptionalTag("")) {
+                mDescription.push_back(scanner->getValue());
+            }
+        }
+    } else if (scanner->findOptionalTag("summary:")) {
+        scanner->error() << "Only the first specification should have a summary.\n";
+    }
+}
+
+Constant::~Constant() {
+    for (auto i : mSpecifications) {
+        delete i;
+    }
+}
+
+Type::~Type() {
+    for (auto i : mSpecifications) {
+        delete i;
+    }
+}
+
+Function::Function(const string& name, SpecFile* specFile) : Definition(name, specFile) {
+    mCapitalizedName = capitalize(mName);
+}
+
+Function::~Function() {
+    for (auto i : mSpecifications) {
+        delete i;
+    }
+}
+
+bool Function::someParametersAreDocumented() const {
+    for (auto p : mParameters) {
+        if (!p->documentation.empty()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void Function::addParameter(ParameterEntry* entry, Scanner* scanner) {
+    for (auto i : mParameters) {
+        if (i->name == entry->name) {
+            // It's a duplicate.
+            if (!entry->documentation.empty()) {
+                scanner->error(entry->lineNumber)
+                            << "Only the first occurence of an arg should have the "
+                               "documentation.\n";
+            }
+            return;
+        }
+    }
+    mParameters.push_back(entry);
+}
+
+void Function::addReturn(ParameterEntry* entry, Scanner* scanner) {
+    if (entry->documentation.empty()) {
+        return;
+    }
+    if (!mReturnDocumentation.empty()) {
+        scanner->error() << "ret: should be documented only for the first variant\n";
+    }
+    mReturnDocumentation = entry->documentation;
+}
+
+void Specification::scanVersionInfo(Scanner* scanner) {
+    mVersionInfo.scan(scanner);
+}
+
+void ConstantSpecification::scanConstantSpecification(Scanner* scanner, SpecFile* specFile) {
+    string name = scanner->getValue();
+
+    bool created = false;
+    Constant* constant = specFile->findOrCreateConstant(name, &created);
+
+    ConstantSpecification* spec = new ConstantSpecification();
+    constant->addSpecification(spec);
+
+    spec->scanVersionInfo(scanner);
+    if (scanner->findTag("value:")) {
+        spec->mValue = scanner->getValue();
+    }
+    constant->scanDocumentationTags(scanner, created);
+
+    scanner->findTag("end:");
+}
+
+void TypeSpecification::scanTypeSpecification(Scanner* scanner, SpecFile* specFile) {
+    string name = scanner->getValue();
+
+    bool created = false;
+    Type* type = specFile->findOrCreateType(name, &created);
+
+    TypeSpecification* spec = new TypeSpecification();
+    type->addSpecification(spec);
+
+    spec->scanVersionInfo(scanner);
+    if (scanner->findOptionalTag("simple:")) {
+        spec->mKind = SIMPLE;
+        spec->mSimpleType = scanner->getValue();
+    }
+    if (scanner->findOptionalTag("struct:")) {
+        spec->mKind = STRUCT;
+        spec->mStructName = scanner->getValue();
+        while (scanner->findOptionalTag("field:")) {
+            string s = scanner->getValue();
+            string comment;
+            scanner->parseDocumentation(&s, &comment);
+            spec->mFields.push_back(s);
+            spec->mFieldComments.push_back(comment);
+        }
+        if (scanner->findOptionalTag("attrib:")) {
+            spec->mAttrib = scanner->getValue();
+        }
+    }
+    if (scanner->findOptionalTag("enum:")) {
+        spec->mKind = ENUM;
+        spec->mEnumName = scanner->getValue();
+        while (scanner->findOptionalTag("value:")) {
+            string s = scanner->getValue();
+            string comment;
+            scanner->parseDocumentation(&s, &comment);
+            spec->mValues.push_back(s);
+            spec->mValueComments.push_back(comment);
+        }
+    }
+    type->scanDocumentationTags(scanner, created);
+
+    scanner->findTag("end:");
+}
+
+FunctionSpecification::~FunctionSpecification() {
+    for (auto i : mParameters) {
+        delete i;
+    }
+    delete mReturn;
+    for (auto i : mPermutations) {
+        delete i;
+    }
+}
+
+string FunctionSpecification::expandString(string s,
+                                           int replacementIndexes[MAX_REPLACEABLES]) const {
+    if (mReplaceables.size() > 0) {
+        s = stringReplace(s, "#1", mReplaceables[0][replacementIndexes[0]]);
+    }
+    if (mReplaceables.size() > 1) {
+        s = stringReplace(s, "#2", mReplaceables[1][replacementIndexes[1]]);
+    }
+    if (mReplaceables.size() > 2) {
+        s = stringReplace(s, "#3", mReplaceables[2][replacementIndexes[2]]);
+    }
+    if (mReplaceables.size() > 3) {
+        s = stringReplace(s, "#4", mReplaceables[3][replacementIndexes[3]]);
+    }
+    return s;
+}
+
+void FunctionSpecification::expandStringVector(const vector<string>& in,
+                                               int replacementIndexes[MAX_REPLACEABLES],
+                                               vector<string>* out) const {
+    out->clear();
+    for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
+        out->push_back(expandString(*iter, replacementIndexes));
+    }
+}
+
+void FunctionSpecification::createPermutations(Function* function, Scanner* scanner) {
+    int start[MAX_REPLACEABLES];
+    int end[MAX_REPLACEABLES];
+    for (int i = 0; i < MAX_REPLACEABLES; i++) {
+        if (i < (int)mReplaceables.size()) {
+            start[i] = 0;
+            end[i] = mReplaceables[i].size();
+        } else {
+            start[i] = -1;
+            end[i] = 0;
+        }
+    }
+    int replacementIndexes[MAX_REPLACEABLES];
+    // TODO: These loops assume that MAX_REPLACEABLES is 4.
+    for (replacementIndexes[3] = start[3]; replacementIndexes[3] < end[3];
+         replacementIndexes[3]++) {
+        for (replacementIndexes[2] = start[2]; replacementIndexes[2] < end[2];
+             replacementIndexes[2]++) {
+            for (replacementIndexes[1] = start[1]; replacementIndexes[1] < end[1];
+                 replacementIndexes[1]++) {
+                for (replacementIndexes[0] = start[0]; replacementIndexes[0] < end[0];
+                     replacementIndexes[0]++) {
+                    auto p = new FunctionPermutation(function, this, replacementIndexes, scanner);
+                    mPermutations.push_back(p);
+                }
+            }
+        }
+    }
+}
+
+string FunctionSpecification::getName(int replacementIndexes[MAX_REPLACEABLES]) const {
+    return expandString(mUnexpandedName, replacementIndexes);
+}
+
+void FunctionSpecification::getReturn(int replacementIndexes[MAX_REPLACEABLES],
+                                      std::string* retType, int* lineNumber) const {
+    *retType = expandString(mReturn->type, replacementIndexes);
+    *lineNumber = mReturn->lineNumber;
+}
+
+void FunctionSpecification::getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES],
+                                     std::string* type, std::string* name, std::string* testOption,
+                                     int* lineNumber) const {
+    ParameterEntry* p = mParameters[index];
+    *type = expandString(p->type, replacementIndexes);
+    *name = p->name;
+    *testOption = expandString(p->testOption, replacementIndexes);
+    *lineNumber = p->lineNumber;
+}
+
+void FunctionSpecification::getInlines(int replacementIndexes[MAX_REPLACEABLES],
+                                       std::vector<std::string>* inlines) const {
+    expandStringVector(mInline, replacementIndexes, inlines);
+}
+
+void FunctionSpecification::parseTest(Scanner* scanner) {
+    const string value = scanner->getValue();
+    if (value == "scalar" || value == "vector" || value == "noverify" || value == "custom" ||
+        value == "none") {
+        mTest = value;
+    } else if (value.compare(0, 7, "limited") == 0) {
+        mTest = "limited";
+        if (value.compare(7, 1, "(") == 0) {
+            size_t pParen = value.find(')');
+            if (pParen == string::npos) {
+                scanner->error() << "Incorrect test: \"" << value << "\"\n";
+            } else {
+                mPrecisionLimit = value.substr(8, pParen - 8);
+            }
+        }
+    } else {
+        scanner->error() << "Unrecognized test option: \"" << value << "\"\n";
+    }
+}
+
+bool FunctionSpecification::hasTests(int versionOfTestFiles) const {
+    if (mVersionInfo.minVersion != 0 && mVersionInfo.minVersion > versionOfTestFiles) {
+        return false;
+    }
+    if (mVersionInfo.maxVersion != 0 && mVersionInfo.maxVersion < versionOfTestFiles) {
+        return false;
+    }
+    if (mTest == "none") {
+        return false;
+    }
+    return true;
+}
+
+void FunctionSpecification::scanFunctionSpecification(Scanner* scanner, SpecFile* specFile) {
+    // Some functions like convert have # part of the name.  Truncate at that point.
+    string name = scanner->getValue();
+    size_t p = name.find('#');
+    if (p != string::npos) {
+        if (p > 0 && name[p - 1] == '_') {
+            p--;
+        }
+        name.erase(p);
+    }
+
+    bool created = false;
+    Function* function = specFile->findOrCreateFunction(name, &created);
+
+    FunctionSpecification* spec = new FunctionSpecification();
+    function->addSpecification(spec);
+
+    spec->mUnexpandedName = scanner->getValue();
+    spec->mTest = "scalar";  // default
+
+    spec->scanVersionInfo(scanner);
+
+    if (scanner->findOptionalTag("attrib:")) {
+        spec->mAttribute = scanner->getValue();
+    }
+    if (scanner->findOptionalTag("w:")) {
+        vector<string> t;
+        if (scanner->getValue().find("1") != string::npos) {
+            t.push_back("");
+        }
+        if (scanner->getValue().find("2") != string::npos) {
+            t.push_back("2");
+        }
+        if (scanner->getValue().find("3") != string::npos) {
+            t.push_back("3");
+        }
+        if (scanner->getValue().find("4") != string::npos) {
+            t.push_back("4");
+        }
+        spec->mReplaceables.push_back(t);
+    }
+
+    while (scanner->findOptionalTag("t:")) {
+        spec->mReplaceables.push_back(convertToTypeVector(scanner->getValue()));
+    }
+
+    if (scanner->findTag("ret:")) {
+        ParameterEntry* p = scanner->parseArgString(true);
+        function->addReturn(p, scanner);
+        spec->mReturn = p;
+    }
+    while (scanner->findOptionalTag("arg:")) {
+        ParameterEntry* p = scanner->parseArgString(false);
+        function->addParameter(p, scanner);
+        spec->mParameters.push_back(p);
+    }
+
+    function->scanDocumentationTags(scanner, created);
+
+    if (scanner->findOptionalTag("inline:")) {
+        scanner->checkNoValue();
+        while (scanner->findOptionalTag("")) {
+            spec->mInline.push_back(scanner->getValue());
+        }
+    }
+    if (scanner->findOptionalTag("test:")) {
+        spec->parseTest(scanner);
+    }
+
+    scanner->findTag("end:");
+
+    spec->createPermutations(function, scanner);
+}
+
+FunctionPermutation::FunctionPermutation(Function* func, FunctionSpecification* spec,
+                                         int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner)
+    : mFunction(func), mReturn(nullptr), mInputCount(0), mOutputCount(0) {
+    // We expand the strings now to make capitalization easier.  The previous code preserved
+    // the #n
+    // markers just before emitting, which made capitalization difficult.
+    mName = spec->getName(replacementIndexes);
+    mNameTrunk = func->getName();
+    mTest = spec->getTest();
+    mPrecisionLimit = spec->getPrecisionLimit();
+    spec->getInlines(replacementIndexes, &mInline);
+
+    mHasFloatAnswers = false;
+    for (size_t i = 0; i < spec->getNumberOfParams(); i++) {
+        string type, name, testOption;
+        int lineNumber = 0;
+        spec->getParam(i, replacementIndexes, &type, &name, &testOption, &lineNumber);
+        ParameterDefinition* def = new ParameterDefinition();
+        def->parseParameterDefinition(type, name, testOption, lineNumber, false, scanner);
+        if (def->isOutParameter) {
+            mOutputCount++;
+        } else {
+            mInputCount++;
+        }
+
+        if (def->typeIndex < 0 && mTest != "none") {
+            scanner->error(lineNumber)
+                        << "Could not find " << def->rsBaseType
+                        << " while generating automated tests.  Use test: none if not needed.\n";
+        }
+        if (def->isOutParameter && def->isFloatType) {
+            mHasFloatAnswers = true;
+        }
+        mParams.push_back(def);
+    }
+
+    string retType;
+    int lineNumber = 0;
+    spec->getReturn(replacementIndexes, &retType, &lineNumber);
+    if (!retType.empty()) {
+        mReturn = new ParameterDefinition();
+        mReturn->parseParameterDefinition(retType, "", "", lineNumber, true, scanner);
+        if (mReturn->isFloatType) {
+            mHasFloatAnswers = true;
+        }
+        mOutputCount++;
+    }
+}
+
+FunctionPermutation::~FunctionPermutation() {
+    for (auto i : mParams) {
+        delete i;
+    }
+    delete mReturn;
+}
+
+SpecFile::SpecFile(const string& specFileName) : mSpecFileName(specFileName) {
+    string core = mSpecFileName;
+    // Remove .spec
+    size_t l = core.length();
+    const char SPEC[] = ".spec";
+    const int SPEC_SIZE = sizeof(SPEC) - 1;
+    const int start = l - SPEC_SIZE;
+    if (start >= 0 && core.compare(start, SPEC_SIZE, SPEC) == 0) {
+        core.erase(start);
+    }
+
+    // The header file name should have the same base but with a ".rsh" extension.
+    mHeaderFileName = core + ".rsh";
+
+    mDetailedDocumentationUrl = BASE_URL;
+    mDetailedDocumentationUrl += core + ".html";
+}
+
+SpecFile::~SpecFile() {
+    for (auto i : mConstantsList) {
+        delete i;
+    }
+    for (auto i : mTypesList) {
+        delete i;
+    }
+    for (auto i : mFunctionsList) {
+        delete i;
+    }
+}
+
+// Read the specification, adding the definitions to the global functions map.
+bool SpecFile::readSpecFile() {
+    FILE* specFile = fopen(mSpecFileName.c_str(), "rt");
+    if (!specFile) {
+        cerr << "Error opening input file: " << mSpecFileName << "\n";
+        return false;
+    }
+
+    Scanner scanner(mSpecFileName, specFile);
+
+    // Scan the header that should start the file.
+    scanner.skipBlankEntries();
+    if (scanner.findTag("header:")) {
+        if (scanner.findTag("summary:")) {
+            mBriefDescription = scanner.getValue();
+        }
+        if (scanner.findTag("description:")) {
+            scanner.checkNoValue();
+            while (scanner.findOptionalTag("")) {
+                mFullDescription.push_back(scanner.getValue());
+            }
+        }
+        if (scanner.findOptionalTag("include:")) {
+            scanner.checkNoValue();
+            while (scanner.findOptionalTag("")) {
+                mVerbatimInclude.push_back(scanner.getValue());
+            }
+        }
+        scanner.findTag("end:");
+    }
+
+    while (1) {
+        scanner.skipBlankEntries();
+        if (scanner.atEnd()) {
+            break;
+        }
+        const string tag = scanner.getNextTag();
+        if (tag == "function:") {
+            FunctionSpecification::scanFunctionSpecification(&scanner, this);
+        } else if (tag == "type:") {
+            TypeSpecification::scanTypeSpecification(&scanner, this);
+        } else if (tag == "constant:") {
+            ConstantSpecification::scanConstantSpecification(&scanner, this);
+        } else {
+            scanner.error() << "Expected function:, type:, or constant:.  Found: " << tag << "\n";
+            return false;
+        }
+    }
+
+    fclose(specFile);
+    return scanner.getErrorCount() == 0;
+}
+
+// Returns the named entry in the map.  Creates it if it's not there.
+template <class T>
+T* findOrCreate(const string& name, list<T*>* list, map<string, T*>* map, bool* created,
+                SpecFile* specFile) {
+    auto iter = map->find(name);
+    if (iter != map->end()) {
+        *created = false;
+        return iter->second;
+    }
+    *created = true;
+    T* f = new T(name, specFile);
+    map->insert(pair<string, T*>(name, f));
+    list->push_back(f);
+    return f;
+}
+
+Constant* SpecFile::findOrCreateConstant(const string& name, bool* created) {
+    return findOrCreate<Constant>(name, &mConstantsList, &mConstantsMap, created, this);
+}
+
+Type* SpecFile::findOrCreateType(const string& name, bool* created) {
+    return findOrCreate<Type>(name, &mTypesList, &mTypesMap, created, this);
+}
+
+Function* SpecFile::findOrCreateFunction(const string& name, bool* created) {
+    return findOrCreate<Function>(name, &mFunctionsList, &mFunctionsMap, created, this);
+}
+
+SystemSpecification::~SystemSpecification() {
+    for (auto i : mSpecFiles) {
+        delete i;
+    }
+}
+
+template <class T>
+static bool addDefinitionToMap(map<string, T*>* map, T* object) {
+    const string& name = object->getName();
+    auto i = map->find(name);
+    if (i != map->end()) {
+        T* existing = i->second;
+        cerr << object->getSpecFileName() << ": Error. " << name << " has already been defined in "
+             << existing->getSpecFileName() << "\n";
+        return false;
+    }
+    (*map)[name] = object;
+    return true;
+}
+
+bool SystemSpecification::readSpecFile(const string& fileName) {
+    SpecFile* spec = new SpecFile(fileName);
+    if (!spec->readSpecFile()) {
+        cerr << fileName << ": Failed to parse.\n";
+        return false;
+    }
+    mSpecFiles.push_back(spec);
+
+    // Store links to the definitions in a global table.
+    bool success = true;
+    for (auto i : spec->getConstantsMap()) {
+        if (!addDefinitionToMap(&mConstants, i.second)) {
+            success = false;
+        }
+    }
+    for (auto i : spec->getTypesMap()) {
+        if (!addDefinitionToMap(&mTypes, i.second)) {
+            success = false;
+        }
+    }
+    for (auto i : spec->getFunctionsMap()) {
+        if (!addDefinitionToMap(&mFunctions, i.second)) {
+            success = false;
+        }
+    }
+
+    return success;
+}
+
+bool SystemSpecification::generateFiles(int versionOfTestFiles) const {
+    bool success = GenerateHeaderFiles() && generateHtmlDocumentation() &&
+                   GenerateTestFiles(versionOfTestFiles);
+    if (success) {
+        cout << "Successfully processed " << mTypes.size() << " types, " << mConstants.size()
+             << " constants, and " << mFunctions.size() << " functions.\n";
+    }
+    return success;
+}
+
+string SystemSpecification::getHtmlAnchor(const string& name) const {
+    Definition* d = nullptr;
+    auto c = mConstants.find(name);
+    if (c != mConstants.end()) {
+        d = c->second;
+    } else {
+        auto t = mTypes.find(name);
+        if (t != mTypes.end()) {
+            d = t->second;
+        } else {
+            auto f = mFunctions.find(name);
+            if (f != mFunctions.end()) {
+                d = f->second;
+            } else {
+                return string();
+            }
+        }
+    }
+    ostringstream stream;
+    stream << "<a href='" << d->getUrl() << "'>" << name << "</a>";
+    return stream.str();
+}
diff --git a/api/Specification.h b/api/Specification.h
new file mode 100644
index 0000000..6146665
--- /dev/null
+++ b/api/Specification.h
@@ -0,0 +1,517 @@
+/*
+ * 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_RS_API_GENERATOR_SPECIFICATION_H
+#define ANDROID_RS_API_GENERATOR_SPECIFICATION_H
+
+// See Generator.cpp for documentation of the .spec file format.
+
+#include <fstream>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+class Constant;
+class ConstantSpecification;
+class Function;
+class FunctionPermutation;
+class FunctionSpecification;
+class SpecFile;
+class Specification;
+class Scanner;
+class SystemSpecification;
+class Type;
+class TypeSpecification;
+
+enum NumberKind { SIGNED_INTEGER, UNSIGNED_INTEGER, FLOATING_POINT };
+
+// Table of type equivalences.
+struct NumericalType {
+    const char* specType;    // Name found in the .spec file
+    const char* rsDataType;  // RS data type
+    const char* cType;       // Type in a C file
+    const char* javaType;    // Type in a Java file
+    NumberKind kind;
+    /* For integers, number of bits of the number, excluding the sign bit.
+     * For floats, number of implied bits of the mantissa.
+     */
+    int significantBits;
+    // For floats, number of bits of the exponent.  0 for integer types.
+    int exponentBits;
+};
+
+/* Corresponds to one parameter line in a .spec file.  These will be parsed when
+ * we instantiate the FunctionPermutation(s) that correspond to one FunctionSpecification.
+ */
+struct ParameterEntry {
+    std::string type;
+    std::string name;
+    /* Optional information on how to generate test values for this parameter.  Can be:
+     * - range(low, high): Generates values between these two limits only.
+     * - above(other_parameter): The values must be greater than those of the named parameter.
+     *       Used for clamp.
+     * - compatible(type): The values must also be fully representable in the specified type.
+     * - conditional: Don't verify this value the function return NaN.
+     */
+    std::string testOption;
+    std::string documentation;
+    int lineNumber;
+};
+
+/* Information about a parameter to a function.  The values of all the fields should only be set by
+ * parseParameterDefinition.
+ */
+struct ParameterDefinition {
+    std::string rsType;        // The Renderscript type, e.g. "uint3"
+    std::string rsBaseType;    // As above but without the number, e.g. "uint"
+    std::string javaBaseType;  // The type we need to declare in Java, e.g. "unsigned int"
+    std::string specType;      // The type found in the spec, e.g. "f16"
+    bool isFloatType;          // True if it's a floating point value
+    /* The number of entries in the vector.  It should be either "1", "2", "3", or "4".  It's also
+     * "1" for scalars.
+     */
+    std::string mVectorSize;
+    /* The space the vector takes in an array.  It's the same as the vector size, except for size
+     * "3", where the width is "4".
+     */
+    std::string vectorWidth;
+
+    std::string specName;       // e.g. x, as found in the spec file
+    std::string variableName;   // e.g. inX, used both in .rs and .java
+    std::string rsAllocName;    // e.g. gAllocInX
+    std::string javaAllocName;  // e.g. inX
+    std::string javaArrayName;  // e.g. arrayInX
+
+    // If non empty, the mininum and maximum values to be used when generating the test data.
+    std::string minValue;
+    std::string maxValue;
+    /* If non empty, contains the name of another parameter that should be smaller or equal to this
+     * parameter, i.e.  value(smallerParameter) <= value(this).  This is used when testing clamp.
+     */
+    std::string smallerParameter;
+
+    bool isOutParameter;       // True if this parameter returns data from the script.
+    bool undefinedIfOutIsNan;  // If true, we don't validate if 'out' is NaN.
+
+    int typeIndex;            // Index in the TYPES array. Negative if not found in the array.
+    int compatibleTypeIndex;  // Index in TYPES for which the test data must also fit.
+
+    /* Fill this object from the type, name, and testOption.
+     * isReturn is true if we're processing the "return:"
+     */
+    void parseParameterDefinition(const std::string& type, const std::string& name,
+                                  const std::string& testOption, int lineNumber, bool isReturn,
+                                  Scanner* scanner);
+};
+
+struct VersionInfo {
+    /* The range of versions a specification applies to. Zero if there's no restriction,
+     * so an API that became available at 12 and is still valid would have min:12 max:0.
+     * If non zero, both versions should be at least 9, the API level that introduced
+     * RenderScript.
+     */
+    int minVersion;
+    int maxVersion;
+    // Either 0, 32 or 64.  If 0, this definition is valid for both 32 and 64 bits.
+    int intSize;
+
+    VersionInfo() : minVersion(0), maxVersion(0), intSize(0) {}
+    void scan(Scanner* scanner);
+};
+
+// We have three type of definitions
+class Definition {
+protected:
+    std::string mName;
+    std::string mSpecFileName;
+
+    bool mHidden;                           // True if it should not be documented
+    std::string mSummary;                   // A one-line description
+    std::vector<std::string> mDescription;  // The comments to be included in the header
+    std::string mUrl;                       // The URL of the detailed documentation
+
+public:
+    Definition(const std::string& name, SpecFile* specFile);
+
+    std::string getName() const { return mName; }
+    std::string getSpecFileName() const { return mSpecFileName; }
+
+    bool hidden() const { return mHidden; }
+    std::string getSummary() const { return mSummary; }
+    const std::vector<std::string>& getDescription() const { return mDescription; }
+    std::string getUrl() const { return mUrl; }
+
+    void scanDocumentationTags(Scanner* scanner, bool firstOccurence);
+};
+
+/* Represents a constant, like M_PI.  This is a grouping of the version specific specifications.
+ * We'll only have one instance of Constant for each name.
+ */
+class Constant : public Definition {
+private:
+    std::vector<ConstantSpecification*> mSpecifications;  // Owned
+
+public:
+    Constant(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {}
+    ~Constant();
+
+    const std::vector<ConstantSpecification*> getSpecifications() const { return mSpecifications; }
+    // This method should only be called by the scanning code.
+    void addSpecification(ConstantSpecification* spec) { mSpecifications.push_back(spec); }
+};
+
+/* Represents a type, like "float4".  This is a grouping of the version specific specifications.
+ * We'll only have one instance of Type for each name.
+ */
+class Type : public Definition {
+private:
+    std::vector<TypeSpecification*> mSpecifications;  // Owned
+
+public:
+    Type(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {}
+    ~Type();
+
+    const std::vector<TypeSpecification*> getSpecifications() const { return mSpecifications; }
+    // This method should only be called by the scanning code.
+    void addSpecification(TypeSpecification* spec) { mSpecifications.push_back(spec); }
+};
+
+/* Represents a function, like "clamp".  Even though the spec file contains many entries for clamp,
+ * we'll only have one clamp instance.
+ */
+class Function : public Definition {
+private:
+    // mName in the base class contains the lower case name, e.g. native_log
+    std::string mCapitalizedName;  // The capitalized name, e.g. NativeLog
+
+    // The unique parameters between all the specifications.  NOT OWNED.
+    std::vector<ParameterEntry*> mParameters;
+    std::string mReturnDocumentation;
+
+    std::vector<FunctionSpecification*> mSpecifications;  // Owned
+
+public:
+    Function(const std::string& name, SpecFile* specFile);
+    ~Function();
+
+    std::string getCapitalizedName() const { return mCapitalizedName; }
+    const std::vector<ParameterEntry*>& getParameters() const { return mParameters; }
+    std::string getReturnDocumentation() const { return mReturnDocumentation; }
+    const std::vector<FunctionSpecification*> getSpecifications() const { return mSpecifications; }
+
+    bool someParametersAreDocumented() const;
+
+    // The following methods should only be called by the scanning code.
+    void addParameter(ParameterEntry* entry, Scanner* scanner);
+    void addReturn(ParameterEntry* entry, Scanner* scanner);
+    void addSpecification(FunctionSpecification* spec) { mSpecifications.push_back(spec); }
+};
+
+/* Base class for TypeSpecification, ConstantSpecification, and FunctionSpecification.
+ * A specification can be specific to a range of RenderScript version or 32bits vs 64 bits.
+ * This base class contains code to parse and store this version information.
+ */
+class Specification {
+protected:
+    VersionInfo mVersionInfo;
+    void scanVersionInfo(Scanner* scanner);
+
+public:
+    VersionInfo getVersionInfo() const { return mVersionInfo; }
+};
+
+/* Defines one of the many variations of a constant.  There's a one to one correspondance between
+ * ConstantSpecification objects and entries in the spec file.
+ */
+class ConstantSpecification : public Specification {
+private:
+    std::string mValue;  // E.g. "3.1415"
+public:
+    std::string getValue() const { return mValue; }
+
+    // Parse a constant specification and add it to specFile.
+    static void scanConstantSpecification(Scanner* scanner, SpecFile* specFile);
+};
+
+enum TypeKind {
+    SIMPLE,
+    STRUCT,
+    ENUM,
+};
+
+/* Defines one of the many variations of a type.  There's a one to one correspondance between
+ * TypeSpecification objects and entries in the spec file.
+ */
+class TypeSpecification : public Specification {
+private:
+    TypeKind mKind;  // The kind of type specification
+
+    // If mKind is SIMPLE:
+    std::string mSimpleType;  // The definition of the type
+
+    // If mKind is STRUCT:
+    std::string mStructName;                  // The name found after the struct keyword
+    std::vector<std::string> mFields;         // One entry per struct field
+    std::vector<std::string> mFieldComments;  // One entry per struct field
+    std::string mAttrib;                      // Some structures may have attributes
+
+    // If mKind is ENUM:
+    std::string mEnumName;                    // The name found after the enum keyword
+    std::vector<std::string> mValues;         // One entry per enum value
+    std::vector<std::string> mValueComments;  // One entry per enum value
+public:
+    TypeKind getKind() const { return mKind; }
+    std::string getSimpleType() const { return mSimpleType; }
+    std::string getStructName() const { return mStructName; }
+    const std::vector<std::string>& getFields() const { return mFields; }
+    const std::vector<std::string>& getFieldComments() const { return mFieldComments; }
+    std::string getAttrib() const { return mAttrib; }
+    std::string getEnumName() const { return mEnumName; }
+    const std::vector<std::string>& getValues() const { return mValues; }
+    const std::vector<std::string>& getValueComments() const { return mValueComments; }
+
+    // Parse a type specification and add it to specFile.
+    static void scanTypeSpecification(Scanner* scanner, SpecFile* specFile);
+};
+
+// Maximum number of placeholders (like #1, #2) in function specifications.
+const int MAX_REPLACEABLES = 4;
+
+/* Defines one of the many variations of the function.  There's a one to one correspondance between
+ * FunctionSpecification objects and entries in the spec file.  Some of the strings that are parts
+ * of a FunctionSpecification can include placeholders, which are "#1", "#2", "#3", and "#4".  We'll
+ * replace these by values before generating the files.
+ */
+class FunctionSpecification : public Specification {
+private:
+    /* How to test.  One of:
+     * "scalar": Generate test code that checks entries of each vector indepently.  E.g. for
+     *           sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times.
+     * "limited": Like "scalar" but we don't generate extreme values.  This is not currently
+     *            enabled as we were generating to many errors.
+     * "custom": Like "scalar" but instead of calling CoreMathVerifier.computeXXX() to compute
+     *           the expected value, we call instead CoreMathVerifier.verifyXXX().  This method
+     *           returns a string that contains the error message, null if there's no error.
+     * "vector": Generate test code that calls the CoreMathVerifier only once for each vector.
+     *           This is useful for APIs like dot() or length().
+     * "noverify": Generate test code that calls the API but don't verify the returned value.
+     *             This can discover unresolved references.
+     */
+    std::string mTest;
+    std::string mAttribute;       // Function attributes.
+    std::string mPrecisionLimit;  // Maximum precision required when checking output of this
+                                  // function.
+
+    // The vectors of values with which we'll replace #1, #2, ...
+    std::vector<std::vector<std::string> > mReplaceables;
+
+    /* The collection of permutations for this specification, i.e. this class instantianted
+     * for specific values of #1, #2, etc.  Owned.
+     */
+    std::vector<FunctionPermutation*> mPermutations;
+
+    // The following fields may contain placeholders that will be replaced using the mReplaceables.
+
+    /* As of this writing, convert_... is the only function with #1 in its name.
+     * The related Function object contains the name of the function without #n, e.g. convert.
+     * This is the name with the #, e.g. convert_#1_#2
+     */
+    std::string mUnexpandedName;
+    ParameterEntry* mReturn;  // The return type. The name should be empty.  Owned.
+    int mReturnLineNumber;
+    std::vector<ParameterEntry*> mParameters;  // The parameters.  Owned.
+    std::vector<std::string> mInline;          // The inline code to be included in the header
+
+    /* Substitute the placeholders in the strings (e.g. #1, #2, ...) by the corresponding
+     * entries in mReplaceables.  indexOfReplaceable1 selects with value to use for #1,
+     * same for 2, 3, and 4.
+     */
+    std::string expandString(std::string s, int indexOfReplaceable[MAX_REPLACEABLES]) const;
+    void expandStringVector(const std::vector<std::string>& in,
+                            int replacementIndexes[MAX_REPLACEABLES],
+                            std::vector<std::string>* out) const;
+
+    // Fill the mPermutations field.
+    void createPermutations(Function* function, Scanner* scanner);
+
+public:
+    FunctionSpecification() : mReturn(nullptr) {}
+    ~FunctionSpecification();
+
+    std::string getAttribute() const { return mAttribute; }
+    std::string getTest() const { return mTest; }
+    std::string getPrecisionLimit() const { return mPrecisionLimit; }
+
+    const std::vector<FunctionPermutation*>& getPermutations() const { return mPermutations; }
+
+    std::string getName(int replacementIndexes[MAX_REPLACEABLES]) const;
+    void getReturn(int replacementIndexes[MAX_REPLACEABLES], std::string* retType,
+                   int* lineNumber) const;
+    size_t getNumberOfParams() const { return mParameters.size(); }
+    void getParam(size_t index, int replacementIndexes[MAX_REPLACEABLES], std::string* type,
+                  std::string* name, std::string* testOption, int* lineNumber) const;
+    void getInlines(int replacementIndexes[MAX_REPLACEABLES],
+                    std::vector<std::string>* inlines) const;
+
+    // Parse the "test:" line.
+    void parseTest(Scanner* scanner);
+
+    // Return true if we need to generate tests for this function.
+    bool hasTests(int versionOfTestFiles) const;
+
+    // Parse a function specification and add it to specFile.
+    static void scanFunctionSpecification(Scanner* scanner, SpecFile* specFile);
+};
+
+/* A concrete version of a function specification, where all placeholders have been replaced by
+ * actual values.
+ */
+class FunctionPermutation {
+private:
+    Function* mFunction;  // NOT OWNED.
+
+    // These are the expanded version of those found on FunctionSpecification
+    std::string mName;
+    std::string mNameTrunk;  // The name without any expansion, e.g. convert
+    std::string mTest;       // How to test.  One of "scalar", "vector", "noverify", "limited", and
+                             // "none".
+    std::string mPrecisionLimit;  // Maximum precision required when checking output of this
+                                  // function.
+
+    // The parameters of the function.  This does not include the return type.  Owned.
+    std::vector<ParameterDefinition*> mParams;
+    // The return type.  nullptr if a void function.  Owned.
+    ParameterDefinition* mReturn;
+
+    // The number of input and output parameters.  mOutputCount counts the return type.
+    int mInputCount;
+    int mOutputCount;
+
+    // Whether one of the output parameters is a float.
+    bool mHasFloatAnswers;
+
+    // The inline code that implements this function.  Will be empty if not an inline.
+    std::vector<std::string> mInline;
+
+public:
+    FunctionPermutation(Function* function, FunctionSpecification* specification,
+                        int replacementIndexes[MAX_REPLACEABLES], Scanner* scanner);
+    ~FunctionPermutation();
+
+    std::string getName() const { return mName; }
+    std::string getNameTrunk() const { return mNameTrunk; }
+    std::string getTest() const { return mTest; }
+    std::string getPrecisionLimit() const { return mPrecisionLimit; }
+
+    const std::vector<std::string> getInline() const { return mInline; }
+    const ParameterDefinition* getReturn() const { return mReturn; }
+    int getInputCount() const { return mInputCount; }
+    int getOutputCount() const { return mOutputCount; }
+    bool hasFloatAnswers() const { return mHasFloatAnswers; }
+
+    const std::vector<ParameterDefinition*> getParams() const { return mParams; }
+};
+
+// An entire spec file and the methods to process it.
+class SpecFile {
+private:
+    std::string mSpecFileName;
+    std::string mHeaderFileName;
+    std::string mDetailedDocumentationUrl;
+    std::string mBriefDescription;
+    std::vector<std::string> mFullDescription;
+    // Text to insert as-is in the generated header.
+    std::vector<std::string> mVerbatimInclude;
+
+    /* The constants, types, and functions declared in this file,
+     * in the order they are found in the file.  This matters for
+     * header generation, as some types and inline functions depend
+     * on each other.
+     *
+     * Pointers are owned by this list.
+     */
+    std::list<Constant*> mConstantsList;
+    std::list<Type*> mTypesList;
+    std::list<Function*> mFunctionsList;
+
+    // Quick way to find entries in the previous lists.  Pointers not owned.
+    std::map<std::string, Constant*> mConstantsMap;
+    std::map<std::string, Type*> mTypesMap;
+    std::map<std::string, Function*> mFunctionsMap;
+
+public:
+    explicit SpecFile(const std::string& specFileName);
+    ~SpecFile();
+
+    std::string getSpecFileName() const { return mSpecFileName; }
+    std::string getHeaderFileName() const { return mHeaderFileName; }
+    std::string getDetailedDocumentationUrl() const { return mDetailedDocumentationUrl; }
+    const std::string getBriefDescription() const { return mBriefDescription; }
+    const std::vector<std::string>& getFullDescription() const { return mFullDescription; }
+    const std::vector<std::string>& getVerbatimInclude() const { return mVerbatimInclude; }
+
+    const std::list<Constant*>& getConstantsList() const { return mConstantsList; }
+    const std::list<Type*>& getTypesList() const { return mTypesList; }
+    const std::list<Function*>& getFunctionsList() const { return mFunctionsList; }
+
+    const std::map<std::string, Constant*>& getConstantsMap() const { return mConstantsMap; }
+    const std::map<std::string, Type*>& getTypesMap() const { return mTypesMap; }
+    const std::map<std::string, Function*>& getFunctionsMap() const { return mFunctionsMap; }
+
+    bool readSpecFile();
+
+    Constant* findOrCreateConstant(const std::string& name, bool* created);
+    Type* findOrCreateType(const std::string& name, bool* created);
+    Function* findOrCreateFunction(const std::string& name, bool* created);
+};
+
+// The collection of all the spec files.
+class SystemSpecification {
+private:
+    std::vector<SpecFile*> mSpecFiles;
+
+    /* Entries in the table of contents.  We accumulate them in a map to sort them.
+     * Pointers are not owned, they belong to the SpecFile object.
+     */
+    std::map<std::string, Constant*> mConstants;
+    std::map<std::string, Type*> mTypes;
+    std::map<std::string, Function*> mFunctions;
+
+public:
+    ~SystemSpecification();
+    // Parse the spec file and create the object hierarchy, adding a pointer to mSpecFiles.
+    bool readSpecFile(const std::string& fileName);
+    // Generate all the files.
+    bool generateFiles(int versionOfTestFiles) const;
+
+    const std::vector<SpecFile*>& getSpecFiles() const { return mSpecFiles; }
+    const std::map<std::string, Constant*>& getConstants() const { return mConstants; }
+    const std::map<std::string, Type*>& getTypes() const { return mTypes; }
+    const std::map<std::string, Function*>& getFunctions() const { return mFunctions; }
+
+    // Returns "<a href='...'> for the named specification, or empty if not found.
+    std::string getHtmlAnchor(const std::string& name) const;
+};
+
+// Singleton that represents the collection of all the specs we're processing.
+extern SystemSpecification systemSpecification;
+
+// Table of equivalences of numerical types.
+extern const NumericalType TYPES[];
+extern const int NUM_TYPES;
+
+#endif  // ANDROID_RS_API_GENERATOR_SPECIFICATION_H
diff --git a/api/Utilities.cpp b/api/Utilities.cpp
new file mode 100644
index 0000000..80ebb0d
--- /dev/null
+++ b/api/Utilities.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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 <iostream>
+#include <sstream>
+
+#include "Utilities.h"
+
+using namespace std;
+
+const char LEGAL_NOTICE[] =
+            "/*\n"
+            " * Copyright (C) 2015 The Android Open Source Project\n"
+            " *\n"
+            " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+            " * you may not use this file except in compliance with the License.\n"
+            " * You may obtain a copy of the License at\n"
+            " *\n"
+            " *      http://www.apache.org/licenses/LICENSE-2.0\n"
+            " *\n"
+            " * Unless required by applicable law or agreed to in writing, software\n"
+            " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+            " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+            " * See the License for the specific language governing permissions and\n"
+            " * limitations under the License.\n"
+            " */\n\n";
+
+const char AUTO_GENERATED_WARNING[] =
+            "Don't edit this file!  It is auto-generated by frameworks/rs/api/gen_runtime.";
+
+string capitalize(const string& source) {
+    int length = source.length();
+    string result;
+    bool capitalize = true;
+    for (int s = 0; s < length; s++) {
+        if (source[s] == '_') {
+            capitalize = true;
+        } else if (capitalize) {
+            result += toupper(source[s]);
+            capitalize = false;
+        } else {
+            result += source[s];
+        }
+    }
+    return result;
+}
+
+void trimSpaces(string* s) {
+    const size_t end = s->find_last_not_of(" ");
+    if (end == string::npos) {
+        // All spaces
+        s->erase();
+        return;
+    } else {
+        s->erase(end + 1);
+    }
+    const size_t start = s->find_first_not_of(" ");
+    if (start > 0) {
+        s->erase(0, start);
+    }
+}
+
+string stringReplace(string s, string match, string rep) {
+    while (1) {
+        // This is not efficient but we don't care, as this program runs very rarely.
+        size_t p = s.find(match);
+        if (p == string::npos) break;
+
+        s.erase(p, match.size());
+        s.insert(p, rep);
+    }
+    return s;
+}
+
+bool charRemoved(char c, string* s) {
+    size_t p = s->find(c);
+    if (p != string::npos) {
+        s->erase(p, 1);
+        return true;
+    }
+    return false;
+}
+
+string stripHtml(const string& html) {
+    string s;
+    for (size_t start = 0; start < html.size(); start++) {
+        size_t lt = html.find('<', start);
+        if (lt == string::npos) {
+            s += html.substr(start);
+            break;
+        }
+        s += html.substr(start, lt - start);
+        if (isalpha(html[lt + 1]) || html[lt + 1] == '/') {
+            // It's an HTML tag.  Search for the end.
+            start = html.find('>', lt + 1);
+            if (start == string::npos) {
+                break;
+            }
+        } else {
+            s += '<';
+        }
+    }
+    s = stringReplace(s, "&gt;", ">");
+    s = stringReplace(s, "&lt;", "<");
+    s = stringReplace(s, "&nbsp;", " ");
+    return s;
+}
+
+string hashString(const string& s) {
+    long hash = 0;
+    for (size_t i = 0; i < s.length(); i++) {
+        hash = hash * 43 + s[i];
+    }
+    stringstream stream;
+    stream << "0x" << std::hex << hash << "l";
+    return stream.str();
+}
+
+bool testAndSet(const string& flag, set<string>* set) {
+    if (set->find(flag) == set->end()) {
+        set->insert(flag);
+        return false;
+    }
+    return true;
+}
+
+double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) {
+    /* Double has only 52 bits of precision (53 implied). So for longs, we want
+     * to create smaller values to avoid a round up.  Same for floats and halfs.
+     */
+    int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize);
+    unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits))
+                      << lowZeroBits;
+    return (double)l;
+}
+
+// Opens the stream.  Reports an error if it can't.
+bool GeneratedFile::start(const string& name) {
+    open(name.c_str(), ios::out | ios::trunc);
+    if (!is_open()) {
+        cerr << "Error.  Can't open the output file: " << name << "\n";
+        return false;
+    }
+    return true;
+}
+
+void GeneratedFile::writeNotices() {
+    *this << LEGAL_NOTICE;
+    *this << "// " << AUTO_GENERATED_WARNING << "\n\n";
+}
+
+void GeneratedFile::increaseIndent() {
+    mIndent.append(string(TAB_SIZE, ' '));
+}
+
+void GeneratedFile::decreaseIndent() {
+    mIndent.erase(0, TAB_SIZE);
+}
diff --git a/api/Utilities.h b/api/Utilities.h
new file mode 100644
index 0000000..8b0cd9c
--- /dev/null
+++ b/api/Utilities.h
@@ -0,0 +1,97 @@
+/*
+ * 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_RS_API_GENERATOR_UTILITIES_H
+#define ANDROID_RS_API_GENERATOR_UTILITIES_H
+
+#include <fstream>
+#include <set>
+#include <string>
+
+// Capitalizes and removes underscores.  E.g. converts "native_log" to NativeLog.
+std::string capitalize(const std::string& source);
+
+// Trim trailing and leading spaces from a string.
+void trimSpaces(std::string* s);
+
+// Replaces in string s all occurences of match with rep.
+std::string stringReplace(std::string s, std::string match, std::string rep);
+
+// Removes the character from present. Returns true if the string contained the character.
+bool charRemoved(char c, std::string* s);
+
+// Removes HTML references from the string.
+std::string stripHtml(const std::string& html);
+
+// Returns a string that's an hexadecimal constant of the hash of the string.
+std::string hashString(const std::string& s);
+
+// Adds a string to a set.  Return true if it was already in.
+bool testAndSet(const std::string& flag, std::set<std::string>* set);
+
+/* Returns a double that should be able to be converted to an integer of size
+ * numberOfIntegerBits.
+ */
+double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize);
+
+/* This class is used to generate one source file.  There will be one instance
+ * for each generated file.
+ */
+class GeneratedFile : public std::ofstream {
+private:
+    std::string mIndent;  // The correct spacing at the beginning of each line.
+    const int TAB_SIZE = 4;
+
+public:
+    // Opens the stream.  Reports an error if it can't.
+    bool start(const std::string& name);
+
+    // Write copyright notice & auto-generated warning in Java/C style comments.
+    void writeNotices();
+
+    void increaseIndent();               // Increases the new line indentation by 4.
+    void decreaseIndent();               // Decreases the new line indentation by 4.
+    void comment(const std::string& s);  // Outputs a multiline comment.
+
+    // Starts a control block.  This works both for Java and C++.
+    void startBlock() {
+        *this << " {\n";
+        increaseIndent();
+    }
+
+    // Ends a control block.
+    void endBlock(bool addSemicolon = false) {
+        decreaseIndent();
+        indent() << "}" << (addSemicolon ? ";" : "") << "\n";
+    }
+
+    /* Indents the line.  By returning *this, we can use like this:
+     *  mOut.ident() << "a = b;\n";
+     */
+    std::ofstream& indent() {
+        *this << mIndent;
+        return *this;
+    }
+
+    std::ofstream& indentPlus() {
+        *this << mIndent << std::string(2 * TAB_SIZE, ' ');
+        return *this;
+    }
+};
+
+extern const char AUTO_GENERATED_WARNING[];
+
+#endif  // ANDROID_RS_API_GENERATOR_UTILITIES_H
diff --git a/api/gen_runtime.cpp b/api/gen_runtime.cpp
deleted file mode 100644
index 812a755..0000000
--- a/api/gen_runtime.cpp
+++ /dev/null
@@ -1,1969 +0,0 @@
-/*
- * 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.
- */
-
-/* This program processes Renderscript function definitions described in spec files.
- * For each spec file provided on the command line, it generates a corresponding
- * Renderscript header (*.rsh) which is meant for inclusion in client scripts.
- *
- * This program also generates Junit test files to automatically test each of the
- * functions using randomly generated data.  We create two files for each function:
- * - a Renderscript file named Test{Function}.rs,
- * - a Junit file named Test{function}.java, which calls the above RS file.
- *
- * This program takes an optional -v parameter, the RS version to target the
- * test files for.  The header file will always contain all the functions.
- *
- * This program contains five main classes:
- * - SpecFile: Represents on spec file.
- * - Function: Each instance represents a function, like clamp.  Even though the
- *      spec file contains many entries for clamp, we'll only have one clamp instance.
- * - Specification: Defines one of the many variations of the function.  There's
- *      a one to one correspondance between Specification objects and entries in the
- *      spec file.  Strings that are parts of a Specification can include placeholders,
- *      which are "#1", "#2", "#3", and "#4".  We'll replace these by values before
- *      generating the files.
- * - Permutation: A concrete version of a specification, where all placeholders have
- *      been replaced by actual values.
- * - ParameterDefinition: A definition of a parameter of a concrete function.
- */
-
-#include <math.h>
-#include <stdio.h>
-#include <cctype>
-#include <cstdlib>
-#include <fstream>
-#include <functional>
-#include <iomanip>
-#include <list>
-#include <map>
-#include <set>
-#include <sstream>
-#include <string>
-#include <vector>
-
-using namespace std;
-
-namespace {
-
-const char* AUTO_GENERATED_WARNING =
-            "// Don't edit this file!  It is auto-generated by "
-            "frameworks/rs/api/gen_runtime.\n\n";
-const char* LEGAL_NOTICE =
-            "/*\n"
-            " * Copyright (C) 2014 The Android Open Source Project\n"
-            " *\n"
-            " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
-            " * you may not use this file except in compliance with the License.\n"
-            " * You may obtain a copy of the License at\n"
-            " *\n"
-            " *      http://www.apache.org/licenses/LICENSE-2.0\n"
-            " *\n"
-            " * Unless required by applicable law or agreed to in writing, software\n"
-            " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
-            " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
-            " * See the License for the specific language governing permissions and\n"
-            " * limitations under the License.\n"
-            " */\n\n";
-const char* DOX_HEADER =
-            "/** @file\n"
-            " *\n"
-            " */\n\n";
-
-class Function;
-class Specification;
-class Permutation;
-struct Type;
-
-/* Information about a parameter to a function.  The values of all the fields should only be set by
- * parseParameterDefinition.
- */
-struct ParameterDefinition {
-    string rsType;        // The Renderscript type, e.g. "uint3"
-    string rsBaseType;    // As above but without the number, e.g. "uint"
-    string javaBaseType;  // The type we need to declare in Java, e.g. "unsigned int"
-    string specType;      // The type found in the spec, e.g. "f16"
-    bool isFloatType;     // True if it's a floating point value
-
-    /* The number of entries in the vector.  It should be either "1", "2", "3", or "4".  It's also
-     * "1" for scalars.
-     */
-    string mVectorSize;
-    /* The space the vector takes in an array.  It's the same as the vector size, except for size
-     * "3", where the width is "4".
-     */
-    string vectorWidth;
-
-    string specName;       // e.g. x, as found in the spec file
-    string variableName;   // e.g. inX, used both in .rs and .java
-    string rsAllocName;    // e.g. gAllocInX
-    string javaAllocName;  // e.g. inX
-    string javaArrayName;  // e.g. arrayInX
-
-    // If non empty, the mininum and maximum values to be used when generating the test data.
-    string minValue;
-    string maxValue;
-    /* If non empty, contains the name of another parameter that should be smaller or equal to this
-     * parameter, i.e.  value(smallerParameter) <= value(this).  This is used when testing clamp.
-     */
-    string smallerParameter;
-
-    bool isOutParameter;       // True if this parameter returns data from the script.
-    bool undefinedIfOutIsNan;  // If true, we don't validate if 'out' is NaN.
-
-    int typeIndex;            // Index in the TYPES array.
-    int compatibleTypeIndex;  // Index in TYPES for which the test data must also fit.
-
-    /* Parse the parameter definition found in the spec file.  It will generate a name if none
-     * are present in the file.  One of the two counts will be incremented, and potentially
-     * used to generate unique names.  isReturn is true if we're processing the "return:"
-     * definition.
-     */
-    void parseParameterDefinition(string s, bool isReturn, int* inputCount, int* outputCount);
-};
-
-// An entire spec file and the methods to process it.
-class SpecFile {
-public:
-    explicit SpecFile(const string& specFileName) : mSpecFileName(specFileName) {}
-    bool process(int versionOfTestFiles);
-
-private:
-    const string mSpecFileName;
-    // The largest version number that we have found in all the specifications.
-    int mLargestVersionNumber;
-
-    map<string, Function*> mFunctionsMap;  // All the known functions.
-    typedef map<string, Function*>::iterator FunctionsIterator;
-
-    bool readSpecFile();
-    Function* getFunction(const string& name);
-    bool generateFiles(int versionOfTestFiles);
-    bool writeAllFunctions(ofstream& headerFile, int versionOfTestFiles);
-};
-
-/* Represents a function, like "clamp".  Even though the spec file contains many entries for clamp,
- * we'll only have one clamp instance.
- */
-class Function {
-private:
-    string mName;             // The lower case name, e.g. native_log
-    string mCapitalizedName;  // The capitalized name, e.g. NativeLog
-    string mTestName;         // e.g. GeneratedTestNativeLog
-    string mRelaxedTestName;  // e.g. GeneratedTestNativeLogRelaxed
-
-    vector<Specification*> mSpecifications;
-    typedef vector<Specification*>::iterator SpecificationIterator;
-
-    /* We keep track of the allocations generated in the .rs file and the argument classes defined
-     * in the Java file, as we share these between the functions created for each specification.
-     */
-    set<string> mRsAllocationsGenerated;
-    set<string> mJavaGeneratedArgumentClasses;
-
-    string mJavaCallAllCheckMethods;  // Lines of Java code to invoke the check methods.
-
-    ofstream mRsFile;    // The Renderscript test file we're generating.
-    ofstream mJavaFile;  // The Jave test file we're generating.
-
-    bool startRsFile();         // Open the mRsFile and writes its header.
-    bool writeRelaxedRsFile();  // Write the entire relaxed rs test file (an include essentially)
-    bool startJavaFile();       // Open the mJavaFile and writes the header.
-    void finishJavaFile();      // Write the test method and closes the file.
-
-public:
-    explicit Function(const string& name);
-    void addSpecification(Specification* spec) { mSpecifications.push_back(spec); }
-    /* Write the .java and the two .rs test files.  versionOfTestFiles is used to restrict which API
-     * to test.  Also writes the section of the header file.
-     */
-    bool writeFiles(ofstream& headerFile, int versionOfTestFiles);
-    // Write an allocation and keep track of having it written, so it can be shared.
-    void writeRsAllocationDefinition(const ParameterDefinition& param);
-    // Write an argument class definiton and keep track of having it written, so it can be shared.
-    void writeJavaArgumentClassDefinition(const string& className, const string& definition);
-    // Add a call to mJavaCallAllCheckMethods to be used at the end of the file generation.
-    void addJavaCheckCall(const string& call);
-};
-
-/* Defines one of the many variations of the function.  There's a one to one correspondance between
- * Specification objects and entries in the spec file.  Some of the strings that are parts of a
- * Specification can include placeholders, which are "#1", "#2", "#3", and "#4".  We'll replace
- * these by values before generating the files.
- */
-class Specification {
-private:
-    /* The range of versions this specification applies to. 0 if there's no restriction, so an API
-     * that became available at 9 and is still valid would have min:9 max:0.
-     */
-    int mMinVersion;
-    int mMaxVersion;
-
-    /* The name of the function without #n, e.g. convert.  As of this writing, it only differs for
-     * convert.
-     */
-    string mCleanName;
-    /* How to test.  One of:
-     * "scalar": Generate test code that checks entries of each vector indepently.  E.g. for
-     *           sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times.
-     * "vector": Generate test code that calls the CoreMathVerifier only once for each vector.
-     *           This is useful for APIs like dot() or length().
-     * "noverify": Generate test code that calls the API but don't verify the returned value.
-     * "limited": Like "scalar" but tests a limited range of input values.
-     * "custom": Like "scalar" but instead of calling CoreMathVerifier.computeXXX() to compute
-     *           the expected value, we call instead CoreMathVerifier.verifyXXX().  This method
-     *           returns a string that contains the error message, null if there's no error.
-     */
-    string mTest;
-    string mPrecisionLimit;  // Maximum precision required when checking output of this function.
-
-    vector<vector<string> > mReplaceables;
-
-    // The following fields may contain placeholders that will be replaced using the mReplaceables.
-
-    // The name of this function, can include #, e.g. convert_#1_#2
-    string mName;
-
-    string mReturn;           // The return type
-    vector<string> mComment;  // The comments to be included in the header
-    vector<string> mInline;   // The inline code to be included in the header
-    vector<string> mParam;    // One entry per parameter defined
-
-    // Substitute the placeholders in the strings by the corresponding entries in mReplaceables.
-    string expandString(string s, int i1, int i2, int i3, int i4) const;
-    void expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4,
-                            vector<string>* out) const;
-
-public:
-    Specification() {
-        mMinVersion = 0;
-        mMaxVersion = 0;
-    }
-    int getMinVersion() const { return mMinVersion; }
-    int getMaxVersion() const { return mMaxVersion; }
-
-    string getName(int i1, int i2, int i3, int i4) const {
-        return expandString(mName, i1, i2, i3, i4);
-    }
-    string getReturn(int i1, int i2, int i3, int i4) const {
-        return expandString(mReturn, i1, i2, i3, i4);
-    }
-    void getComments(int i1, int i2, int i3, int i4, vector<string>* comments) const {
-        return expandStringVector(mComment, i1, i2, i3, i4, comments);
-    }
-    void getInlines(int i1, int i2, int i3, int i4, vector<string>* inlines) const {
-        return expandStringVector(mInline, i1, i2, i3, i4, inlines);
-    }
-    void getParams(int i1, int i2, int i3, int i4, vector<string>* params) const {
-        return expandStringVector(mParam, i1, i2, i3, i4, params);
-    }
-    string getTest() const { return mTest; }
-    string getPrecisionLimit() const { return mPrecisionLimit; }
-    string getCleanName() const { return mCleanName; }
-
-    void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, Function* function,
-                    int versionOfTestFiles);
-    bool writeRelaxedRsFile() const;
-    // Return true if this specification should be generated for this version.
-    bool relevantForVersion(int versionOfTestFiles) const;
-
-    static Specification* scanSpecification(FILE* in);
-};
-
-// A concrete version of a specification, where all placeholders have been replaced by actual
-// values.
-class Permutation {
-private:
-    Function* mFunction;
-    Specification* mSpecification;
-
-    // These are the expanded version of those found on Specification
-    string mName;
-    string mCleanName;
-    string mTest;  // How to test.  One of "scalar", "vector", "noverify", "limited", and "none".
-    string mPrecisionLimit;  // Maximum precision required when checking output of this function.
-    vector<string> mInline;
-    vector<string> mComment;
-
-    // The inputs and outputs of the function.  This include the return type, if present.
-    vector<ParameterDefinition*> mParams;
-    // The index of the return value in mParams, -1 if the function is void.
-    int mReturnIndex;
-    // The index of the first input value in mParams, -1 if there's no input.
-    int mFirstInputIndex;
-    // The number of input and output parameters.
-    int mInputCount;
-    int mOutputCount;
-    // Whether one of the output parameters is a float.
-    bool mHasFloatAnswers;
-
-    string mRsKernelName;
-    string mJavaArgumentsClassName;
-    string mJavaArgumentsNClassName;
-    string mJavaVerifierComputeMethodName;
-    string mJavaVerifierVerifyMethodName;
-    string mJavaCheckMethodName;
-    string mJavaVerifyMethodName;
-
-    void writeHeaderSection(ofstream& file) const;
-
-    void writeRsSection(ofstream& rs) const;
-
-    void writeJavaSection(ofstream& file) const;
-    void writeJavaArgumentClass(ofstream& file, bool scalar) const;
-    void writeJavaCheckMethod(ofstream& file, bool generateCallToVerifier) const;
-    void writeJavaVerifyScalarMethod(ofstream& file, bool verifierValidates) const;
-    void writeJavaVerifyVectorMethod(ofstream& file) const;
-    void writeJavaVerifyFunctionHeader(ofstream& file) const;
-    void writeJavaInputAllocationDefinition(ofstream& file, const string& indent,
-                                            const ParameterDefinition& param) const;
-    void writeJavaOutputAllocationDefinition(ofstream& file, const string& indent,
-                                             const ParameterDefinition& param) const;
-    // Write code to create a random allocation for which the data must be compatible for two types.
-    void writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType,
-                                                  const string& seed, char vectorSize,
-                                                  const Type& compatibleType,
-                                                  const Type& generatedType) const;
-    void writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType,
-                                                    const string& seed, char vectorSize,
-                                                    const Type& compatibleType,
-                                                    const Type& generatedType) const;
-    void writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerifier) const;
-
-    void writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p,
-                                  const string& argsIndex, const string& actualIndex) const;
-    void writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p,
-                               const string& argsIndex, const string& actualIndex) const;
-    void writeJavaAppendOutputToMessage(ofstream& file, int indent, const ParameterDefinition& p,
-                                        const string& argsIndex, const string& actualIndex,
-                                        bool verifierValidates) const;
-    void writeJavaAppendInputToMessage(ofstream& file, int indent, const ParameterDefinition& p,
-                                       const string& actual) const;
-    void writeJavaAppendNewLineToMessage(ofstream& file, int indent) const;
-    void writeJavaAppendVariableToMessage(ofstream& file, int indent, const ParameterDefinition& p,
-                                          const string& value) const;
-    void writeJavaAppendFloatVariableToMessage(ofstream& file, int indent, const string& value,
-                                               bool regularFloat) const;
-    void writeJavaVectorComparison(ofstream& file, int indent, const ParameterDefinition& p) const;
-    void writeJavaAppendVectorInputToMessage(ofstream& file, int indent,
-                                             const ParameterDefinition& p) const;
-    void writeJavaAppendVectorOutputToMessage(ofstream& file, int indent,
-                                              const ParameterDefinition& p) const;
-    bool passByAddressToSet(const string& name) const;
-    void convertToRsType(const string& name, string* dataType, char* vectorSize) const;
-
-public:
-    Permutation(Function* function, Specification* specification, int i1, int i2, int i3, int i4);
-    void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
-                    int versionOfTestFiles);
-};
-
-// Table of type equivalences
-// TODO: We should just be pulling this from a shared header. Slang does exactly the same thing.
-
-enum NumberKind { SIGNED_INTEGER, UNSIGNED_INTEGER, FLOATING_POINT };
-
-struct Type {
-    const char* specType;  // Name found in the .spec file
-    string rsDataType;     // RS data type
-    string cType;          // Type in a C file
-    const char* javaType;  // Type in a Java file
-    NumberKind kind;
-    /* For integers, number of bits of the number, excluding the sign bit.
-     * For floats, number of implied bits of the mantissa.
-     */
-    int significantBits;
-    // For floats, number of bits of the exponent.  0 for integer types.
-    int exponentBits;
-};
-
-const Type TYPES[] = {{"f16", "FLOAT_16", "half", "half", FLOATING_POINT, 11, 5},
-                      {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8},
-                      {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11},
-                      {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0},
-                      {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0},
-                      {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0},
-                      {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0},
-                      {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0},
-                      {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0},
-                      {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0},
-                      {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0}};
-
-const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]);
-
-// Returns the index in TYPES for the provided cType
-int FindCType(const string& cType) {
-    for (int i = 0; i < NUM_TYPES; i++) {
-        if (cType == TYPES[i].cType) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-// Capitalizes and removes underscores.  E.g. converts "native_log" to NativeLog.
-string capitalize(const string& source) {
-    int length = source.length();
-    string result;
-    bool capitalize = true;
-    for (int s = 0; s < length; s++) {
-        if (source[s] == '_') {
-            capitalize = true;
-        } else if (capitalize) {
-            result += toupper(source[s]);
-            capitalize = false;
-        } else {
-            result += source[s];
-        }
-    }
-    return result;
-}
-
-string tab(int n) { return string(n * 4, ' '); }
-
-// Returns a string that's an hexadecimal constant fo the hash of the string.
-string hashString(const string& s) {
-    long hash = 0;
-    for (size_t i = 0; i < s.length(); i++) {
-        hash = hash * 43 + s[i];
-    }
-    stringstream stream;
-    stream << "0x" << std::hex << hash << "l";
-    return stream.str();
-}
-
-// Removes the character from present. Returns true if the string contained the character.
-static bool charRemoved(char c, string* s) {
-    size_t p = s->find(c);
-    if (p != string::npos) {
-        s->erase(p, 1);
-        return true;
-    }
-    return false;
-}
-
-// Return true if the string is already in the set.  Inserts it if not.
-bool testAndSet(const string& flag, set<string>* set) {
-    if (set->find(flag) == set->end()) {
-        set->insert(flag);
-        return false;
-    }
-    return true;
-}
-
-// Convert an int into a string.
-string toString(int n) {
-    char buf[100];
-    snprintf(buf, sizeof(buf), "%d", n);
-    return string(buf);
-}
-
-void trim(string* s, size_t start) {
-    if (start > 0) {
-        s->erase(0, start);
-    }
-
-    while (s->size() && (s->at(0) == ' ')) {
-        s->erase(0, 1);
-    }
-
-    size_t p = s->find_first_of("\n\r");
-    if (p != string::npos) {
-        s->erase(p);
-    }
-
-    while ((s->size() > 0) && (s->at(s->size() - 1) == ' ')) {
-        s->erase(s->size() - 1);
-    }
-}
-
-string stringReplace(string s, string match, string rep) {
-    while (1) {
-        size_t p = s.find(match);
-        if (p == string::npos) break;
-
-        s.erase(p, match.size());
-        s.insert(p, rep);
-    }
-    return s;
-}
-
-// Return the next line from the input file.
-bool getNextLine(FILE* in, string* s) {
-    s->clear();
-    while (1) {
-        int c = fgetc(in);
-        if (c == EOF) return s->size() != 0;
-        if (c == '\n') break;
-        s->push_back((char)c);
-    }
-    return true;
-}
-
-void writeIfdef(ofstream& file, string filename, bool isStart) {
-    string t = "__";
-    t += filename;
-    t += "__";
-
-    for (size_t i = 2; i < t.size(); i++) {
-        if (t[i] == '.') {
-            t[i] = '_';
-        }
-    }
-
-    if (isStart) {
-        file << "#ifndef " << t << "\n";
-        file << "#define " << t << "\n";
-    } else {
-        file << "#endif // " << t << "\n";
-    }
-}
-
-void writeJavaArrayInitialization(ofstream& file, const ParameterDefinition& p) {
-    file << tab(2) << p.javaBaseType << "[] " << p.javaArrayName << " = new " << p.javaBaseType
-         << "[INPUTSIZE * " << p.vectorWidth << "];\n";
-    file << tab(2) << p.javaAllocName << ".copyTo(" << p.javaArrayName << ");\n";
-}
-
-bool parseCommandLine(int argc, char* argv[], int* versionOfTestFiles,
-                      vector<string>* specFileNames) {
-    for (int i = 1; i < argc; i++) {
-        if (argv[i][0] == '-') {
-            if (argv[i][1] == 'v') {
-                i++;
-                if (i < argc) {
-                    char* end;
-                    *versionOfTestFiles = strtol(argv[i], &end, 10);
-                    if (*end != '\0') {
-                        printf("Can't parse the version number %s\n", argv[i]);
-                        return false;
-                    }
-                } else {
-                    printf("Missing version number after -v\n");
-                    return false;
-                }
-            } else {
-                printf("Unrecognized flag %s\n", argv[i]);
-                return false;
-            }
-        } else {
-            specFileNames->push_back(argv[i]);
-        }
-    }
-    if (specFileNames->size() == 0) {
-        printf("No spec file specified\n");
-        return false;
-    }
-    return true;
-}
-
-/* Returns a double that should be able to be converted to an integer of size
- * numberOfIntegerBits.
- */
-static double MaxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) {
-    /* Double has only 52 bits of precision (53 implied). So for longs, we want
-     * to create smaller values to avoid a round up.  Same for floats and halfs.
-     */
-    int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize);
-    unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits))
-                      << lowZeroBits;
-    return (double)l;
-}
-
-/* Parse a parameter definition.  It's of the form "type [*][name]".  The type
- * is required.  The name is optional.  The * indicates it's an output
- * parameter.  We also pass the indexed of this parameter in the definition, so
- * we can create names like in2, in3, etc. */
-void ParameterDefinition::parseParameterDefinition(string s, bool isReturn, int* inputCount,
-                                                   int* outputCount) {
-    istringstream stream(s);
-    string name, type, option;
-    stream >> rsType;
-    stream >> specName;
-    stream >> option;
-
-    // Determine if this is an output.
-    isOutParameter = charRemoved('*', &rsType) || charRemoved('*', &specName) || isReturn;
-
-    // Extract the vector size out of the type.
-    int last = rsType.size() - 1;
-    char lastChar = rsType[last];
-    if (lastChar >= '0' && lastChar <= '9') {
-        rsBaseType = rsType.substr(0, last);
-        mVectorSize = lastChar;
-    } else {
-        rsBaseType = rsType;
-        mVectorSize = "1";
-    }
-    if (mVectorSize == "3") {
-        vectorWidth = "4";
-    } else {
-        vectorWidth = mVectorSize;
-    }
-
-    /* Create variable names to be used in the java and .rs files.  Because x and
-     * y are reserved in .rs files, we prefix variable names with "in" or "out".
-     */
-    if (isOutParameter) {
-        variableName = "out";
-        if (!specName.empty()) {
-            variableName += capitalize(specName);
-        } else if (!isReturn) {
-            variableName += toString(*outputCount);
-        }
-        (*outputCount)++;
-    } else {
-        variableName = "in";
-        if (!specName.empty()) {
-            variableName += capitalize(specName);
-        } else if (*inputCount > 0) {
-            variableName += toString(*inputCount);
-        }
-        (*inputCount)++;
-    }
-    rsAllocName = "gAlloc" + capitalize(variableName);
-    javaAllocName = variableName;
-    javaArrayName = "array" + capitalize(javaAllocName);
-
-    // Process the option.
-    undefinedIfOutIsNan = false;
-    compatibleTypeIndex = -1;
-    if (!option.empty()) {
-        if (option.compare(0, 6, "range(") == 0) {
-            size_t pComma = option.find(',');
-            size_t pParen = option.find(')');
-            if (pComma == string::npos || pParen == string::npos) {
-                printf("Incorrect range %s\n", option.c_str());
-            } else {
-                minValue = option.substr(6, pComma - 6);
-                maxValue = option.substr(pComma + 1, pParen - pComma - 1);
-            }
-        } else if (option.compare(0, 6, "above(") == 0) {
-            size_t pParen = option.find(')');
-            if (pParen == string::npos) {
-                printf("Incorrect option %s\n", option.c_str());
-            } else {
-                smallerParameter = option.substr(6, pParen - 6);
-            }
-        } else if (option.compare(0, 11, "compatible(") == 0) {
-            size_t pParen = option.find(')');
-            if (pParen == string::npos) {
-                printf("Incorrect option %s\n", option.c_str());
-            } else {
-                compatibleTypeIndex = FindCType(option.substr(11, pParen - 11));
-            }
-        } else if (option.compare(0, 11, "conditional") == 0) {
-            undefinedIfOutIsNan = true;
-        } else {
-            printf("Unrecognized option %s\n", option.c_str());
-        }
-    }
-
-    typeIndex = FindCType(rsBaseType);
-    isFloatType = false;
-    if (typeIndex < 0) {
-        // TODO set a global flag when we encounter an error & abort
-        printf("Error, could not find %s\n", rsBaseType.c_str());
-    } else {
-        javaBaseType = TYPES[typeIndex].javaType;
-        specType = TYPES[typeIndex].specType;
-        isFloatType = TYPES[typeIndex].exponentBits > 0;
-    }
-}
-
-bool SpecFile::process(int versionOfTestFiles) {
-    if (!readSpecFile()) {
-        return false;
-    }
-    if (versionOfTestFiles == 0) {
-        versionOfTestFiles = mLargestVersionNumber;
-    }
-    if (!generateFiles(versionOfTestFiles)) {
-        return false;
-    }
-    printf("%s: %ld functions processed.\n", mSpecFileName.c_str(), mFunctionsMap.size());
-    return true;
-}
-
-// Read the specification, adding the definitions to the global functions map.
-bool SpecFile::readSpecFile() {
-    FILE* specFile = fopen(mSpecFileName.c_str(), "rt");
-    if (!specFile) {
-        printf("Error opening input file: %s\n", mSpecFileName.c_str());
-        return false;
-    }
-
-    mLargestVersionNumber = 0;
-    while (1) {
-        Specification* spec = Specification::scanSpecification(specFile);
-        if (spec == nullptr) {
-            break;
-        }
-        getFunction(spec->getCleanName())->addSpecification(spec);
-        int specMin = spec->getMinVersion();
-        int specMax = spec->getMaxVersion();
-        if (specMin && specMin > mLargestVersionNumber) {
-            mLargestVersionNumber = specMin;
-        }
-        if (specMax && specMax > mLargestVersionNumber) {
-            mLargestVersionNumber = specMax;
-        }
-    }
-
-    fclose(specFile);
-    return true;
-}
-
-bool SpecFile::generateFiles(int versionOfTestFiles) {
-    printf("%s: Generating test files for version %d\n", mSpecFileName.c_str(), versionOfTestFiles);
-
-    // The header file name should have the same base but with a ".rsh" extension.
-    string headerFileName = mSpecFileName;
-    size_t l = headerFileName.length();
-    const char SPEC[] = ".spec";
-    const int SPEC_SIZE = sizeof(SPEC) - 1;
-    const int start = l - SPEC_SIZE;
-    if (start >= 0 && headerFileName.compare(start, SPEC_SIZE, SPEC) == 0) {
-        headerFileName.erase(start);
-    }
-    headerFileName += ".rsh";
-
-    // Write the start of the header file.
-    ofstream headerFile;
-    headerFile.open(headerFileName.c_str(), ios::out | ios::trunc);
-    if (!headerFile.is_open()) {
-        printf("Error opening output file: %s\n", headerFileName.c_str());
-        return false;
-    }
-    headerFile << LEGAL_NOTICE;
-    headerFile << AUTO_GENERATED_WARNING;
-    headerFile << DOX_HEADER;
-
-    writeIfdef(headerFile, headerFileName, true);
-
-    // Write the functions to the header and test files.
-    bool success = writeAllFunctions(headerFile, versionOfTestFiles);
-
-    // Finish the header file.
-    writeIfdef(headerFile, headerFileName, false);
-    headerFile.close();
-
-    return success;
-}
-
-// Return the named function from the map.  Creates it if it's not there.
-Function* SpecFile::getFunction(const string& name) {
-    FunctionsIterator iter = mFunctionsMap.find(name);
-    if (iter != mFunctionsMap.end()) {
-        return iter->second;
-    }
-    Function* f = new Function(name);
-    mFunctionsMap[name] = f;
-    return f;
-}
-
-bool SpecFile::writeAllFunctions(ofstream& headerFile, int versionOfTestFiles) {
-    bool success = true;
-    for (FunctionsIterator iter = mFunctionsMap.begin(); iter != mFunctionsMap.end(); iter++) {
-        Function* func = iter->second;
-        if (!func->writeFiles(headerFile, versionOfTestFiles)) {
-            success = false;
-        }
-    }
-    return success;
-}
-
-Function::Function(const string& name) {
-    mName = name;
-    mCapitalizedName = capitalize(mName);
-    mTestName = "GeneratedTest" + mCapitalizedName;
-    mRelaxedTestName = mTestName + "Relaxed";
-}
-
-bool Function::writeFiles(ofstream& headerFile, int versionOfTestFiles) {
-    if (!startRsFile() || !startJavaFile() || !writeRelaxedRsFile()) {
-        return false;
-    }
-
-    for (SpecificationIterator i = mSpecifications.begin(); i < mSpecifications.end(); i++) {
-        (*i)->writeFiles(headerFile, mRsFile, mJavaFile, this, versionOfTestFiles);
-    }
-
-    finishJavaFile();
-    // There's no work to wrap-up in the .rs file.
-
-    mRsFile.close();
-    mJavaFile.close();
-    return true;
-}
-
-bool Function::startRsFile() {
-    string fileName = mTestName + ".rs";
-    mRsFile.open(fileName.c_str(), ios::out | ios::trunc);
-    if (!mRsFile.is_open()) {
-        printf("Error opening file: %s\n", fileName.c_str());
-        return false;
-    }
-    mRsFile << LEGAL_NOTICE;
-    mRsFile << "#pragma version(1)\n";
-    mRsFile << "#pragma rs java_package_name(android.renderscript.cts)\n\n";
-    mRsFile << AUTO_GENERATED_WARNING;
-    return true;
-}
-
-// Write an allocation definition if not already emitted in the .rs file.
-void Function::writeRsAllocationDefinition(const ParameterDefinition& param) {
-    if (!testAndSet(param.rsAllocName, &mRsAllocationsGenerated)) {
-        mRsFile << "rs_allocation " << param.rsAllocName << ";\n";
-    }
-}
-
-// Write the entire *Relaxed.rs test file, as it only depends on the name.
-bool Function::writeRelaxedRsFile() {
-    string name = mRelaxedTestName + ".rs";
-    FILE* file = fopen(name.c_str(), "wt");
-    if (!file) {
-        printf("Error opening file: %s\n", name.c_str());
-        return false;
-    }
-    fputs(LEGAL_NOTICE, file);
-    string s;
-    s += "#include \"" + mTestName + ".rs\"\n";
-    s += "#pragma rs_fp_relaxed\n";
-    s += AUTO_GENERATED_WARNING;
-    fputs(s.c_str(), file);
-    fclose(file);
-    return true;
-}
-
-bool Function::startJavaFile() {
-    string fileName = mTestName + ".java";
-    mJavaFile.open(fileName.c_str(), ios::out | ios::trunc);
-    if (!mJavaFile.is_open()) {
-        printf("Error opening file: %s\n", fileName.c_str());
-        return false;
-    }
-    mJavaFile << LEGAL_NOTICE;
-    mJavaFile << AUTO_GENERATED_WARNING;
-    mJavaFile << "package android.renderscript.cts;\n\n";
-
-    mJavaFile << "import android.renderscript.Allocation;\n";
-    mJavaFile << "import android.renderscript.RSRuntimeException;\n";
-    mJavaFile << "import android.renderscript.Element;\n\n";
-
-    mJavaFile << "public class " << mTestName << " extends RSBaseCompute {\n\n";
-
-    mJavaFile << tab(1) << "private ScriptC_" << mTestName << " script;\n";
-    mJavaFile << tab(1) << "private ScriptC_" << mRelaxedTestName << " scriptRelaxed;\n\n";
-
-    mJavaFile << tab(1) << "@Override\n";
-    mJavaFile << tab(1) << "protected void setUp() throws Exception {\n";
-    mJavaFile << tab(2) << "super.setUp();\n";
-    mJavaFile << tab(2) << "script = new ScriptC_" << mTestName << "(mRS);\n";
-    mJavaFile << tab(2) << "scriptRelaxed = new ScriptC_" << mRelaxedTestName << "(mRS);\n";
-    mJavaFile << tab(1) << "}\n\n";
-    return true;
-}
-
-void Function::writeJavaArgumentClassDefinition(const string& className, const string& definition) {
-    if (!testAndSet(className, &mJavaGeneratedArgumentClasses)) {
-        mJavaFile << definition;
-    }
-}
-
-void Function::addJavaCheckCall(const string& call) {
-    mJavaCallAllCheckMethods += tab(2) + call + "\n";
-}
-
-void Function::finishJavaFile() {
-    mJavaFile << tab(1) << "public void test" << mCapitalizedName << "() {\n";
-    mJavaFile << mJavaCallAllCheckMethods;
-    mJavaFile << tab(1) << "}\n";
-    mJavaFile << "}\n";
-}
-
-void Specification::expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4,
-                                       vector<string>* out) const {
-    out->clear();
-    for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
-        out->push_back(expandString(*iter, i1, i2, i3, i4));
-    }
-}
-
-Specification* Specification::scanSpecification(FILE* in) {
-    Specification* spec = new Specification();
-    spec->mTest = "scalar";  // default
-    bool modeComment = false;
-    bool modeInline = false;
-    bool success = true;
-
-    while (1) {
-        string s;
-        bool ret = getNextLine(in, &s);
-        if (!ret) break;
-
-        if (modeComment) {
-            if (!s.size() || (s[0] == ' ')) {
-                trim(&s, 0);
-                spec->mComment.push_back(s);
-                continue;
-            } else {
-                modeComment = false;
-            }
-        }
-
-        if (modeInline) {
-            if (!s.size() || (s[0] == ' ')) {
-                trim(&s, 0);
-                spec->mInline.push_back(s);
-                continue;
-            } else {
-                modeInline = false;
-            }
-        }
-
-        if (s[0] == '#') {
-            continue;
-        }
-
-        if (s.compare(0, 5, "name:") == 0) {
-            trim(&s, 5);
-            spec->mName = s;
-            // Some functions like convert have # part of the name.  Truncate at that point.
-            size_t p = s.find('#');
-            if (p != string::npos) {
-                if (p > 0 && s[p - 1] == '_') {
-                    p--;
-                }
-                s.erase(p);
-            }
-            spec->mCleanName = s;
-            continue;
-        }
-
-        if (s.compare(0, 4, "arg:") == 0) {
-            trim(&s, 4);
-            spec->mParam.push_back(s);
-            continue;
-        }
-
-        if (s.compare(0, 4, "ret:") == 0) {
-            trim(&s, 4);
-            spec->mReturn = s;
-            continue;
-        }
-
-        if (s.compare(0, 5, "test:") == 0) {
-            trim(&s, 5);
-            if (s == "scalar" || s == "vector" || s == "noverify" || s == "custom" || s == "none") {
-                spec->mTest = s;
-            } else if (s.compare(0, 7, "limited") == 0) {
-                spec->mTest = "limited";
-                if (s.compare(7, 1, "(") == 0) {
-                    size_t pParen = s.find(')');
-                    if (pParen == string::npos) {
-                        printf("Incorrect test %s\n", s.c_str());
-                    } else {
-                        spec->mPrecisionLimit = s.substr(8, pParen - 8);
-                    }
-                }
-            } else {
-                printf("Error: Unrecognized test option: %s\n", s.c_str());
-                success = false;
-            }
-            continue;
-        }
-
-        if (s.compare(0, 4, "end:") == 0) {
-            if (success) {
-                return spec;
-            } else {
-                delete spec;
-                return nullptr;
-            }
-        }
-
-        if (s.compare(0, 8, "comment:") == 0) {
-            modeComment = true;
-            continue;
-        }
-
-        if (s.compare(0, 7, "inline:") == 0) {
-            modeInline = true;
-            continue;
-        }
-
-        if (s.compare(0, 8, "version:") == 0) {
-            trim(&s, 8);
-            sscanf(s.c_str(), "%i %i", &spec->mMinVersion, &spec->mMaxVersion);
-            continue;
-        }
-
-        if (s.compare(0, 8, "start:") == 0) {
-            continue;
-        }
-
-        if (s.compare(0, 2, "w:") == 0) {
-            vector<string> t;
-            if (s.find("1") != string::npos) {
-                t.push_back("");
-            }
-            if (s.find("2") != string::npos) {
-                t.push_back("2");
-            }
-            if (s.find("3") != string::npos) {
-                t.push_back("3");
-            }
-            if (s.find("4") != string::npos) {
-                t.push_back("4");
-            }
-            spec->mReplaceables.push_back(t);
-            continue;
-        }
-
-        if (s.compare(0, 2, "t:") == 0) {
-            vector<string> t;
-            for (int i = 0; i < NUM_TYPES; i++) {
-                if (s.find(TYPES[i].specType) != string::npos) {
-                    t.push_back(TYPES[i].cType);
-                }
-            }
-            spec->mReplaceables.push_back(t);
-            continue;
-        }
-
-        if (s.size() == 0) {
-            // eat empty line
-            continue;
-        }
-
-        printf("Error, line:\n");
-        printf("  %s\n", s.c_str());
-    }
-
-    delete spec;
-    return nullptr;
-}
-
-void Specification::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
-                               Function* function, int versionOfTestFiles) {
-    int start[4];
-    int end[4];
-    for (int i = 0; i < 4; i++) {
-        if (i < (int)mReplaceables.size()) {
-            start[i] = 0;
-            end[i] = mReplaceables[i].size();
-        } else {
-            start[i] = -1;
-            end[i] = 0;
-        }
-    }
-    for (int i4 = start[3]; i4 < end[3]; i4++) {
-        for (int i3 = start[2]; i3 < end[2]; i3++) {
-            for (int i2 = start[1]; i2 < end[1]; i2++) {
-                for (int i1 = start[0]; i1 < end[0]; i1++) {
-                    Permutation p(function, this, i1, i2, i3, i4);
-                    p.writeFiles(headerFile, rsFile, javaFile, versionOfTestFiles);
-                }
-            }
-        }
-    }
-}
-
-bool Specification::relevantForVersion(int versionOfTestFiles) const {
-    if (mMinVersion != 0 && mMinVersion > versionOfTestFiles) {
-        return false;
-    }
-    if (mMaxVersion != 0 && mMaxVersion < versionOfTestFiles) {
-        return false;
-    }
-    return true;
-}
-
-string Specification::expandString(string s, int i1, int i2, int i3, int i4) const {
-    if (mReplaceables.size() > 0) {
-        s = stringReplace(s, "#1", mReplaceables[0][i1]);
-    }
-    if (mReplaceables.size() > 1) {
-        s = stringReplace(s, "#2", mReplaceables[1][i2]);
-    }
-    if (mReplaceables.size() > 2) {
-        s = stringReplace(s, "#3", mReplaceables[2][i3]);
-    }
-    if (mReplaceables.size() > 3) {
-        s = stringReplace(s, "#4", mReplaceables[3][i4]);
-    }
-    return s;
-}
-
-Permutation::Permutation(Function* func, Specification* spec, int i1, int i2, int i3, int i4)
-    : mFunction(func),
-      mSpecification(spec),
-      mReturnIndex(-1),
-      mFirstInputIndex(-1),
-      mInputCount(0),
-      mOutputCount(0) {
-    // We expand the strings now to make capitalization easier.  The previous code preserved the #n
-    // markers just before emitting, which made capitalization difficult.
-    mName = spec->getName(i1, i2, i3, i4);
-    mCleanName = spec->getCleanName();
-    mTest = spec->getTest();
-    mPrecisionLimit = spec->getPrecisionLimit();
-    spec->getInlines(i1, i2, i3, i4, &mInline);
-    spec->getComments(i1, i2, i3, i4, &mComment);
-
-    vector<string> paramDefinitions;
-    spec->getParams(i1, i2, i3, i4, &paramDefinitions);
-    mHasFloatAnswers = false;
-    for (size_t i = 0; i < paramDefinitions.size(); i++) {
-        ParameterDefinition* def = new ParameterDefinition();
-        def->parseParameterDefinition(paramDefinitions[i], false, &mInputCount, &mOutputCount);
-        if (!def->isOutParameter && mFirstInputIndex < 0) {
-            mFirstInputIndex = mParams.size();
-        }
-        if (def->isOutParameter && def->isFloatType) {
-            mHasFloatAnswers = true;
-        }
-        mParams.push_back(def);
-    }
-
-    const string s = spec->getReturn(i1, i2, i3, i4);
-    if (!s.empty() && s != "void") {
-        ParameterDefinition* def = new ParameterDefinition();
-        // Adding "*" tells the parse method it's an output.
-        def->parseParameterDefinition(s, true, &mInputCount, &mOutputCount);
-        if (def->isOutParameter && def->isFloatType) {
-            mHasFloatAnswers = true;
-        }
-        mReturnIndex = mParams.size();
-        mParams.push_back(def);
-    }
-
-    mRsKernelName = "test" + capitalize(mName);
-    mJavaArgumentsClassName = "Arguments";
-    mJavaArgumentsNClassName = "Arguments";
-    mJavaCheckMethodName = "check" + capitalize(mCleanName);
-    mJavaVerifyMethodName = "verifyResults" + capitalize(mCleanName);
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        mRsKernelName += capitalize(p.rsType);
-        mJavaArgumentsClassName += capitalize(p.rsBaseType);
-        mJavaArgumentsNClassName += capitalize(p.rsBaseType);
-        if (p.mVectorSize != "1") {
-            mJavaArgumentsNClassName += "N";
-        }
-        mJavaCheckMethodName += capitalize(p.rsType);
-        mJavaVerifyMethodName += capitalize(p.rsType);
-    }
-    mJavaVerifierComputeMethodName = "compute" + capitalize(mCleanName);
-    mJavaVerifierVerifyMethodName = "verify" + capitalize(mCleanName);
-}
-
-void Permutation::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
-                             int versionOfTestFiles) {
-    writeHeaderSection(headerFile);
-    if (mSpecification->relevantForVersion(versionOfTestFiles) && mTest != "none") {
-        writeRsSection(rsFile);
-        writeJavaSection(javaFile);
-    }
-}
-
-void Permutation::writeHeaderSection(ofstream& file) const {
-    int minVersion = mSpecification->getMinVersion();
-    int maxVersion = mSpecification->getMaxVersion();
-    bool hasVersion = minVersion || maxVersion;
-
-    if (hasVersion) {
-        if (maxVersion) {
-            file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion
-                 << ") && (RS_VERSION <= " << maxVersion << "))\n";
-        } else {
-            file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion << "))\n";
-        }
-    }
-
-    file << "/**\n";
-    for (size_t ct = 0; ct < mComment.size(); ct++) {
-        if (!mComment[ct].empty()) {
-            file << " * " << mComment[ct] << "\n";
-        } else {
-            file << " *\n";
-        }
-    }
-    file << " *\n";
-    if (minVersion || maxVersion) {
-        if (maxVersion) {
-            file << " * Suppored by API versions " << minVersion << " - " << maxVersion << "\n";
-        } else {
-            file << " * Supported by API versions " << minVersion << " and newer.\n";
-        }
-    }
-    file << " */\n";
-    if (mInline.size() > 0) {
-        file << "static ";
-    } else {
-        file << "extern ";
-    }
-    if (mReturnIndex >= 0) {
-        file << mParams[mReturnIndex]->rsType;
-    } else {
-        file << "void";
-    }
-    file << " __attribute__((";
-    if (mOutputCount <= 1) {
-        file << "const, ";
-    }
-    file << "overloadable))";
-    file << mName;
-    file << "(";
-    bool needComma = false;
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        if (i != mReturnIndex) {
-            const ParameterDefinition& p = *mParams[i];
-            if (needComma) {
-                file << ", ";
-            }
-            file << p.rsType;
-            if (p.isOutParameter) {
-                file << "*";
-            }
-            if (!p.specName.empty()) {
-                file << " " << p.specName;
-            }
-            needComma = true;
-        }
-    }
-    if (mInline.size() > 0) {
-        file << ") {\n";
-        for (size_t ct = 0; ct < mInline.size(); ct++) {
-            file << " " << mInline[ct].c_str() << "\n";
-        }
-        file << "}\n";
-    } else {
-        file << ");\n";
-    }
-    if (hasVersion) {
-        file << "#endif\n";
-    }
-    file << "\n";
-}
-
-/* Write the section of the .rs file for this permutation.
- *
- * We communicate the extra input and output parameters via global allocations.
- * For example, if we have a function that takes three arguments, two for input
- * and one for output:
- *
- * start:
- * name: gamn
- * ret: float3
- * arg: float3 a
- * arg: int b
- * arg: float3 *c
- * end:
- *
- * We'll produce:
- *
- * rs_allocation gAllocInB;
- * rs_allocation gAllocOutC;
- *
- * float3 __attribute__((kernel)) test_gamn_float3_int_float3(float3 inA, unsigned int x) {
- *    int inB;
- *    float3 outC;
- *    float2 out;
- *    inB = rsGetElementAt_int(gAllocInB, x);
- *    out = gamn(a, in_b, &outC);
- *    rsSetElementAt_float4(gAllocOutC, &outC, x);
- *    return out;
- * }
- *
- * We avoid re-using x and y from the definition because these have reserved
- * meanings in a .rs file.
- */
-void Permutation::writeRsSection(ofstream& rs) const {
-    // Write the allocation declarations we'll need.
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        // Don't need allocation for one input and one return value.
-        if (i != mReturnIndex && i != mFirstInputIndex) {
-            mFunction->writeRsAllocationDefinition(p);
-        }
-    }
-    rs << "\n";
-
-    // Write the function header.
-    if (mReturnIndex >= 0) {
-        rs << mParams[mReturnIndex]->rsType;
-    } else {
-        rs << "void";
-    }
-    rs << " __attribute__((kernel)) " << mRsKernelName;
-    rs << "(";
-    bool needComma = false;
-    if (mFirstInputIndex >= 0) {
-        rs << mParams[mFirstInputIndex]->rsType << " " << mParams[mFirstInputIndex]->variableName;
-        needComma = true;
-    }
-    if (mOutputCount > 1 || mInputCount > 1) {
-        if (needComma) {
-            rs << ", ";
-        }
-        rs << "unsigned int x";
-    }
-    rs << ") {\n";
-
-    // Write the local variable declarations and initializations.
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        if (i == mFirstInputIndex || i == mReturnIndex) {
-            continue;
-        }
-        const ParameterDefinition& p = *mParams[i];
-        rs << tab(1) << p.rsType << " " << p.variableName;
-        if (p.isOutParameter) {
-            rs << " = 0;\n";
-        } else {
-            rs << " = rsGetElementAt_" << p.rsType << "(" << p.rsAllocName << ", x);\n";
-        }
-    }
-
-    // Write the function call.
-    if (mReturnIndex >= 0) {
-        if (mOutputCount > 1) {
-            rs << tab(1) << mParams[mReturnIndex]->rsType << " "
-               << mParams[mReturnIndex]->variableName << " = ";
-        } else {
-            rs << tab(1) << "return ";
-        }
-    }
-    rs << mName << "(";
-    needComma = false;
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (i == mReturnIndex) {
-            continue;
-        }
-        if (needComma) {
-            rs << ", ";
-        }
-        if (p.isOutParameter) {
-            rs << "&";
-        }
-        rs << p.variableName;
-        needComma = true;
-    }
-    rs << ");\n";
-
-    if (mOutputCount > 1) {
-        // Write setting the extra out parameters into the allocations.
-        for (int i = 0; i < (int)mParams.size(); i++) {
-            const ParameterDefinition& p = *mParams[i];
-            if (p.isOutParameter && i != mReturnIndex) {
-                rs << tab(1) << "rsSetElementAt_" << p.rsType << "(" << p.rsAllocName << ", ";
-                if (passByAddressToSet(p.variableName)) {
-                    rs << "&";
-                }
-                rs << p.variableName << ", x);\n";
-            }
-        }
-        if (mReturnIndex >= 0) {
-            rs << tab(1) << "return " << mParams[mReturnIndex]->variableName << ";\n";
-        }
-    }
-    rs << "}\n";
-}
-
-bool Permutation::passByAddressToSet(const string& name) const {
-    string s = name;
-    int last = s.size() - 1;
-    char lastChar = s[last];
-    return lastChar >= '0' && lastChar <= '9';
-}
-
-void Permutation::writeJavaSection(ofstream& file) const {
-    // By default, we test the results using item by item comparison.
-    if (mTest == "scalar" || mTest == "limited") {
-        writeJavaArgumentClass(file, true);
-        writeJavaCheckMethod(file, true);
-        writeJavaVerifyScalarMethod(file, false);
-    } else if (mTest == "custom") {
-        writeJavaArgumentClass(file, true);
-        writeJavaCheckMethod(file, true);
-        writeJavaVerifyScalarMethod(file, true);
-    } else if (mTest == "vector") {
-        writeJavaArgumentClass(file, false);
-        writeJavaCheckMethod(file, true);
-        writeJavaVerifyVectorMethod(file);
-    } else if (mTest == "noverify") {
-        writeJavaCheckMethod(file, false);
-    }
-
-    // Register the check method to be called.  This code will be written at the end.
-    mFunction->addJavaCheckCall(mJavaCheckMethodName + "();");
-}
-
-void Permutation::writeJavaArgumentClass(ofstream& file, bool scalar) const {
-    string name;
-    if (scalar) {
-        name = mJavaArgumentsClassName;
-    } else {
-        name = mJavaArgumentsNClassName;
-    }
-    string s;
-    s += tab(1) + "public class " + name + " {\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        s += tab(2) + "public ";
-        if (p.isOutParameter && p.isFloatType && mTest != "custom") {
-            s += "Target.Floaty";
-        } else {
-            s += p.javaBaseType;
-        }
-        if (!scalar && p.mVectorSize != "1") {
-            s += "[]";
-        }
-        s += " " + p.variableName + ";\n";
-    }
-    s += tab(1) + "}\n\n";
-
-    mFunction->writeJavaArgumentClassDefinition(name, s);
-}
-
-void Permutation::writeJavaCheckMethod(ofstream& file, bool generateCallToVerifier) const {
-    file << tab(1) << "private void " << mJavaCheckMethodName << "() {\n";
-    // Generate the input allocations and initialization.
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (!p.isOutParameter) {
-            writeJavaInputAllocationDefinition(file, tab(2), p);
-        }
-    }
-    // Enforce ordering if needed.
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (!p.isOutParameter && !p.smallerParameter.empty()) {
-            string smallerAlloc = "in" + capitalize(p.smallerParameter);
-            file << tab(2) << "enforceOrdering(" << smallerAlloc << ", " << p.javaAllocName
-                 << ");\n";
-        }
-    }
-    writeJavaCallToRs(file, false, generateCallToVerifier);
-    writeJavaCallToRs(file, true, generateCallToVerifier);
-    file << tab(1) << "}\n\n";
-}
-
-void Permutation::writeJavaInputAllocationDefinition(ofstream& file, const string& indent,
-                                                     const ParameterDefinition& param) const {
-    string dataType;
-    char vectorSize;
-    convertToRsType(param.rsType, &dataType, &vectorSize);
-
-    string seed = hashString(mJavaCheckMethodName + param.javaAllocName);
-    file << indent << "Allocation " << param.javaAllocName << " = ";
-    if (param.compatibleTypeIndex >= 0) {
-        if (TYPES[param.typeIndex].kind == FLOATING_POINT) {
-            writeJavaRandomCompatibleFloatAllocation(file, dataType, seed, vectorSize,
-                                                     TYPES[param.compatibleTypeIndex],
-                                                     TYPES[param.typeIndex]);
-        } else {
-            writeJavaRandomCompatibleIntegerAllocation(file, dataType, seed, vectorSize,
-                                                       TYPES[param.compatibleTypeIndex],
-                                                       TYPES[param.typeIndex]);
-        }
-    } else if (!param.minValue.empty()) {
-        if (TYPES[param.typeIndex].kind != FLOATING_POINT) {
-            printf("range(,) is only supported for floating point\n");
-        } else {
-            file << "createRandomFloatAllocation(mRS, Element.DataType." << dataType << ", "
-                 << vectorSize << ", " << seed << ", " << param.minValue << ", " << param.maxValue
-                 << ")";
-        }
-    } else {
-        file << "createRandomAllocation(mRS, Element.DataType." << dataType << ", " << vectorSize
-            // TODO set to false only for native, i.e.
-            // << ", " << seed << ", " << (mTest == "limited" ? "false" : "true") << ")";
-            << ", " << seed << ", false)";
-    }
-    file << ";\n";
-}
-
-void Permutation::writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType,
-                                                           const string& seed, char vectorSize,
-                                                           const Type& compatibleType,
-                                                           const Type& generatedType) const {
-    file << "createRandomFloatAllocation"
-         << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
-    double minValue = 0.0;
-    double maxValue = 0.0;
-    switch (compatibleType.kind) {
-        case FLOATING_POINT: {
-            // We're generating floating point values.  We just worry about the exponent.
-            // Subtract 1 for the exponent sign.
-            int bits = min(compatibleType.exponentBits, generatedType.exponentBits) - 1;
-            maxValue = ldexp(0.95, (1 << bits) - 1);
-            minValue = -maxValue;
-            break;
-        }
-        case UNSIGNED_INTEGER:
-            maxValue = MaxDoubleForInteger(compatibleType.significantBits,
-                                           generatedType.significantBits);
-            minValue = 0.0;
-            break;
-        case SIGNED_INTEGER:
-            maxValue = MaxDoubleForInteger(compatibleType.significantBits,
-                                           generatedType.significantBits);
-            minValue = -maxValue - 1.0;
-            break;
-    }
-    file << scientific << std::setprecision(19);
-    file << minValue << ", " << maxValue << ")";
-    file.unsetf(ios_base::floatfield);
-}
-
-void Permutation::writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType,
-                                                             const string& seed, char vectorSize,
-                                                             const Type& compatibleType,
-                                                             const Type& generatedType) const {
-    file << "createRandomIntegerAllocation"
-         << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
-
-    if (compatibleType.kind == FLOATING_POINT) {
-        // Currently, all floating points can take any number we generate.
-        bool isSigned = generatedType.kind == SIGNED_INTEGER;
-        file << (isSigned ? "true" : "false") << ", " << generatedType.significantBits;
-    } else {
-        bool isSigned =
-                    compatibleType.kind == SIGNED_INTEGER && generatedType.kind == SIGNED_INTEGER;
-        file << (isSigned ? "true" : "false") << ", "
-             << min(compatibleType.significantBits, generatedType.significantBits);
-    }
-    file << ")";
-}
-
-void Permutation::writeJavaOutputAllocationDefinition(ofstream& file, const string& indent,
-                                                      const ParameterDefinition& param) const {
-    string dataType;
-    char vectorSize;
-    convertToRsType(param.rsType, &dataType, &vectorSize);
-    file << indent << "Allocation " << param.javaAllocName << " = Allocation.createSized(mRS, "
-         << "getElement(mRS, Element.DataType." << dataType << ", " << vectorSize
-         << "), INPUTSIZE);\n";
-}
-
-// Converts float2 to FLOAT_32 and 2, etc.
-void Permutation::convertToRsType(const string& name, string* dataType, char* vectorSize) const {
-    string s = name;
-    int last = s.size() - 1;
-    char lastChar = s[last];
-    if (lastChar >= '1' && lastChar <= '4') {
-        s.erase(last);
-        *vectorSize = lastChar;
-    } else {
-        *vectorSize = '1';
-    }
-    dataType->clear();
-    for (int i = 0; i < NUM_TYPES; i++) {
-        if (s == TYPES[i].cType) {
-            *dataType = TYPES[i].rsDataType;
-            break;
-        }
-    }
-}
-
-void Permutation::writeJavaVerifyScalarMethod(ofstream& file, bool verifierValidates) const {
-    writeJavaVerifyFunctionHeader(file);
-    string vectorSize = "1";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        writeJavaArrayInitialization(file, p);
-        if (p.mVectorSize != "1" && p.mVectorSize != vectorSize) {
-            if (vectorSize == "1") {
-                vectorSize = p.mVectorSize;
-            } else {
-                printf("Yikes, had vector %s and %s\n", vectorSize.c_str(), p.mVectorSize.c_str());
-            }
-        }
-    }
-
-    file << tab(2) << "for (int i = 0; i < INPUTSIZE; i++) {\n";
-    file << tab(3) << "for (int j = 0; j < " << vectorSize << " ; j++) {\n";
-
-    file << tab(4) << "// Extract the inputs.\n";
-    file << tab(4) << mJavaArgumentsClassName << " args = new " << mJavaArgumentsClassName
-         << "();\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (!p.isOutParameter) {
-            file << tab(4) << "args." << p.variableName << " = " << p.javaArrayName << "[i";
-            if (p.vectorWidth != "1") {
-                file << " * " << p.vectorWidth << " + j";
-            }
-            file << "];\n";
-        }
-    }
-
-    if (verifierValidates) {
-        file << tab(4) << "// Extract the outputs.\n";
-        for (size_t i = 0; i < mParams.size(); i++) {
-            const ParameterDefinition& p = *mParams[i];
-            if (p.isOutParameter) {
-                file << tab(4) << "args." << p.variableName << " = " << p.javaArrayName
-                     << "[i * " + p.vectorWidth + " + j];\n";
-            }
-        }
-        file << tab(4) << "// Ask the CoreMathVerifier to validate.\n";
-        if (mHasFloatAnswers) {
-            file << tab(4) << "Target target = new Target(relaxed);\n";
-        }
-        file << tab(4) << "String errorMessage = CoreMathVerifier." << mJavaVerifierVerifyMethodName
-             << "(args";
-        if (mHasFloatAnswers) {
-            file << ", target";
-        }
-        file << ");\n";
-        file << tab(4) << "boolean valid = errorMessage == null;\n";
-    } else {
-        file << tab(4) << "// Figure out what the outputs should have been.\n";
-        if (mHasFloatAnswers) {
-            file << tab(4) << "Target target = new Target(relaxed);\n";
-        }
-        file << tab(4) << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args";
-        if (mHasFloatAnswers) {
-            file << ", target";
-        }
-        file << ");\n";
-        file << tab(4) << "// Validate the outputs.\n";
-        file << tab(4) << "boolean valid = true;\n";
-        for (size_t i = 0; i < mParams.size(); i++) {
-            const ParameterDefinition& p = *mParams[i];
-            if (p.isOutParameter) {
-                writeJavaTestAndSetValid(file, 4, p, "", "[i * " + p.vectorWidth + " + j]");
-            }
-        }
-    }
-
-    file << tab(4) << "if (!valid) {\n";
-    file << tab(5) << "StringBuilder message = new StringBuilder();\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (p.isOutParameter) {
-            writeJavaAppendOutputToMessage(file, 5, p, "", "[i * " + p.vectorWidth + " + j]",
-                                           verifierValidates);
-        } else {
-            writeJavaAppendInputToMessage(file, 5, p, "args." + p.variableName);
-        }
-    }
-    if (verifierValidates) {
-        file << tab(5) << "message.append(errorMessage);\n";
-    }
-
-    file << tab(5) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
-    file << tab(7) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
-    file << tab(4) << "}\n";
-    file << tab(3) << "}\n";
-    file << tab(2) << "}\n";
-    file << tab(1) << "}\n\n";
-}
-
-void Permutation::writeJavaVerifyFunctionHeader(ofstream& file) const {
-    file << tab(1) << "private void " << mJavaVerifyMethodName << "(";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        file << "Allocation " << p.javaAllocName << ", ";
-    }
-    file << "boolean relaxed) {\n";
-}
-
-void Permutation::writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p,
-                                           const string& argsIndex,
-                                           const string& actualIndex) const {
-    writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex);
-    file << tab(indent + 1) << "valid = false;\n";
-    file << tab(indent) << "}\n";
-}
-
-void Permutation::writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p,
-                                        const string& argsIndex, const string& actualIndex) const {
-    file << tab(indent) << "if (";
-    if (p.isFloatType) {
-        file << "!args." << p.variableName << argsIndex << ".couldBe(" << p.javaArrayName
-             << actualIndex;
-        if (!mPrecisionLimit.empty()) {
-            file << ", " << mPrecisionLimit;
-        }
-        file << ")";
-    } else {
-        file << "args." << p.variableName << argsIndex << " != " << p.javaArrayName << actualIndex;
-    }
-    if (p.undefinedIfOutIsNan && mReturnIndex >= 0) {
-        file << " && !args." << mParams[mReturnIndex]->variableName << argsIndex << ".isNaN()";
-    }
-    file << ") {\n";
-}
-
-void Permutation::writeJavaAppendOutputToMessage(ofstream& file, int indent,
-                                                 const ParameterDefinition& p,
-                                                 const string& argsIndex, const string& actualIndex,
-                                                 bool verifierValidates) const {
-    if (verifierValidates) {
-        const string actual = "args." + p.variableName + argsIndex;
-        file << tab(indent) << "message.append(\"Output " + p.variableName + ": \");\n";
-        if (p.isFloatType) {
-            writeJavaAppendFloatVariableToMessage(file, indent, actual, true);
-        } else {
-            writeJavaAppendVariableToMessage(file, indent, p, actual);
-        }
-        writeJavaAppendNewLineToMessage(file, indent);
-    } else {
-        const string expected = "args." + p.variableName + argsIndex;
-        const string actual = p.javaArrayName + actualIndex;
-        file << tab(indent) << "message.append(\"Expected output " + p.variableName + ": \");\n";
-        if (p.isFloatType) {
-            writeJavaAppendFloatVariableToMessage(file, indent, expected, false);
-        } else {
-            writeJavaAppendVariableToMessage(file, indent, p, expected);
-        }
-        writeJavaAppendNewLineToMessage(file, indent);
-        file << tab(indent) << "message.append(\"Actual   output " + p.variableName + ": \");\n";
-        writeJavaAppendVariableToMessage(file, indent, p, actual);
-
-        writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex);
-        file << tab(indent + 1) << "message.append(\" FAIL\");\n";
-        file << tab(indent) << "}\n";
-        writeJavaAppendNewLineToMessage(file, indent);
-    }
-}
-
-void Permutation::writeJavaAppendInputToMessage(ofstream& file, int indent,
-                                                const ParameterDefinition& p,
-                                                const string& actual) const {
-    file << tab(indent) << "message.append(\"Input " + p.variableName + ": \");\n";
-    writeJavaAppendVariableToMessage(file, indent, p, actual);
-    writeJavaAppendNewLineToMessage(file, indent);
-}
-
-void Permutation::writeJavaAppendNewLineToMessage(ofstream& file, int indent) const {
-    file << tab(indent) << "message.append(\"\\n\");\n";
-}
-
-void Permutation::writeJavaAppendVariableToMessage(ofstream& file, int indent,
-                                                   const ParameterDefinition& p,
-                                                   const string& value) const {
-    if (p.specType == "f16" || p.specType == "f32") {
-        file << tab(indent) << "message.append(String.format(\"%14.8g {%8x} %15a\",\n";
-        file << tab(indent + 2) << value << ", "
-             << "Float.floatToRawIntBits(" << value << "), " << value << "));\n";
-    } else if (p.specType == "f64") {
-        file << tab(indent) << "message.append(String.format(\"%24.8g {%16x} %31a\",\n";
-        file << tab(indent + 2) << value << ", "
-             << "Double.doubleToRawLongBits(" << value << "), " << value << "));\n";
-    } else if (p.specType[0] == 'u') {
-        file << tab(indent) << "message.append(String.format(\"0x%x\", " << value << "));\n";
-    } else {
-        file << tab(indent) << "message.append(String.format(\"%d\", " << value << "));\n";
-    }
-}
-
-void Permutation::writeJavaAppendFloatVariableToMessage(ofstream& file, int indent,
-                                                        const string& value,
-                                                        bool regularFloat) const {
-    file << tab(indent) << "message.append(";
-    if (regularFloat) {
-        file << "Float.toString(" << value << ")";
-    } else {
-        file << value << ".toString()";
-    }
-    file << ");\n";
-}
-
-void Permutation::writeJavaVectorComparison(ofstream& file, int indent,
-                                            const ParameterDefinition& p) const {
-    if (p.mVectorSize == "1") {
-        writeJavaTestAndSetValid(file, indent, p, "", "[i]");
-
-    } else {
-        file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
-        writeJavaTestAndSetValid(file, indent + 1, p, "[j]", "[i * " + p.vectorWidth + " + j]");
-        file << tab(indent) << "}\n";
-    }
-}
-
-void Permutation::writeJavaAppendVectorInputToMessage(ofstream& file, int indent,
-                                                      const ParameterDefinition& p) const {
-    if (p.mVectorSize == "1") {
-        writeJavaAppendInputToMessage(file, indent, p, p.javaArrayName + "[i]");
-    } else {
-        file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
-        writeJavaAppendInputToMessage(file, indent + 1, p,
-                                      p.javaArrayName + "[i * " + p.vectorWidth + " + j]");
-        file << tab(indent) << "}\n";
-    }
-}
-
-void Permutation::writeJavaAppendVectorOutputToMessage(ofstream& file, int indent,
-                                                       const ParameterDefinition& p) const {
-    if (p.mVectorSize == "1") {
-        writeJavaAppendOutputToMessage(file, indent, p, "", "[i]", false);
-
-    } else {
-        file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
-        writeJavaAppendOutputToMessage(file, indent + 1, p, "[j]",
-                                       "[i * " + p.vectorWidth + " + j]", false);
-        file << tab(indent) << "}\n";
-    }
-}
-
-void Permutation::writeJavaVerifyVectorMethod(ofstream& file) const {
-    writeJavaVerifyFunctionHeader(file);
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        writeJavaArrayInitialization(file, p);
-    }
-    file << tab(2) + "for (int i = 0; i < INPUTSIZE; i++) {\n";
-    file << tab(3) << mJavaArgumentsNClassName << " args = new " << mJavaArgumentsNClassName
-         << "();\n";
-
-    file << tab(3) << "// Create the appropriate sized arrays in args\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (p.mVectorSize != "1") {
-            string type = p.javaBaseType;
-            if (p.isOutParameter && p.isFloatType) {
-                type = "Target.Floaty";
-            }
-            file << tab(3) << "args." << p.variableName << " = new " << type << "[" << p.mVectorSize
-                 << "];\n";
-        }
-    }
-
-    file << tab(3) << "// Fill args with the input values\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (!p.isOutParameter) {
-            if (p.mVectorSize == "1") {
-                file << tab(3) << "args." << p.variableName << " = " << p.javaArrayName + "[i]"
-                     << ";\n";
-            } else {
-                file << tab(3) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
-                file << tab(4) << "args." << p.variableName + "[j] = "
-                     << p.javaArrayName + "[i * " + p.vectorWidth + " + j]"
-                     << ";\n";
-                file << tab(3) << "}\n";
-            }
-        }
-    }
-    file << tab(3) << "Target target = new Target(relaxed);\n";
-    file << tab(3) << "CoreMathVerifier." << mJavaVerifierComputeMethodName
-         << "(args, target);\n\n";
-
-    file << tab(3) << "// Compare the expected outputs to the actual values returned by RS.\n";
-    file << tab(3) << "boolean valid = true;\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (p.isOutParameter) {
-            writeJavaVectorComparison(file, 3, p);
-        }
-    }
-
-    file << tab(3) << "if (!valid) {\n";
-    file << tab(4) << "StringBuilder message = new StringBuilder();\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (p.isOutParameter) {
-            writeJavaAppendVectorOutputToMessage(file, 4, p);
-        } else {
-            writeJavaAppendVectorInputToMessage(file, 4, p);
-        }
-    }
-
-    file << tab(4) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
-    file << tab(6) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
-    file << tab(3) << "}\n";
-    file << tab(2) << "}\n";
-    file << tab(1) << "}\n\n";
-}
-
-void Permutation::writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerifier) const {
-    string script = "script";
-    if (relaxed) {
-        script += "Relaxed";
-    }
-
-    file << tab(2) << "try {\n";
-    for (size_t i = 0; i < mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (p.isOutParameter) {
-            writeJavaOutputAllocationDefinition(file, tab(3), p);
-        }
-    }
-
-    for (int i = 0; i < (int)mParams.size(); i++) {
-        const ParameterDefinition& p = *mParams[i];
-        if (i != mReturnIndex && i != mFirstInputIndex) {
-            file << tab(3) << script << ".set_" << p.rsAllocName << "(" << p.javaAllocName
-                 << ");\n";
-        }
-    }
-
-    file << tab(3) << script << ".forEach_" << mRsKernelName << "(";
-    bool needComma = false;
-    if (mFirstInputIndex >= 0) {
-        file << mParams[mFirstInputIndex]->javaAllocName;
-        needComma = true;
-    }
-    if (mReturnIndex >= 0) {
-        if (needComma) {
-            file << ", ";
-        }
-        file << mParams[mReturnIndex]->variableName << ");\n";
-    }
-
-    if (generateCallToVerifier) {
-        file << tab(3) << mJavaVerifyMethodName << "(";
-        for (size_t i = 0; i < mParams.size(); i++) {
-            const ParameterDefinition& p = *mParams[i];
-            file << p.variableName << ", ";
-        }
-
-        if (relaxed) {
-            file << "true";
-        } else {
-            file << "false";
-        }
-        file << ");\n";
-    }
-    file << tab(2) << "} catch (Exception e) {\n";
-    file << tab(3) << "throw new RSRuntimeException(\"RenderScript. Can't invoke forEach_"
-         << mRsKernelName << ": \" + e.toString());\n";
-    file << tab(2) << "}\n";
-}
-
-}  // namespace
-
-int main(int argc, char* argv[]) {
-    int versionOfTestFiles = 0;
-    vector<string> specFileNames;
-    if (!parseCommandLine(argc, argv, &versionOfTestFiles, &specFileNames)) {
-        printf("Usage: gen_runtime spec_file [spec_file...] [-v version_of_test_files]\n");
-        return -1;
-    }
-    int result = 0;
-    for (size_t i = 0; i < specFileNames.size(); i++) {
-        SpecFile specFile(specFileNames[i]);
-        if (!specFile.process(versionOfTestFiles)) {
-            result = -1;
-        }
-    }
-    return result;
-}
diff --git a/api/generate.sh b/api/generate.sh
index 44c9e80..0881690 100755
--- a/api/generate.sh
+++ b/api/generate.sh
@@ -16,9 +16,14 @@
 #
 
 set -e
-g++ gen_runtime.cpp -std=c++11 -Wall -o gen_runtime
-./gen_runtime -v 21 rs_core_math.spec
-mv GeneratedTest*.java ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/
-mv GeneratedTest*.rs ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/
-mv rs_core_math.rsh ../scriptc/
-rm ./gen_runtime
+g++ Generator.cpp Specification.cpp GenerateHtmlDocumentation.cpp GenerateHeaderFiles.cpp GenerateTestFiles.cpp Scanner.cpp Utilities.cpp -g -std=c++11 -Wall -o generator
+
+./generator rs_allocation.spec rs_atomic.spec rs_core_math.spec rs_core.spec rs_debug.spec rs_element.spec rs_graphics.spec rs_math.spec rs_matrix.spec rs_mesh.spec rs_object.spec rs_program.spec rs_quaternion.spec rs_sampler.spec rs_time.spec rs_types.spec
+
+rm ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/GeneratedTest*
+mv GeneratedTest* ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/
+
+mv *.rsh ../scriptc
+
+rm *.html # TODO handle the documentation files.
+rm generator
diff --git a/api/rs_allocation.spec b/api/rs_allocation.spec
new file mode 100644
index 0000000..51ec190
--- /dev/null
+++ b/api/rs_allocation.spec
@@ -0,0 +1,473 @@
+#
+# 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.
+#
+
+header:
+summary: Allocation routines
+description:
+ Functions that can be used to query the characteristics of an allocation,
+ to set and get elements of the allocation.
+end:
+
+function: rsAllocationCopy1DRange
+version: 14
+ret: void
+arg: rs_allocation dstAlloc, "Allocation to copy data into."
+arg: uint32_t dstOff, "The offset of the first element to be copied in the destination allocation."
+arg: uint32_t dstMip, "Mip level in the destination allocation."
+arg: uint32_t count, "The number of elements to be copied."
+arg: rs_allocation srcAlloc, "The source data allocation."
+arg: uint32_t srcOff, "The offset of the first element in data to be copied in the source allocation."
+arg: uint32_t srcMip, "Mip level in the source allocation."
+summary: Copy consecutive values between allocations
+description:
+ Copies part of an allocation into another allocation.
+
+ The two allocations must be different.  Using this function to copy whithin
+ the same allocation yields undefined results.
+test: none
+end:
+
+
+function: rsAllocationCopy2DRange
+version: 14
+ret: void
+arg: rs_allocation dstAlloc, "Allocation to copy data into."
+arg: uint32_t dstXoff, "X offset of the region to update in the destination allocation."
+arg: uint32_t dstYoff, "Y offset of the region to update in the destination allocation."
+arg: uint32_t dstMip, "Mip level in the destination allocation."
+arg: rs_allocation_cubemap_face dstFace, "Cubemap face of the destination allocation, ignored for allocations that aren't cubemaps."
+arg: uint32_t width, "Width of the incoming region to update."
+arg: uint32_t height, "Height of the incoming region to update."
+arg: rs_allocation srcAlloc, "The source data allocation."
+arg: uint32_t srcXoff, "X offset in data of the source allocation."
+arg: uint32_t srcYoff, "Y offset in data of the source allocation."
+arg: uint32_t srcMip, "Mip level in the source allocation."
+arg: rs_allocation_cubemap_face srcFace, "Cubemap face of the source allocation, ignored for allocations that aren't cubemaps."
+summary: Copy a rectangular region between allocations
+description:
+ Copy a rectangular region into the allocation from another allocation.
+
+ The two allocations must be different.  Using this function to copy whithin
+ the same allocation yields undefined results.
+test: none
+end:
+
+function: rsAllocationGetDimFaces
+ret: uint32_t, "Returns 1 if more than one face is present, 0 otherwise."
+arg: rs_allocation a
+summary: Presence of more than one face
+description:
+ If the allocation is a cubemap, this function returns 1 if there's more than one
+ face present.  In all other cases, it returns 0.
+test: none
+end:
+
+function: rsAllocationGetDimLOD
+ret: uint32_t, "Returns 1 if more than one LOD is present, 0 otherwise."
+arg: rs_allocation a
+summary: Presence of levels of details
+description:
+ Query an allocation for the presence of more than one Level Of Details.  This is useful for mipmaps.
+test: none
+end:
+
+function: rsAllocationGetDimX
+ret: uint32_t, "The X dimension of the allocation."
+arg: rs_allocation a
+summary: Size of the X dimension
+description:
+ Returns the size of the X dimension of the allocation.
+test: none
+end:
+
+function: rsAllocationGetDimY
+ret: uint32_t, "The Y dimension of the allocation."
+arg: rs_allocation a
+summary: Size of the Y dimension
+description:
+ Returns the size of the Y dimension of the allocation.
+ If the allocation has less than two dimensions, returns 0.
+test: none
+end:
+
+function: rsAllocationGetDimZ
+ret: uint32_t, "The Z dimension of the allocation."
+arg: rs_allocation a
+summary: Size of the Z dimension
+description:
+ Returns the size of the Z dimension of the allocation.
+ If the allocation has less than three dimensions, returns 0.
+test: none
+end:
+
+function: rsAllocationGetElement
+ret: rs_element, "element describing allocation layout"
+arg: rs_allocation a, "allocation to get data from"
+summary:
+description:
+ Get the element object describing the allocation's layout
+test: none
+end:
+
+function: rsAllocationIoReceive
+version: 16
+ret: void
+arg: rs_allocation a, "allocation to work on"
+summary: Receive new content from the queue
+description:
+ Receive a new set of contents from the queue.
+test: none
+end:
+
+function: rsAllocationIoSend
+version: 16
+ret: void
+arg: rs_allocation a, "allocation to work on"
+summary: Send new content to the queue
+description:
+ Send the contents of the Allocation to the queue.
+test: none
+end:
+
+function: rsAllocationVLoadX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+summary:
+description:
+ Get a single element from an allocation.
+test: none
+end:
+
+function: rsAllocationVLoadX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsAllocationVLoadX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+test: none
+end:
+
+function: rsAllocationVStoreX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+summary:
+description:
+ Set a single element of an allocation.
+test: none
+end:
+
+function: rsAllocationVStoreX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsAllocationVStoreX_#2#1
+version: 22
+w: 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+test: none
+end:
+
+function: rsGetAllocation
+ret: rs_allocation
+arg: const void* p
+summary: Returns the Allocation for a given pointer
+description:
+ Returns the Allocation for a given pointer.  The pointer should point within
+ a valid allocation.  The results are undefined if the pointer is not from a
+ valid allocation.
+
+ This function is deprecated and will be removed from the SDK in a future
+ release.
+test: none
+end:
+
+function: rsGetElementAt
+ret: const void*
+arg: rs_allocation a
+arg: uint32_t x
+summary: Get an element
+description:
+ Extract a single element from an allocation.
+test: none
+end:
+
+function: rsGetElementAt
+ret: const void*
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsGetElementAt
+ret: const void*
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 9 17
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+inline:
+ return ((#2#1 *)rsGetElementAt(a, x))[0];
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 9 17
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+inline:
+ return ((#2#1 *)rsGetElementAt(a, x, y))[0];
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 9 17
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+inline:
+ return ((#2#1 *)rsGetElementAt(a, x, y, z))[0];
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsGetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: #2#1
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+test: none
+end:
+
+function: rsGetElementAtYuv_uchar_U
+version: 18
+ret: uchar
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+summary:
+description:
+ Extract a single element from an allocation.
+
+ Coordinates are in the dimensions of the Y plane
+test: none
+end:
+
+function: rsGetElementAtYuv_uchar_V
+version: 18
+ret: uchar
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+summary:
+description:
+ Extract a single element from an allocation.
+
+ Coordinates are in the dimensions of the Y plane
+test: none
+end:
+
+function: rsGetElementAtYuv_uchar_Y
+version: 18
+ret: uchar
+arg: rs_allocation a
+arg: uint32_t x
+arg: uint32_t y
+summary:
+description:
+ Extract a single element from an allocation.
+test: none
+end:
+
+function: rsSample
+version: 16
+ret: float4
+arg: rs_allocation a, "allocation to sample from"
+arg: rs_sampler s, "sampler state"
+arg: float location, "location to sample from"
+summary:
+description:
+ Fetch allocation in a way described by the sampler
+
+ If your allocation is 1D, use the variant with float for location.
+ For 2D, use the float2 variant.
+test: none
+end:
+
+function: rsSample
+version: 16
+ret: float4
+arg: rs_allocation a
+arg: rs_sampler s
+arg: float location
+arg: float lod, "mip level to sample from, for fractional values mip levels will be interpolated if RS_SAMPLER_LINEAR_MIP_LINEAR is used"
+test: none
+end:
+
+function: rsSample
+version: 16
+ret: float4
+arg: rs_allocation a
+arg: rs_sampler s
+arg: float2 location
+test: none
+end:
+
+function: rsSample
+version: 16
+ret: float4
+arg: rs_allocation a
+arg: rs_sampler s
+arg: float2 location
+arg: float lod
+test: none
+end:
+
+function: rsSetElementAt
+version: 18
+ret: void
+arg: rs_allocation a
+arg: void* ptr
+arg: uint32_t x
+summary: Set an element
+description:
+ Set single element of an allocation.
+test: none
+end:
+
+function: rsSetElementAt
+version: 18
+ret: void
+arg: rs_allocation a
+arg: void* ptr
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsSetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+test: none
+end:
+
+function: rsSetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+arg: uint32_t y
+test: none
+end:
+
+function: rsSetElementAt_#2#1
+version: 18
+w: 1, 2, 3, 4
+t: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
+ret: void
+arg: rs_allocation a
+arg: #2#1 val
+arg: uint32_t x
+arg: uint32_t y
+arg: uint32_t z
+test: none
+end:
diff --git a/api/rs_atomic.spec b/api/rs_atomic.spec
new file mode 100644
index 0000000..8add583
--- /dev/null
+++ b/api/rs_atomic.spec
@@ -0,0 +1,229 @@
+#
+# 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.
+#
+
+header:
+summary: Atomic routines
+description:
+ To update values shared between multiple threads, use the functions below.
+ They ensure that the values are atomically updated, i.e. that the memory
+ reads, the updates, and the memory writes are all done in the right order.
+
+ These functions are slower than just doing the non-atomic variants, so use
+ them only when synchronization is needed.
+
+ Note that in RenderScript, your code is likely to be running in separate
+ threads even though you did not explicitely create them.  The RenderScript
+ runtime will very often split the execution of one kernel across multiple
+ threads.  Updating globals should be done with atomic functions.  If possible,
+ modify your algorithm to avoid them altogether.
+end:
+
+function: rsAtomicAdd
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to modify"
+arg: int32_t value, "Amount to add"
+summary: Thread-safe addition
+description:
+ Atomicly adds a value to the value at addr, i.e. <code>*addr += value</code>.
+test: none
+end:
+
+function: rsAtomicAdd
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+arg: uint32_t value
+test: none
+end:
+
+function: rsAtomicAnd
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to modify"
+arg: int32_t value, "Value to and with"
+summary: Thread-safe bitwise and
+description:
+ Atomicly performs a bitwise and of two values, storing the result back at addr,
+ i.e. <code>*addr &= value</code>
+test: none
+end:
+
+function: rsAtomicAnd
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+arg: uint32_t value
+test: none
+end:
+
+function: rsAtomicCas
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "The address to compare and replace if the compare passes."
+arg: int32_t compareValue, "The value to test *addr against."
+arg: int32_t newValue, "The value to write if the test passes."
+summary: Thread-safe compare and set
+description:
+ If the value at addr matches compareValue then the newValue is written at addr,
+ i.e. <code>if (*addr == compareValue) { *addr = newValue; }</code>
+
+ You can check that the value was written by checking that the value returned
+ by rsAtomicCas is compareValue.
+test: none
+end:
+
+function: rsAtomicCas
+version: 14
+ret: uint32_t
+arg: volatile uint32_t* addr
+arg: uint32_t compareValue
+arg: uint32_t newValue
+test: none
+end:
+
+function: rsAtomicDec
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to decrement"
+summary: Thread-safe decrement
+description:
+ Atomicly subtracts one from the value at addr.  Equal to <code>@rsAtomicSub(addr, 1)</code>
+test: none
+end:
+
+function: rsAtomicDec
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+test: none
+end:
+
+function: rsAtomicInc
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to increment"
+summary: Thread-safe increment
+description:
+ Atomicly adds one to the value at addr.  Equal to <code>@rsAtomicAdd(addr, 1)</code>
+test: none
+end:
+
+function: rsAtomicInc
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+test: none
+end:
+
+function: rsAtomicMax
+version: 14
+ret: uint32_t, "Old value"
+arg: volatile uint32_t* addr, "Address of the value to modify"
+arg: uint32_t value, "Comparison value"
+summary: Thread-safe maximum
+description:
+ Atomicly sets the value at addr to the maximum of addr and value, i.e.
+ <code>*addr = max(*addr, value)</code>
+test: none
+end:
+
+function: rsAtomicMax
+version: 14
+ret: int32_t
+arg: volatile int32_t* addr
+arg: int32_t value
+test: none
+end:
+
+function: rsAtomicMin
+version: 14
+ret: uint32_t, "Old value"
+arg: volatile uint32_t* addr, "Address of the value to modify"
+arg: uint32_t value, "Comparison value"
+summary: Thread-safe minimum
+description:
+ Atomicly sets the value at addr to the minimum of addr and value, i.e.
+ <code>*addr = min(*addr, value)</code>
+test: none
+end:
+
+function: rsAtomicMin
+version: 14
+ret: int32_t
+arg: volatile int32_t* addr
+arg: int32_t value
+test: none
+end:
+
+function: rsAtomicOr
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to modify"
+arg: int32_t value, "Value to or with"
+summary: Thread-safe bitwise or
+description:
+ Atomicly perform a bitwise or two values, storing the result at addr,
+ i.e. <code>*addr |= value</code>
+test: none
+end:
+
+function: rsAtomicOr
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+arg: uint32_t value
+test: none
+end:
+
+function: rsAtomicSub
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to modify"
+arg: int32_t value, "Amount to subtract"
+summary: Thread-safe subtraction
+description:
+ Atomicly subtracts a value from the value at addr, i.e. <code>*addr -= value</code>
+test: none
+end:
+
+function: rsAtomicSub
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+arg: uint32_t value
+test: none
+end:
+
+function: rsAtomicXor
+version: 14
+ret: int32_t, "Old value"
+arg: volatile int32_t* addr, "Address of the value to modify"
+arg: int32_t value, "Value to xor with"
+summary: Thread-safe bitwise exclusive or
+description:
+ Atomicly performs a bitwise xor of two values, storing the result at addr,
+ i.e. <code>*addr ^= value</code>
+test: none
+end:
+
+function: rsAtomicXor
+version: 20
+ret: int32_t
+arg: volatile uint32_t* addr
+arg: uint32_t value
+test: none
+end:
diff --git a/api/rs_core.spec b/api/rs_core.spec
new file mode 100644
index 0000000..bd5cda8
--- /dev/null
+++ b/api/rs_core.spec
@@ -0,0 +1,411 @@
+#
+# 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.
+#
+
+header:
+summary: TODO
+description:
+# TODO move elsewhere?
+ RenderScript is a high-performance runtime that provides
+ compute operations at the native level. RenderScript code is compiled on devices
+ at runtime to allow platform-independence as well.
+ This reference documentation describes the RenderScript runtime APIs, which you
+ can utilize to write RenderScript code in C99. The RenderScript compute header
+ files are automatically included for you.
+
+ To use RenderScript, you need to utilize the RenderScript runtime APIs documented here
+ as well as the Android framework APIs for RenderScript.
+ For documentation on the Android framework APIs, see the <a target="_parent" href="http://developer.android.com/reference/android/renderscript/package-summary.html">android.renderscript</a> package reference.
+ For more information on how to develop with RenderScript and how the runtime and
+ Android framework APIs interact, see the <a target="_parent" href="http://developer.android.com/guide/topics/renderscript/index.html">RenderScript developer guide</a>
+ and the <a target="_parent" href="http://developer.android.com/resources/samples/RenderScript/index.html">RenderScript samples</a>.
+include:
+ #define RS_KERNEL __attribute__((kernel))
+
+ #include "rs_types.rsh"
+ #include "rs_allocation.rsh"
+ #include "rs_atomic.rsh"
+ #include "rs_core_math.rsh"
+ #include "rs_debug.rsh"
+ #include "rs_element.rsh"
+ #include "rs_math.rsh"
+ #include "rs_matrix.rsh"
+ #include "rs_object.rsh"
+ #include "rs_quaternion.rsh"
+ #include "rs_sampler.rsh"
+ #include "rs_time.rsh"
+end:
+
+type: rs_for_each_strategy_t
+enum: rs_for_each_strategy
+value: RS_FOR_EACH_STRATEGY_SERIAL = 0
+value: RS_FOR_EACH_STRATEGY_DONT_CARE = 1
+value: RS_FOR_EACH_STRATEGY_DST_LINEAR = 2
+value: RS_FOR_EACH_STRATEGY_TILE_SMALL = 3
+value: RS_FOR_EACH_STRATEGY_TILE_MEDIUM = 4
+value: RS_FOR_EACH_STRATEGY_TILE_LARGE = 5
+summary: Launch order hint for rsForEach calls
+description:
+ Launch order hint for rsForEach calls.  This provides a hint to the system to
+ determine in which order the root function of the target is called with each
+ cell of the allocation.
+
+ This is a hint and implementations may not obey the order.
+end:
+
+type: rs_kernel_context
+version: 23
+simple: const struct rs_kernel_context_t *
+summary: Opaque handle to RenderScript kernel invocation context
+description:
+ TODO
+end:
+
+type: rs_script_call_t
+struct: rs_script_call
+field: rs_for_each_strategy_t strategy
+field: uint32_t xStart
+field: uint32_t xEnd
+field: uint32_t yStart
+field: uint32_t yEnd
+field: uint32_t zStart
+field: uint32_t zEnd
+field: uint32_t arrayStart
+field: uint32_t arrayEnd
+summary: Provides extra information to a rsForEach call
+description:
+ Structure to provide extra information to a rsForEach call.  Primarly used to
+ restrict the call to a subset of cells in the allocation.
+end:
+
+function: rsForEach
+version: 9 13
+ret: void
+arg: rs_script script, "The target script to call"
+arg: rs_allocation input, "The allocation to source data from"
+arg: rs_allocation output, "the allocation to write date into"
+arg: const void* usrData, "The user defined params to pass to the root script.  May be NULL."
+arg: const rs_script_call_t* sc, "Extra control infomation used to select a sub-region of the allocation to be processed or suggest a walking strategy.  May be NULL."
+summary:
+description:
+ Make a script to script call to launch work. One of the input or output is
+ required to be a valid object. The input and output must be of the same
+ dimensions.
+test: none
+end:
+
+function: rsForEach
+version: 9 13
+ret: void
+arg: rs_script script
+arg: rs_allocation input
+arg: rs_allocation output
+arg: const void* usrData
+test: none
+end:
+
+function: rsForEach
+version: 14 20
+ret: void
+arg: rs_script script
+arg: rs_allocation input
+arg: rs_allocation output
+arg: const void* usrData
+arg: size_t usrDataLen, "The size of the userData structure.  This will be used to perform a shallow copy of the data if necessary."
+arg: const rs_script_call_t* sc
+test: none
+end:
+
+function: rsForEach
+version: 14 20
+ret: void
+arg: rs_script script
+arg: rs_allocation input
+arg: rs_allocation output
+arg: const void* usrData
+arg: size_t usrDataLen
+test: none
+end:
+
+function: rsForEach
+version: 14
+ret: void
+arg: rs_script script
+arg: rs_allocation input
+arg: rs_allocation output
+test: none
+end:
+
+function: rsSendToClient
+ret: bool
+arg: int cmdID
+summary:
+description:
+ Send a message back to the client.  Will not block and returns true
+ if the message was sendable and false if the fifo was full.
+ A message ID is required.  Data payload is optional.
+test: none
+end:
+
+function: rsSendToClient
+ret: bool
+arg: int cmdID
+arg: const void* data
+arg: uint len
+test: none
+end:
+
+function: rsSendToClientBlocking
+ret: void
+arg: int cmdID
+summary:
+description:
+ Send a message back to the client, blocking until the message is queued.
+ A message ID is required.  Data payload is optional.
+test: none
+end:
+
+function: rsSendToClientBlocking
+ret: void
+arg: int cmdID
+arg: const void* data
+arg: uint len
+test: none
+end:
+
+function: rsGetArray0
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Index in the Array0 dimension for the specified context
+description:
+ Returns the index in the Array0 dimension of the cell being processed,
+ as specified by the supplied context.
+
+ This context is created when a kernel is launched and updated at each
+ iteration.  It contains common characteristics of the allocations being
+ iterated over and rarely used indexes, like the Array0 index.
+
+ You can access the context by adding a rs_kernel_context argument to your
+ kernel function.  E.g.<br/>
+ <code>short RS_KERNEL myKernel(short value, uint32_t x, rs_kernel_context context) {<br/>
+ &nbsp;&nbsp;// The current index in the common x, y, z, w dimensions are accessed by<br/>
+ &nbsp;&nbsp;// adding these variables as arguments.  For the more rarely used indexes<br/>
+ &nbsp;&nbsp;// to the other dimensions, extract them from the context:<br/>
+ &nbsp;&nbsp;uint32_t index_a0 = rsGetArray0(context);<br/>
+ &nbsp;&nbsp;//...<br/>
+ }<br/></code>
+
+ This function returns 0 if the Array0 dimension is not present.
+test: none
+end:
+
+function: rsGetArray1
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Index in the Array1 dimension for the specified context
+description:
+ Returns the index in the Array1 dimension of the cell being processed,
+ as specified by the supplied context.  See @rsGetArray0() for an explanation
+ of the context.
+
+ Returns 0 if the Array1 dimension is not present.
+test: none
+end:
+
+function: rsGetArray2
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Index in the Array2 dimension for the specified context
+description:
+ Returns the index in the Array2 dimension of the cell being processed,
+ as specified by the supplied context.  See @rsGetArray0() for an explanation
+ of the context.
+
+ Returns 0 if the Array2 dimension is not present.
+test: none
+end:
+
+function: rsGetArray3
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Index in the Array3 dimension for the specified context
+description:
+ Returns the index in the Array3 dimension of the cell being processed,
+ as specified by the supplied context.  See @rsGetArray0() for an explanation
+ of the context.
+
+ Returns 0 if the Array3 dimension is not present.
+test: none
+end:
+
+function: rsGetDimArray0
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Array0 dimension for the specified context
+description:
+ Returns the size of the Array0 dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Array0 dimension is not present.
+#TODO Add an hyperlink to something that explains Array0/1/2/3
+# for the relevant functions.
+test: none
+end:
+
+function: rsGetDimArray1
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Array1 dimension for the specified context
+description:
+ Returns the size of the Array1 dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Array1 dimension is not present.
+test: none
+end:
+
+function: rsGetDimArray2
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Array2 dimension for the specified context
+description:
+ Returns the size of the Array2 dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Array2 dimension is not present.
+test: none
+end:
+
+function: rsGetDimArray3
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Array3 dimension for the specified context
+description:
+ Returns the size of the Array3 dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Array3 dimension is not present.
+test: none
+end:
+
+function: rsGetDimHasFaces
+version: 23
+ret: bool, "Returns true if more than one face is present, false otherwise."
+arg: rs_kernel_context ctxt
+summary: Presence of more than one face for the specified context
+description:
+ If the context refers to a cubemap, this function returns true if there's
+ more than one face present.  In all other cases, it returns false.
+ See @rsGetDimX() for an explanation of the context.
+
+ @rsAllocationGetDimFaces() is similar but returns 0 or 1 instead of a bool.
+test: none
+end:
+
+function: rsGetDimLod
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Number of levels of detail for the specified context
+description:
+ Returns the number of levels of detail for the specified context.
+ This is useful for mipmaps.  See @rsGetDimX() for an explanation of the context.
+ Returns 0 if Level of Detail is not used.
+
+ @rsAllocationGetDimLOD() is similar but returns 0 or 1 instead the actual
+ number of levels.
+test: none
+end:
+
+function: rsGetDimX
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the X dimension for the specified context
+description:
+ Returns the size of the X dimension for the specified context.
+
+ This context is created when a kernel is launched.  It contains common
+ characteristics of the allocations being iterated over by the kernel in
+ a very efficient structure.  It also contains rarely used indexes.
+
+ You can access it by adding a rs_kernel_context argument to your kernel
+ function.  E.g.<br/>
+ <code>int4 RS_KERNEL myKernel(int4 value, rs_kernel_context context) {<br/>
+ &nbsp;&nbsp;uint32_t size = rsGetDimX(context); //...<br/></code>
+test: none
+end:
+
+function: rsGetDimY
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Y dimension for the specified context
+description:
+ Returns the size of the X dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Y dimension is not present.
+test: none
+end:
+
+function: rsGetDimZ
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Size of the Z dimension for the specified context
+description:
+ Returns the size of the Z dimension for the specified context.
+ See @rsGetDimX() for an explanation of the context.
+
+ Returns 0 if the Z dimension is not present.
+test: none
+end:
+
+function: rsGetFace
+version: 23
+ret: rs_allocation_cubemap_face
+arg: rs_kernel_context ctxt
+summary: Coordinate of the Face for the specified context
+description:
+ Returns the face on which the cell being processed is found, as specified
+ by the supplied context.  See @rsGetArray0() for an explanation of the context.
+
+ Returns RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X if the face dimension is not
+ present.
+test: none
+end:
+
+function: rsGetLod
+version: 23
+ret: uint32_t
+arg: rs_kernel_context ctxt
+summary: Index in the Levels of Detail dimension for the specified context.
+description:
+ Returns the index in the Levels of Detail dimension of the cell being
+ processed, as specified by the supplied context.  See @rsGetArray0() for
+ an explanation of the context.
+
+ Returns 0 if the Levels of Detail dimension is not present.
+test: none
+end:
diff --git a/api/rs_core_math.spec b/api/rs_core_math.spec
index 3b0b601..bf47bdc 100644
--- a/api/rs_core_math.spec
+++ b/api/rs_core_math.spec
@@ -14,1016 +14,1095 @@
 # limitations under the License.
 #
 
-start:
+header:
+summary: Mathematical functions
+description:
+ Most mathematical functions can be applied to scalars and vectors.
+ When applied to vectors, a vector of the function applied to each entry
+ of the input is returned.
+
+ For example:<br/>
+ <code>
+ float3 a, b;<br/>
+ // The following call sets<br/>
+ //   a.x to sin(b.x),<br/>
+ //   a.y to sin(b.y), and<br/>
+ //   a.z to sin(b.z).<br/>
+ a = sin(b);<br/>
+ </code>
+
+ A few functions like @distance() and @length() interpret instead the input
+ as a single vector in n-dimensional space.
+
+ The precision of the mathematical operations is affected by the pragmas
+# TODO Create an anchor for the section of http://developer.android.com/guide/topics/renderscript/compute.html that details rs_fp_* and link them here.
+ rs_fp_relaxed and rs_fp_full.
+
+ Different precision/speed tradeoffs can be achieved by using three variants
+ of common math functions.  Functions with a name starting with<ul>
+ <li>native_ may have custom hardware implementations with weaker precision,</li>
+ <li>half_ may perform internal computations using 16 bit floats, and</li>
+ <li>fast_ are n-dimensional space computations that may use 16 bit floats.
+ </ul>
+end:
+
+function: abs
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: i8, i16, i32
-name: abs
 ret: u#2#1
 arg: #2#1 v
-comment:
+summary: Absolute value of an integer
+description:
  Returns the absolute value of an integer.
 
- For floats, use fabs().
-version: 9
+ For floats, use @fabs().
 end:
 
-start:
+function: acos
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: acos
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse cosine
+description:
  Returns the inverse cosine, in radians.
-version: 9
+
+ See also @native_acos().
 end:
 
-start:
+function: acosh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: acosh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Inverse hyperbolic cosine
+description:
  Returns the inverse hyperbolic cosine, in radians.
-version: 9
+
+ See also @native_acosh().
 end:
 
-start:
+function: acospi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: acospi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse cosine divided by pi
+description:
  Returns the inverse cosine in radians, divided by pi.
 
- To get an inverse cosine measured in degrees, use acospi(a) * 180.f.
-version: 9
+ To get an inverse cosine measured in degrees, use <code>acospi(a) * 180.f</code>.
+
+ See also @native_acospi().
 end:
 
-start:
+function: asin
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: asin
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse sine
+description:
  Returns the inverse sine, in radians.
-version: 9
+
+ See also @native_asin().
 end:
 
-start:
+function: asinh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: asinh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Inverse hyperbolic sine
+description:
  Returns the inverse hyperbolic sine, in radians.
-version: 9
+
+ See also @native_asinh().
 end:
 
-start:
+function: asinpi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: asinpi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse sine divided by pi
+description:
  Returns the inverse sine in radians, divided by pi.
 
- To get an inverse sine measured in degrees, use asinpi(a) * 180.f.
-version: 9
+ To get an inverse sine measured in degrees, use <code>asinpi(a) * 180.f</code>.
+
+ See also @native_asinpi().
 end:
 
-start:
+function: atan
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: atan
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse tangent
+description:
  Returns the inverse tangent, in radians.
-version: 9
+
+ See also @native_atan().
 end:
 
-start:
+function: atan2
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: atan2
 ret: #2#1
-arg: #2#1 numerator
-arg: #2#1 denominator
-comment:
- Returns the inverse tangent of (numerator / denominator), in radians.
+arg: #2#1 numerator, "The numerator"
+arg: #2#1 denominator, "The denominator.  Can be 0."
+summary: Inverse tangent of a ratio
+description:
+ Returns the inverse tangent of <code>(numerator / denominator)</code>, in radians.
 
- denominator can be 0.
-version: 9
+ See also @native_atan2().
 end:
 
-start:
+function: atan2pi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: atan2pi
 ret: #2#1
-arg: #2#1 numerator
-arg: #2#1 denominator
-comment:
- Returns the inverse tangent of (numerator / denominator), in radians, divided by pi.
+arg: #2#1 numerator, "The numerator"
+arg: #2#1 denominator, "The denominator.  Can be 0."
+summary: Inverse tangent of a ratio, divided by pi
+description:
+ Returns the inverse tangent of <code>(numerator / denominator)</code>, in radians, divided by pi.
 
- To get an inverse tangent measured in degrees, use atan2pi(n, d) * 180.f.
+ To get an inverse tangent measured in degrees, use <code>atan2pi(n, d) * 180.f</code>.
 
- denominator can be 0.
-version: 9
+ See also @native_atan2pi().
 end:
 
-start:
+function: atanh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: atanh
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse hyperbolic tangent
+description:
  Returns the inverse hyperbolic tangent, in radians.
-version: 9
+
+ See also @native_atanh().
 end:
 
-start:
+function: atanpi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: atanpi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Inverse tangent divided by pi
+description:
  Returns the inverse tangent in radians, divided by pi.
 
- To get an inverse tangent measured in degrees, use atanpi(a) * 180.f.
-version: 9
+ To get an inverse tangent measured in degrees, use <code>atanpi(a) * 180.f</code>.
+
+ See also @native_atanpi().
 end:
 
-start:
+function: cbrt
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: cbrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Cube root
+description:
  Returns the cube root.
-version: 9
+
+ See also @native_cbrt().
 end:
 
-start:
+function: ceil
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: ceil
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Smallest integer not less than a value
+description:
  Returns the smallest integer not less than a value.
 
- For example, ceil(1.2f) returns 2.f, and ceil(-1.2f) returns -1.f.
-version: 9
+ For example, <code>ceil(1.2f)</code> returns 2.f, and <code>ceil(-1.2f)</code> returns -1.f.
+
+ See also @floor().
 end:
 
-start:
+function: clamp
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: clamp
 ret: #2#1
-arg: #2#1 value
-arg: #2#1 min_value
-arg: #2#1 max_value above(min_value)
-comment:
- Clamps a value to a specified high and low bound.
+arg: #2#1 value, "Value to be clamped."
+arg: #2#1 min_value, "Lower bound, a scalar or matching vector."
+arg: #2#1 max_value, above(min_value), "High bound, must match the type of low."
+summary: Restrain a value to a range
+description:
+ Clamps a value to a specified high and low bound.  clamp() returns min_value
+ if value &lt; min_value, max_value if value &gt; max_value, otherwise value.
 
- clamp() returns min_value if value < min_value, max_value if value > max_value, otherwise value.
+ There are two variants of clamp: one where the min and max are scalars applied
+ to all entries of the value, the other where the min and max are also vectors.
 
  If min_value is greater than max_value, the results are undefined.
-
- @param value Value to be clamped.  Supports 1, 2, 3, 4 components.
- @param min_value Lower bound, must be scalar or matching vector.
- @param max_value High bound, must match the type of low.
-version: 9
 end:
 
-start:
+function: clamp
+version: 9
+attrib: const
 w: 2, 3, 4
 t: f32
-name: clamp
 ret: #2#1
 arg: #2#1 value
 arg: #2 min_value
-arg: #2 max_value above(min_value)
-comment:
- Clamps a value to a specified high and low bound.
-
- clamp() returns min_value if value < min_value, max_value if value > max_value, otherwise value.
-
- If min_value is greater than max_value, the results are undefined.
-
- @param value Value to be clamped.  Supports 1, 2, 3, 4 components.
- @param min_value Lower bound, must be scalar or matching vector.
- @param max_value High bound, must match the type of low.
-version: 9
+arg: #2 max_value, above(min_value)
 end:
 
-start:
+function: clamp
+version: 19
+attrib: const
 w: 1, 2, 3, 4
 t: u8, u16, u32, u64, i8, i16, i32, i64
-name: clamp
 ret: #2#1
 arg: #2#1 value
 arg: #2#1 min_value
-arg: #2#1 max_value above(min_value)
-comment:
- Clamps a value to a specified high and low bound.
-
- clamp() returns min_value if value < min_value, max_value if value > max_value, otherwise value.
-
- If min_value is greater than max_value, the results are undefined.
-
- @param value Value to be clamped.  Supports 1, 2, 3, 4 components.
- @param min_value Lower bound, must be scalar or matching vector.
- @param max_value High bound, must match the type of low.
-version: 19
+arg: #2#1 max_value, above(min_value)
 end:
 
-start:
+function: clamp
+version: 19
+attrib: const
 w: 2, 3, 4
 t: u8, u16, u32, u64, i8, i16, i32, i64
-name: clamp
 ret: #2#1
 arg: #2#1 value
 arg: #2 min_value
-arg: #2 max_value above(min_value)
-comment:
- Clamps a value to a specified high and low bound.
-
- clamp() returns min_value if value < min_value, max_value if value > max_value, otherwise value.
-
- If min_value is greater than max_value, the results are undefined.
-
- @param value Value to be clamped.  Supports 1, 2, 3, 4 components.
- @param min_value Lower bound, must be scalar or matching vector.
- @param max_value High bound, must match the type of low.
-version: 19
+arg: #2 max_value, above(min_value)
 end:
 
-start:
+function: clz
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: u8, u16, u32, i8, i16, i32
-name: clz
 ret: #2#1
 arg: #2#1 value
-comment:
+summary: Number of leading 0 bits
+description:
  Returns the number of leading 0-bits in a value.
 
- For example, clz((char)0x03) returns 5.
+ For example, <code>clz((char)0x03)</code> returns 6.
+end:
+
+function: convert_#3#1
 version: 9
-end:
-
-start:
+attrib: const
 w: 2, 3, 4
 t: u8, u16, u32, i8, i16, i32, f32
 t: u8, u16, u32, i8, i16, i32, f32
-name: convert_#3#1
-arg: #2#1 v compatible(#3)
 ret: #3#1
-comment:
- Component wise conversion from #2#1 to #3#1.
+arg: #2#1 v, compatible(#3)
+summary: Converts numerical vectors
+description:
+ Component wise conversion from a numerical type to another.
 
- For the convert_* functions, conversions of floating point values to integer will truncate.
+ Conversions of floating point values to integer will truncate.
+
  Conversions of numbers too large to fit the destination type yield undefined results.
  For example, converting a float that contains 1.0e18 to a short is undefined.
+ Use @clamp() to avoid this.
+end:
+
+function: convert_#3#1
+version: 21
+attrib: const
+w: 2, 3, 4
+t: u64, i64, f64
+t: u64, i64, f64
+ret: #3#1
+arg: #2#1 v, compatible(#3)
+end:
+
+function: convert_#3#1
+version: 21
+attrib: const
+w: 2, 3, 4
+t: u64, i64, f64
+t: u8, u16, u32, i8, i16, i32, f32
+ret: #3#1
+arg: #2#1 v, compatible(#3)
+end:
+
+function: convert_#3#1
+version: 21
+attrib: const
+w: 2, 3, 4
+t: u8, u16, u32, i8, i16, i32, f32
+t: u64, i64, f64
+ret: #3#1
+arg: #2#1 v, compatible(#3)
+end:
+
+function: copysign
 version: 9
-end:
-
-start:
-w: 2, 3, 4
-t: u64, i64, f64
-t: u64, i64, f64
-name: convert_#3#1
-arg: #2#1 v compatible(#3)
-ret: #3#1
-comment:
- Component wise conversion from #2#1 to #3#1.
-
- For the convert_* functions, conversions of floating point values to integer will truncate.
- Conversions of numbers too large to fit the destination type yield undefined results.
- For example, converting a float that contains 1.0e18 to a short is undefined.
-version: 21
-end:
-
-start:
-w: 2, 3, 4
-t: u64, i64, f64
-t: u8, u16, u32, i8, i16, i32, f32
-name: convert_#3#1
-arg: #2#1 v compatible(#3)
-ret: #3#1
-comment:
- Component wise conversion from #2#1 to #3#1.
-
- For the convert_* functions, conversions of floating point values to integer will truncate.
- Conversions of numbers too large to fit the destination type yield undefined results.
- For example, converting a float that contains 1.0e18 to a short is undefined.
-version: 21
-end:
-
-start:
-w: 2, 3, 4
-t: u8, u16, u32, i8, i16, i32, f32
-t: u64, i64, f64
-name: convert_#3#1
-arg: #2#1 v compatible(#3)
-ret: #3#1
-comment:
- Component wise conversion from #2#1 to #3#1.
-
- For the convert_* functions, conversions of floating point values to integer will truncate.
- Conversions of numbers too large to fit the destination type yield undefined results.
- For example, converting a float that contains 1.0e18 to a short is undefined.
-version: 21
-end:
-
-start:
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: copysign
 ret: #2#1
 arg: #2#1 magnitude_value
 arg: #2#1 sign_value
-comment:
+summary: Copies the sign of a number to another
+description:
  Copies the sign from sign_value to magnitude_value.
 
  The value returned is either magnitude_value or -magnitude_value.
 
- For example, copysign(4.0f, -2.7f) returns -4.0f and copysign(-4.0f, 2.7f) returns 4.0f.
-version: 9
+ For example, <code>copysign(4.0f, -2.7f)</code> returns -4.0f and <code>copysign(-4.0f, 2.7f)</code> returns 4.0f.
 end:
 
-start:
+function: cos
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: cos
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Cosine
+description:
  Returns the cosine of an angle measured in radians.
-version: 9
+
+ See also @native_cos().
 end:
 
-start:
+function: cosh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: cosh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Hypebolic cosine
+description:
  Returns the hypebolic cosine of v, where v is measured in radians.
-version: 9
+
+ See also @native_cosh().
 end:
 
-start:
+function: cospi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: cospi
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the cosine of (v * pi), where (v * pi) is measured in radians.
+summary: Cosine of a number multiplied by pi
+description:
+ Returns the cosine of <code>(v * pi)</code>, where <code>(v * pi)</code> is measured in radians.
 
- To get the cosine of a value measured in degrees, call cospi(v / 180.f).
-version: 9
+ To get the cosine of a value measured in degrees, call <code>cospi(v / 180.f)</code>.
+
+ See also @native_cospi().
 end:
 
-start:
+function: cross
+version: 9
+attrib: const
 w: 3, 4
 t: f32
-name: cross
 ret: #2#1
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
+summary: Cross product of two vectors
+description:
  Computes the cross product of two vectors.
-version: 9
 test: vector
 end:
 
-start:
+function: degrees
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: degrees
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Converts radians into degrees
+description:
  Converts from radians to degrees.
-version: 9
 end:
 
-start:
+function: distance
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: distance
 ret: #2
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
+summary: Distance between two points
+description:
  Compute the distance between two points.
-version: 9
+
+ See also @fast_distance(), @native_distance().
 test: vector
 end:
 
-start:
+function: dot
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: dot
 ret: #2
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
+summary: Dot product of two vectors
+description:
  Computes the dot product of two vectors.
-version: 9
 test: vector
 end:
 
-start:
+function: erf
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: erf
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Mathematical error function
+description:
  Returns the error function.
-version: 9
 end:
 
-start:
+function: erfc
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: erfc
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Mathematical complementary error function
+description:
  Returns the complementary error function.
-version: 9
 end:
 
-start:
+function: exp
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: exp
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: e raised to a number
+description:
  Returns e raised to v, i.e. e ^ v.
-version: 9
+
+ See also @native_exp().
 end:
 
-start:
+function: exp10
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: exp10
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: 10 raised to a number
+description:
  Returns 10 raised to v, i.e. 10.f ^ v.
-version: 9
+
+ See also @native_exp10().
 end:
 
-start:
+function: exp2
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: exp2
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: 2 raised to a number
+description:
  Returns 2 raised to v, i.e. 2.f ^ v.
-version: 9
+
+ See also @native_exp2().
 end:
 
-start:
+function: expm1
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: expm1
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: e raised to a number minus one
+description:
  Returns e raised to v minus 1, i.e. (e ^ v) - 1.
-version: 9
+
+ See also @native_expm1().
 end:
 
-start:
+function: fabs
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fabs
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Absolute value of a float
+description:
  Returns the absolute value of the float v.
 
- For integers, use abs().
-version: 9
+ For integers, use @abs().
 end:
 
-start:
+function: fast_distance
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fast_distance
 ret: #2
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
+summary: Approximate distance between two points
+description:
  Computes the approximate distance between two points.
 
  The precision is what would be expected from doing the computation using 16 bit floating point values.
-version: 17
+
+ See also @distance(), @native_distance().
 test: vector
 end:
 
-start:
+function: fast_length
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fast_length
 ret: #2
 arg: #2#1 v
-comment:
+summary: Approximate length of a vector
+description:
  Computes the approximate length of a vector.
 
  The precision is what would be expected from doing the computation using 16 bit floating point values.
-version: 17
+
+ See also @length(), @native_length().
 test: vector
 end:
 
-start:
+function: fast_normalize
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fast_normalize
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate normalized vector
+description:
  Approximately normalizes a vector.
 
  For vectors of size 1, returns -1.f for negative values, 0.f for null values, and 1.f for positive values.
 
  The precision is what would be expected from doing the computation using 16 bit floating point values.
-version: 17
+
+ See also @normalize(), @native_normalize().
 test: vector
 end:
 
-start:
+function: fdim
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fdim
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
+summary: Positive difference between two values
+description:
  Returns the positive difference between two values.
 
- If a > b, returns (a - b) otherwise returns 0f.
-version: 9
+ If a &gt; b, returns (a - b) otherwise returns 0f.
 end:
 
-start:
+function: floor
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: floor
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Smallest integer not greater than a value
+description:
  Returns the smallest integer not greater than a value.
-version: 9
+
+ For example, <code>floor(1.2f)</code> returns 1.f, and <code>floor(-1.2f)</code> returns -2.f.
+
+ See also @ceil().
 end:
 
-start:
+function: fma
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fma
 ret: #2#1
 arg: #2#1 multiplicand1
 arg: #2#1 multiplicand2
 arg: #2#1 offset
-comment:
- Multiply and add.  Returns (multiplicand1 * multiplicand2) + offset.
+summary: Multiply and add
+description:
+ Multiply and add.  Returns <code>(multiplicand1 * multiplicand2) + offset</code>.
 
- This function is identical to mad().
-version: 9
+ This function is similar to @mad().  fma() retains full precision of the
+ multiplied result and rounds only after the addition.  @mad() rounds after the
+ multiplication and the addition.  This extra precision is not guaranteed in
+ rs_fp_relaxed mode.
 end:
 
-start:
+function: fmax
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fmax
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum of a and b, i.e. (a < b ? b : a).
+summary: Maximum of two floats
+description:
+ Returns the maximum of a and b, i.e. <code>(a &lt; b ? b : a)</code>.
 
- The max() function returns identical results but can be applied to more data types.
-version: 9
+ The @max() function returns identical results but can be applied to more data types.
 end:
 
-start:
+function: fmax
+version: 9
+attrib: const
 w: 2, 3, 4
 t: f32
-name: fmax
 ret: #2#1
 arg: #2#1 a
 arg: #2 b
-comment:
- Returns the maximum of a and b, i.e. (a < b ? b : a).
-
- Unlike the other variants of fmax() and max(), this function compare each element of a to the scalar b.
-version: 9
 end:
 
-start:
+function: fmin
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fmin
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum of a and b, i.e. (a > b ? b : a).
+summary: Minimum of two floats
+description:
+ Returns the minimum of a and b, i.e. <code>(a &gt; b ? b : a)</code>.
 
- The min() function returns identical results but can be applied to more data types.
-version: 9
+ The @min() function returns identical results but can be applied to more data types.
 end:
 
-start:
+function: fmin
+version: 9
+attrib: const
 w: 2, 3, 4
 t: f32
-name: fmin
 ret: #2#1
 arg: #2#1 a
 arg: #2 b
-comment:
- Returns the minimum of a and b, i.e. (a > b ? b : a)
-
- Unlike the other variants of fmin() and min(), this function compare each element of a to the scalar b.
-version: 9
 end:
 
-start:
+function: fmod
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fmod
 ret: #2#1
 arg: #2#1 numerator
 arg: #2#1 denominator
-comment:
+summary: Modulo
+description:
  Returns the remainder of (numerator / denominator), where the quotient is rounded towards zero.
 
- The function remainder() is similar but rounds toward the closest interger.
- For example, fmod(-3.8f, 2.f) returns -1.8f (-3.8f - -1.f * 2.f)
- while remainder(-3.8f, 2.f) returns 0.2f (-3.8f - -2.f * 2.f).
-version: 9
+ The function @remainder() is similar but rounds toward the closest interger.
+ For example, <code>fmod(-3.8f, 2.f)</code> returns -1.8f (-3.8f - -1.f * 2.f)
+ while <code>@remainder(-3.8f, 2.f)</code> returns 0.2f (-3.8f - -2.f * 2.f).
 end:
 
-start:
+function: fract
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: fract
 ret: #2#1
-arg: #2#1 v
-arg: #2#1 *floor
-comment:
- Returns the positive fractional part of v, i.e. v - floor(v).
+arg: #2#1 v, "Input value."
+arg: #2#1* floor, "If floor is not null, *floor will be set to the floor of v."
+summary: Positive fractional part
+description:
+ Returns the positive fractional part of v, i.e. <code>v - floor(v)</code>.
 
- For example, fract(1.3f, &val) returns 0.3f and sets val to 1.f.
- fract(-1.3f, &val) returns 0.7f and sets val to -2.f.
-
- @param v Input value.
- @param floor  If floor is not null, each element of floor will be set to the floor of the corresponding element of v.
-version: 9
+ For example, <code>fract(1.3f, &val)</code> returns 0.3f and sets val to 1.f.
+ <code>fract(-1.3f, &val)</code> returns 0.7f and sets val to -2.f.
 end:
 
-start:
+function: fract
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: fract
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the positive fractional part of v, i.e. v - floor(v).
-
- For example, fract(1.3f, &val) returns 0.3f and sets val to 1.f.
- fract(-1.3f, &val) returns 0.7f and sets val to -2.f.
 inline:
-    #2#1 unused;
-    return fract(v, &unused);
-version: 9
+ #2#1 unused;
+ return fract(v, &unused);
 end:
 
-start:
+function: frexp
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: frexp
 ret: #2#1
-arg: #2#1 v
-arg: int#1 *exponent
-comment:
- Returns the binary mantissa and exponent of v, e.g. v == mantissa * 2 ^ exponent.
+arg: #2#1 v, "Input value."
+arg: int#1* exponent, "If exponent is not null, *exponent will be set to the exponent of v."
+summary: Binary mantissa and exponent
+description:
+ Returns the binary mantissa and exponent of v, i.e. <code>v == mantissa * 2 ^ exponent</code>.
 
  The mantissa is always between 0.5 (inclusive) and 1.0 (exclusive).
- See ldexp() for the reverse operation.
 
- @param v Supports float, float2, float3, float4.
- @param exponent  If exponent is not null, each element of exponent will be set to the exponent of the corresponding element of v.
-version: 9
+ See @ldexp() for the reverse operation.  See also @logb() and @ilogb().
 end:
 
-start:
+function: half_recip
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: half_recip
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Reciprocal computed to 16 bit precision
+description:
  Returns the approximate reciprocal of a value.
 
  The precision is that of a 16 bit floating point value.
-version: 17
+
+ See also @native_recip().
 end:
 
-start:
+function: half_rsqrt
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: half_rsqrt
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the approximate value of (1.f / sqrt(value)).
+summary: Reciprocal of a square root computed to 16 bit precision
+description:
+ Returns the approximate value of <code>(1.f / sqrt(value))</code>.
 
  The precision is that of a 16 bit floating point value.
-version: 17
+
+ See also @rsqrt(), @native_rsqrt().
 end:
 
-start:
+function: half_sqrt
+version: 17
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: half_sqrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Square root computed to 16 bit precision
+description:
  Returns the approximate square root of a value.
 
  The precision is that of a 16 bit floating point value.
-version: 17
+
+ See also @sqrt(), @native_sqrt().
 end:
 
-start:
+function: hypot
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: hypot
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the hypotenuse, i.e. sqrt(a * a + b * b).
-version: 9
+summary: Hypotenuse
+description:
+ Returns the hypotenuse, i.e. <code>sqrt(a * a + b * b)</code>.
+
+ See also @native_hypot().
 end:
 
-start:
+function: ilogb
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: ilogb
 ret: int#1
 arg: float#1 v
-comment:
- Returns the base two exponent of a value, where the mantissa is between 1.f (inclusive) and 2.f (exclusive).
+summary: Base two exponent
+description:
+ Returns the base two exponent of a value, where the mantissa is between
+ 1.f (inclusive) and 2.f (exclusive).
 
- For example, ilogb(8.5f) returns 3.  Because of the difference in mantissa, this number is one less than
- is returned by frexp().
+ For example, <code>ilogb(8.5f)</code> returns 3.
 
- logb() is similar but returns a float.
-version: 9
+ Because of the difference in mantissa, this number is one less than
+ is returned by @frexp().
+
+ @logb() is similar but returns a float.
 test: custom
 end:
 
-start:
-w: 1, 2, 3, 4
-name: ldexp
-ret: float#1
-arg: float#1 mantissa
-arg: int#1 exponent
-comment:
- Returns the floating point created from the mantissa and exponent, i.e. (mantissa * 2 ^ exponent).
-
- See frexp() for the reverse operation.
-
- @param mantissa Supports float, float2, float3, and float4.
- @param exponent Supports single component or matching vector.
+function: ldexp
 version: 9
+attrib: const
+w: 1, 2, 3, 4
+ret: float#1
+arg: float#1 mantissa, "The mantissa"
+arg: int#1 exponent, "The exponent, a single component or matching vector."
+summary: Creates a floating point from mantissa and exponent
+description:
+ Returns the floating point created from the mantissa and exponent,
+ i.e. (mantissa * 2 ^ exponent).
+
+ See @frexp() for the reverse operation.
 end:
 
-start:
+function: ldexp
+version: 9
+attrib: const
 w: 2, 3, 4
-name: ldexp
 ret: float#1
 arg: float#1 mantissa
 arg: int exponent
-comment:
- Returns the floating point created from the mantissa and exponent, i.e. (mantissa * 2 ^ exponent).
- See frexp() for the reverse operation.
-
- @param mantissa Supports float, float2, float3, and float4.
- @param exponent Supports single component or matching vector.
-version: 9
 end:
 
-start:
+function: length
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: length
 ret: #2
 arg: #2#1 v
-comment:
+summary: Length of a vector
+description:
  Computes the length of a vector.
-version: 9
+
+ See also @fast_length(), @native_length().
 test: vector
 end:
 
-start:
+function: lgamma
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: lgamma
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the natural logarithm of the absolute value of the gamma function, i.e. log(fabs(gamma(v))).
-version: 9
+summary: Natural logarithm of the gamma function
+description:
+ Returns the natural logarithm of the absolute value of the gamma function,
+ i.e. <code>@log(@fabs(@tgamma(v)))</code>.
+
+ See also @tgamma().
 end:
 
-start:
+function: lgamma
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: lgamma
 ret: #2#1
 arg: #2#1 v
-arg: int#1 *sign_of_gamma
-comment:
- Returns the natural logarithm of the absolute value of the gamma function, i.e. log(fabs(gamma(v))).
-
- Can also return the sign of the gamma function.
-
- @param v Input value.
- @param sign_of_gamma  If sign is not null, each element of sign will be set to -1.f if the gamma of the corresponding element of v is negative, otherwise to 1.f.
-
-version: 9
-#TODO Temporary until bionic & associated drivers are fixed
+arg: int#1* sign_of_gamma, "If sign_of_gamma is not null, *sign_of_gamma will be set to -1.f if the gamma of v is negative, otherwise to 1.f."
 test: custom
+#TODO Temporary until bionic & associated drivers are fixed
 end:
 
-start:
+function: log
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: log
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Natural logarithm
+description:
  Returns the natural logarithm.
-version: 9
+
+ See also @native_log().
 end:
 
-start:
+function: log10
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: log10
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Base 10 logarithm
+description:
  Returns the base 10 logarithm.
-version: 9
+
+ See also @native_log10().
 end:
 
-start:
+function: log1p
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: log1p
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the natural logarithm of (v + 1.f).
-version: 9
+summary: Natural logarithm of a value plus 1
+description:
+ Returns the natural logarithm of <code>(v + 1.f)</code>.
+
+ See also @native_log1p().
 end:
 
-start:
+function: log2
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: log2
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Base 2 logarithm
+description:
  Returns the base 2 logarithm.
-version: 9
+
+ See also @native_log2().
 end:
 
-start:
+function: logb
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: logb
 ret: #2#1
 arg: #2#1 v
-comment:
- Returns the base two exponent of a value, where the mantissa is between 1.f (inclusive) and 2.f (exclusive).
+summary: Base two exponent
+description:
+ Returns the base two exponent of a value, where the mantissa is between
+ 1.f (inclusive) and 2.f (exclusive).
 
- For example, logb(8.5f) returns 3.f.  Because of the difference in mantissa, this number is one less than
+ For example, <code>logb(8.5f)</code> returns 3.f.
+
+ Because of the difference in mantissa, this number is one less than
  is returned by frexp().
 
- ilogb() is similar but returns an integer.
-version: 9
+ @ilogb() is similar but returns an integer.
 end:
 
-start:
+function: mad
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: mad
 ret: #2#1
 arg: #2#1 multiplicand1
 arg: #2#1 multiplicand2
 arg: #2#1 offset
-comment:
- Multiply and add.  Returns (multiplicand1 * multiplicand2) + offset.
+summary: Multiply and add
+description:
+ Multiply and add.  Returns <code>(multiplicand1 * multiplicand2) + offset</code>.
 
- This function is identical to fma().
-version: 9
+ This function is similar to @fma().  @fma() retains full precision of the
+ multiplied result and rounds only after the addition.  mad() rounds after the
+ multiplication and the addition.  In rs_fp_relaxed mode, mad() may not do the
+ rounding after multiplicaiton.
 end:
 
-start:
+function: max
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: max
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
+summary: Maximum
+description:
  Returns the maximum value of two arguments.
-version: 9
 end:
 
-start:
+function: max
+version: 9 20
+attrib: const
 w: 1
-t: i8 i16 i32 u8 u16 u32
-name: max
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum value of two arguments.
 inline:
  return (a > b ? a : b);
-version: 9 20
 end:
 
-start:
+function: max
+version: 9 20
+attrib: const
 w: 2
-t: i8 i16 i32 u8 u16 u32
-name: max
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x > b.x ? a.x : b.x);
  tmp.y = (a.y > b.y ? a.y : b.y);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: max
+version: 9 20
+attrib: const
 w: 3
-t: i8 i16 i32 u8 u16 u32
-name: max
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x > b.x ? a.x : b.x);
  tmp.y = (a.y > b.y ? a.y : b.y);
  tmp.z = (a.z > b.z ? a.z : b.z);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: max
+version: 9 20
+attrib: const
 w: 4
-t: i8 i16 i32 u8 u16 u32
-name: max
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x > b.x ? a.x : b.x);
@@ -1031,91 +1110,82 @@
  tmp.z = (a.z > b.z ? a.z : b.z);
  tmp.w = (a.w > b.w ? a.w : b.w);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: max
+version: 21
+attrib: const
 w: 1, 2, 3, 4
-t: i8 i16 i32 i64 u8 u16 u32 u64
-name: max
+t: i8, i16, i32, i64, u8, u16, u32, u64
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the maximum value of two arguments.
-version: 21
 end:
 
-start:
+function: min
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: min
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
+summary: Minimum
+description:
  Returns the minimum value of two arguments.
-version: 9
 end:
 
-start:
+function: min
+version: 9 20
+attrib: const
 w: 1
-t: i8 i16 i32 u8 u16 u32
-name: min
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum value of two arguments.
 inline:
  return (a < b ? a : b);
-version: 9 20
 end:
 
-start:
+function: min
+version: 9 20
+attrib: const
 w: 2
-t: i8 i16 i32 u8 u16 u32
-name: min
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x < b.x ? a.x : b.x);
  tmp.y = (a.y < b.y ? a.y : b.y);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: min
+version: 9 20
+attrib: const
 w: 3
-t: i8 i16 i32 u8 u16 u32
-name: min
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x < b.x ? a.x : b.x);
  tmp.y = (a.y < b.y ? a.y : b.y);
  tmp.z = (a.z < b.z ? a.z : b.z);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: min
+version: 9 20
+attrib: const
 w: 4
-t: i8 i16 i32 u8 u16 u32
-name: min
+t: i8, i16, i32, u8, u16, u32
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum value of two arguments.
 inline:
  #2#1 tmp;
  tmp.x = (a.x < b.x ? a.x : b.x);
@@ -1123,952 +1193,1092 @@
  tmp.z = (a.z < b.z ? a.z : b.z);
  tmp.w = (a.w < b.w ? a.w : b.w);
  return tmp;
-version: 9 20
 end:
 
-start:
+function: min
+version: 21
+attrib: const
 w: 1, 2, 3, 4
-t: i8 i16 i32 i64 u8 u16 u32 u64
-name: min
+t: i8, i16, i32, i64, u8, u16, u32, u64
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
- Returns the minimum value of two arguments.
-version: 21
 end:
 
-start:
+function: mix
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: mix
 ret: #2#1
 arg: #2#1 start
 arg: #2#1 stop
 arg: #2#1 fraction
-comment:
+summary: Mixes two values
+description:
  Returns start + ((stop - start) * fraction).
 
- This can be useful for mixing two values.  For example, to create a new color that is 40% color1 and 60% color2, use mix(color1, color2, 0.6f).
-version: 9
+ This can be useful for mixing two values.  For example, to create a new color that is 40% color1 and 60% color2, use <code>mix(color1, color2, 0.6f)</code>.
 end:
 
-start:
+function: mix
+version: 9
+attrib: const
 w: 2, 3, 4
 t: f32
-name: mix
 ret: #2#1
 arg: #2#1 start
 arg: #2#1 stop
 arg: #2 fraction
-comment:
- Returns start + ((stop - start) * fraction).
-
- This can be useful for mixing two values.  For example, to create a new color that is 40% color1 and 60% color2, use mix(color1, color2, 0.6f).
-version: 9
 end:
 
-start:
+function: modf
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: modf
-ret: #2#1
-arg: #2#1 v
-arg: #2#1 *integral_part
-comment:
+ret: #2#1, "The floating point portion of the value."
+arg: #2#1 v, "Source value"
+arg: #2#1* integral_part, "*integral_part will be set to the integral portion of the number."
+summary: Integral and fractional components
+description:
  Returns the integral and fractional components of a number.
 
  Both components will have the same sign as x.  For example, for an input of -3.72f, iret will be set to -3.f and .72f will be returned.
-
- @param v Source value
- @param integral_part integral_part[0] will be set to the integral portion of the number.
- @return The floating point portion of the value.
-version: 9
 end:
 
-start:
+function: nan
+version: 9
+attrib: const
 w: 1
 t: f32
-name: nan
 ret: #2#1
-arg: uint#1 v
-comment:
- Returns a NaN value (Not a Number).
-
- @param v Not used.
+arg: uint#1 v, "Not used."
 #TODO We're not using the argument.  Once we do, add this documentation line:
 # The argument is embedded into the return value and can be used to distinguish various NaNs.
-version: 9
+summary: Not a Number
+description:
+ Returns a NaN value (Not a Number).
 end:
 
-start:
+function: native_acos
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_acos
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse cosine
+description:
  Returns the approximate inverse cosine, in radians.
-version: 21
+
+ This function yields undefined results from input values less than -1 or greater
+ than 1.
+
+ See also @acos().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_acosh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_acosh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate inverse hyperbolic cosine
+description:
  Returns the approximate inverse hyperbolic cosine, in radians.
-version: 21
+
+ See also @acosh().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_acospi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_acospi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse cosine divided by pi
+description:
  Returns the approximate inverse cosine in radians, divided by pi.
 
- To get an inverse cosine measured in degrees, use acospi(a) * 180.f.
-version: 21
+ To get an inverse cosine measured in degrees, use <code>acospi(a) * 180.f</code>.
+
+ This function yields undefined results from input values less than -1 or greater
+ than 1.
+
+ See also @acospi().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_asin
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_asin
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse sine
+description:
  Returns the approximate inverse sine, in radians.
-version: 21
+
+ This function yields undefined results from input values less than -1 or greater
+ than 1.
+
+ See also @asin().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_asinh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_asinh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate inverse hyperbolic sine
+description:
  Returns the approximate inverse hyperbolic sine, in radians.
-version: 21
+
+ See also @asinh().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_asinpi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_asinpi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse sine divided by pi
+description:
  Returns the approximate inverse sine in radians, divided by pi.
 
- To get an inverse sine measured in degrees, use asinpi(a) * 180.f.
-version: 21
+ To get an inverse sine measured in degrees, use <code>asinpi(a) * 180.f</code>.
+
+ This function yields undefined results from input values less than -1 or greater
+ than 1.
+
+ See also @asinpi().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_atan
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_atan
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse tangent
+description:
  Returns the approximate inverse tangent, in radians.
-version: 21
+
+ See also @atan().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_atan2
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_atan2
 ret: #2#1
-arg: #2#1 numerator
-arg: #2#1 denominator
-comment:
- Returns the approximate inverse tangent of numerator / denominator, in radians.
+arg: #2#1 numerator, "The numerator"
+arg: #2#1 denominator, "The denominator.  Can be 0."
+summary: Approximate inverse tangent of a ratio
+description:
+ Returns the approximate inverse tangent of <code>(numerator / denominator)</code>, in radians.
 
- denominator can be 0.
-version: 21
+ See also @atan2().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_atan2pi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_atan2pi
 ret: #2#1
-arg: #2#1 numerator
-arg: #2#1 denominator
-comment:
- Returns the approximate inverse tangent of numerator / denominator, in radians, divided by pi.
+arg: #2#1 numerator, "The numerator"
+arg: #2#1 denominator, "The denominator.  Can be 0."
+summary: Approximate inverse tangent of a ratio, divided by pi
+description:
+ Returns the approximate inverse tangent of <code>(numerator / denominator)</code>, in radians, divided by pi.
 
- To get an inverse tangent measured in degrees, use atan2pi(n, d) * 180.f.
+ To get an inverse tangent measured in degrees, use <code>atan2pi(n, d) * 180.f</code>.
 
- denominator can be 0.
-version: 21
+ See also @atan2pi().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_atanh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_atanh
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse hyperbolic tangent
+description:
  Returns the approximate inverse hyperbolic tangent, in radians.
-version: 21
+
+ See also @atanh().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_atanpi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_atanpi
 ret: #2#1
-arg: #2#1 v range(-1,1)
-comment:
+arg: #2#1 v, range(-1,1)
+summary: Approximate inverse tangent divided by pi
+description:
  Returns the approximate inverse tangent in radians, divided by pi.
 
- To get an inverse tangent measured in degrees, use atanpi(a) * 180.f.
-version: 21
+ To get an inverse tangent measured in degrees, use <code>atanpi(a) * 180.f</code>.
+
+ See also @atanpi().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_cbrt
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_cbrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate cube root
+description:
  Returns the approximate cubic root.
-version: 21
+
+ See also @cbrt().
 end:
 
-start:
+function: native_cos
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_cos
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate cosine
+description:
  Returns the approximate cosine of an angle measured in radians.
-version: 21
+
+ See also @cos().
 end:
 
-start:
+function: native_cosh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_cosh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate hypebolic cosine
+description:
  Returns the approximate hypebolic cosine.
-version: 21
+
+ See also @cosh().
 end:
 
-start:
+function: native_cospi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_cospi
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate cosine of a number multiplied by pi
+description:
  Returns the approximate cosine of (v * pi), where (v * pi) is measured in radians.
 
- To get the cosine of a value measured in degrees, call cospi(v / 180.f).
-version: 21
+ To get the cosine of a value measured in degrees, call <code>cospi(v / 180.f)</code>.
+
+ See also @cospi().
 end:
 
-start:
+function: native_distance
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_distance
 ret: #2
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
+summary: Approximate distance between two points
+description:
  Computes the approximate distance between two points.
-version: 21
+
+ See also @distance(), @fast_distance().
 test: vector
 end:
 
-start:
+function: native_divide
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_divide
 ret: #2#1
 arg: #2#1 left_vector
 arg: #2#1 right_vector
-comment:
- Computes the approximate division result of two values.
-version: 21
+summary: Approximate division
+description:
+ Computes the approximate division of two values.
 end:
 
-start:
+function: native_exp
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_exp
 ret: #2#1
-arg: #2#1 v range(-86,86)
-comment:
+arg: #2#1 v, range(-86,86)
+summary: Approximate e raised to a number
+description:
  Fast approximate exp.
 
  It is valid for inputs from -86.f to 86.f.  The precision is no worse than what would be expected from using 16 bit floating point values.
-version: 18
+
+ See also @exp().
 test: limited
 end:
 
-start:
+function: native_exp10
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_exp10
 ret: #2#1
-arg: #2#1 v range(-37,37)
-comment:
+arg: #2#1 v, range(-37,37)
+summary: Approximate 10 raised to a number
+description:
  Fast approximate exp10.
 
  It is valid for inputs from -37.f to 37.f.  The precision is no worse than what would be expected from using 16 bit floating point values.
-version: 18
+
+ See also @exp10().
 test: limited
 end:
 
-start:
+function: native_exp2
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_exp2
 ret: #2#1
-arg: #2#1 v range(-125,125)
-comment:
+arg: #2#1 v, range(-125,125)
+summary: Approximate 2 raised to a number
+description:
  Fast approximate exp2.
 
  It is valid for inputs from -125.f to 125.f.  The precision is no worse than what would be expected from using 16 bit floating point values.
-version: 18
+
+ See also @exp2().
 test: limited
 end:
 
-start:
+function: native_expm1
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_expm1
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate e raised to a number minus one
+description:
  Returns the approximate (e ^ v) - 1.
-version: 21
+
+ See also @expm1().
 end:
 
-start:
+function: native_hypot
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_hypot
 ret: #2#1
 arg: #2#1 a
 arg: #2#1 b
-comment:
+summary: Approximate hypotenuse
+description:
  Returns the approximate native_sqrt(a * a + b * b)
-version: 21
+
+ See also @hypot().
 end:
 
-start:
+function: native_length
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_length
 ret: #2
 arg: #2#1 v
-comment:
+summary: Approximate length of a vector
+description:
  Compute the approximate length of a vector.
-version: 21
+
+ See also @length(), @fast_length().
 test: vector
 end:
 
-start:
+function: native_log
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_log
 ret: #2#1
-arg: #2#1 v range(10e-10,10e10)
-comment:
+arg: #2#1 v, range(10e-10,10e10)
+summary: Approximate natural logarithm
+description:
  Fast approximate log.
 
  It is not accurate for values very close to zero.
-version: 18
+
+ See also @log().
 test: limited
 end:
 
-start:
+function: native_log10
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_log10
 ret: #2#1
-arg: #2#1 v range(10e-10,10e10)
-comment:
+arg: #2#1 v, range(10e-10,10e10)
+summary: Approximate base 10 logarithm
+description:
  Fast approximate log10.
 
  It is not accurate for values very close to zero.
-version: 18
+
+ See also @log10().
 test: limited
 end:
 
-start:
+function: native_log1p
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_log1p
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate natural logarithm of a value plus 1
+description:
  Returns the approximate natural logarithm of (v + 1.0f)
-version: 21
+
+ See also @log1p().
 end:
 
-start:
+function: native_log2
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_log2
 ret: #2#1
-arg: #2#1 v range(10e-10,10e10)
-comment:
+arg: #2#1 v, range(10e-10,10e10)
+summary: Approximate base 2 logarithm
+description:
  Fast approximate log2.
 
  It is not accurate for values very close to zero.
-version: 18
+
+ See also @log2().
 test: limited
 end:
 
-start:
+function: native_normalize
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_normalize
 ret: #2#1
 arg: #2#1 v
-comment:
+summary:  Approximately normalize a vector
+description:
  Approximately normalizes a vector.
-version: 21
+
+ See also @normalize(), @fast_normalize().
 test: vector
 end:
 
-start:
+function: native_powr
+version: 18
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_powr
 ret: #2#1
-arg: #2#1 base range(0,256)
-arg: #2#1 exponent range(-15,15)
-comment:
+arg: #2#1 base, range(0,256), "Must be between 0.f and 256.f.  The function is not accurate for values very close to zero."
+arg: #2#1 exponent, range(-15,15), "Must be between -15.f and 15.f."
+summary: Approximate positive base raised to an exponent
+description:
  Fast approximate (base ^ exponent).
 
- @param base Must be between 0.f and 256.f.  The function is not accurate for values very close to zero.
- @param exponent Must be between -15.f and 15.f.
-version: 18
+ See also @powr().
 test: limited
 end:
 
-start:
+function: native_recip
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_recip
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate reciprocal
+description:
  Returns the approximate approximate reciprocal of a value.
-version: 21
+
+ See also @half_recip().
 end:
 
-start:
+function: native_rootn
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_rootn
 ret: #2#1
 arg: #2#1 v
 arg: int#1 n
-comment:
+summary: Approximate nth root
+description:
  Compute the approximate Nth root of a value.
-version: 21
+
+ See also @rootn().
 end:
 
-start:
+function: native_rsqrt
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_rsqrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate reciprocal of a square root
+description:
  Returns approximate (1 / sqrt(v)).
-version: 21
+
+ See also @rsqrt(), @half_rsqrt().
 end:
 
-start:
+function: native_sin
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_sin
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate sine
+description:
  Returns the approximate sine of an angle measured in radians.
-version: 21
+
+ See also @sin().
 end:
 
-start:
+function: native_sincos
+version: 21
 w: 1, 2, 3, 4
 t: f32
-name: native_sincos
-ret: #2#1
-arg: #2#1 v
-arg: #2#1 *cos
-comment:
+ret: #2#1, "sine"
+arg: #2#1 v, "The incoming value in radians."
+arg: #2#1* cos, "*cos will be set to the cosine value."
+summary: Approximate sine and cosine
+description:
  Returns the approximate sine and cosine of a value.
 
- @return sine
- @param v The incoming value in radians
- @param *cos cos[0] will be set to the cosine value.
-version: 21
+ See also @sincos().
 # TODO Temporary
 test: limited(0.0005)
 end:
 
-start:
+function: native_sinh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_sinh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate hyperbolic sine
+description:
  Returns the approximate hyperbolic sine of a value specified in radians.
-version: 21
+
+ See also @sinh().
 end:
 
-start:
+function: native_sinpi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_sinpi
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate sine of a number multiplied by pi
+description:
  Returns the approximate sine of (v * pi), where (v * pi) is measured in radians.
 
- To get the sine of a value measured in degrees, call sinpi(v / 180.f).
-version: 21
+ To get the sine of a value measured in degrees, call <code>sinpi(v / 180.f)</code>.
+
+ See also @sinpi().
 end:
 
-start:
+function: native_sqrt
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_sqrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate square root
+description:
  Returns the approximate sqrt(v).
-version: 21
+
+ See also @sqrt(), @half_sqrt().
 end:
 
-start:
+function: native_tan
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_tan
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate tangent
+description:
  Returns the approximate tangent of an angle measured in radians.
-version: 21
 end:
 
-start:
+function: native_tanh
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_tanh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate hyperbolic tangent
+description:
  Returns the approximate hyperbolic tangent of a value.
-version: 21
+
+ See also @tanh().
 end:
 
-start:
+function: native_tanpi
+version: 21
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: native_tanpi
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Approximate tangent of a number multiplied by pi
+description:
  Returns the approximate tangent of (v * pi), where (v * pi) is measured in radians.
 
- To get the tangent of a value measured in degrees, call tanpi(v / 180.f).
-version: 21
+ To get the tangent of a value measured in degrees, call <code>tanpi(v / 180.f)</code>.
+
+ See also @tanpi().
 end:
 
-start:
+function: nextafter
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: nextafter
 ret: #2#1
 arg: #2#1 v
 arg: #2#1 target
-comment:
- Returns the next floating point number from v towards target.
-version: 9
+summary: Next floating point number
+description:
+ Returns the next representable floating point number from v towards target.
+
+ In rs_fp_relaxed mode, a denormalized input value may not yield the next
+ denormalized  value, as support of denormalized values is optional in
+ relaxed mode.
 end:
 
-start:
+function: normalize
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: normalize
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Normalize a vector
+description:
  Normalize a vector.
 
  For vectors of size 1, returns -1.f for negative values, 0.f for null values, and 1.f for positive values.
-version: 9
+
+ See also @fast_normalize(), @native_normalize().
 test: vector
 end:
 
-start:
+function: pow
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: pow
 ret: #2#1
 arg: #2#1 base
 arg: #2#1 exponent
-comment:
+summary: Base raised to an exponent
+description:
  Returns base raised to the power exponent, i.e. base ^ exponent.
 
- pown() and powr() are similar.  pown() takes an integer exponent. powr() assumes the base to be non-negative.
-version: 9
+ @pown() and @powr() are similar.  @pown() takes an integer exponent. @powr() assumes the base to be non-negative.
 end:
 
-start:
+function: pown
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: pown
 ret: #2#1
 arg: #2#1 base
 arg: int#1 exponent
-comment:
+summary: Base raised to an integer exponent
+description:
  Returns base raised to the power exponent, i.e. base ^ exponent.
 
- pow() and powr() are similar.  The both take a float exponent. powr() also assumes the base to be non-negative.
-version: 9
+ @pow() and @powr() are similar.  The both take a float exponent. @powr() also assumes the base to be non-negative.
 end:
 
-start:
+function: powr
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: powr
 ret: #2#1
-arg: #2#1 base range(0,3000)
+arg: #2#1 base, range(0,3000)
 arg: #2#1 exponent
-comment:
- Returns base raised to the power exponent, i.e. base ^ exponent.  base must be >= 0.
+summary: Positive base raised to an exponent
+description:
+ Returns base raised to the power exponent, i.e. base ^ exponent.  base must be &gt;= 0.
 
- pow() and pown() are similar.  They both make no assumptions about the base.  pow() takes a float exponent while pown() take an integer.
-version: 9
+ @pow() and @pown() are similar.  They both make no assumptions about the base.  @pow() takes a float exponent while @pown() take an integer.
+
+ See also @native_powr().
 end:
 
-start:
+function: radians
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: radians
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Converts degrees into radians
+description:
  Converts from degrees to radians.
-version: 9
 end:
 
-start:
+function: remainder
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: remainder
 ret: #2#1
 arg: #2#1 numerator
 arg: #2#1 denominator
-comment:
+summary: Remainder of a division
+description:
  Returns the remainder of (numerator / denominator), where the quotient is rounded towards the nearest integer.
 
- The function fmod() is similar but rounds toward the closest interger.
- For example, fmod(-3.8f, 2.f) returns -1.8f (-3.8f - -1.f * 2.f)
- while remainder(-3.8f, 2.f) returns 0.2f (-3.8f - -2.f * 2.f).
-version: 9
+ The function @fmod() is similar but rounds toward the closest interger.
+ For example, <code>@fmod(-3.8f, 2.f)</code> returns -1.8f (-3.8f - -1.f * 2.f)
+ while <code>remainder(-3.8f, 2.f)</code> returns 0.2f (-3.8f - -2.f * 2.f).
 end:
 
-start:
+function: remquo
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: remquo
-ret: #2#1
-arg: #2#1 numerator
-arg: #2#1 denominator
-arg: int#1 *quotient
-comment:
+ret: #2#1, "The remainder, precise only for the low three bits."
+arg: #2#1 numerator, "The numerator."
+arg: #2#1 denominator, "The denominator."
+arg: int#1* quotient, "*quotient will be set to the integer quotient."
+summary: Remainder and quotient of a division
+description:
  Returns the quotient and the remainder of (numerator / denominator).
 
  Only the sign and lowest three bits of the quotient are guaranteed to be accurate.
 
- This function is useful for implementing periodic functions.  The low three bits of the quotient gives the quadrant and the remainder the distance within the quadrant.  For example, an implementation of sin(x) could call remquo(x, PI / 2.f, &quadrant) to reduce very large value of x to something within a limited range.
+ This function is useful for implementing periodic functions.  The low three bits of the quotient gives the quadrant and the remainder the distance within the quadrant.  For example, an implementation of @sin(x) could call <code>remquo(x, PI / 2.f, &quadrant)</code> to reduce very large value of x to something within a limited range.
 
- Example: remquo(-23.5f, 8.f, &quot) sets the lowest three bits of quot to 3 and the sign negative.  It returns 0.5f.
-
- @param numerator The numerator.
- @param denominator The denominator.
- @param *quotient quotient[0] will be set to the integer quotient.
- @return The remainder, precise only for the low three bits.
-version: 9
+ Example: <code>remquo(-23.5f, 8.f, &quot)</code> sets the lowest three bits of quot to 3 and the sign negative.  It returns 0.5f.
 test: custom
 end:
 
-start:
+function: rint
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: rint
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Round to even
+description:
  Rounds to the nearest integral value.
 
- rint() rounds half values to even.  For example, rint(0.5f) returns 0.f and rint(1.5f) returns 2.f.  Similarly, rint(-0.5f) returns -0.f and rint(-1.5f) returns -2.f.
+ rint() rounds half values to even.  For example, <code>rint(0.5f)</code> returns 0.f and <code>rint(1.5f)</code> returns 2.f.  Similarly, <code>rint(-0.5f)</code> returns -0.f and <code>rint(-1.5f)</code> returns -2.f.
 
- round() is similar but rounds away from zero.  trunc() truncates the decimal fraction.
-version: 9
+ @round() is similar but rounds away from zero.  @trunc() truncates the decimal fraction.
 end:
 
-start:
+function: rootn
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: rootn
 ret: #2#1
 arg: #2#1 v
 arg: int#1 n
-comment:
+summary: Nth root
+description:
  Compute the Nth root of a value.
-version: 9
+
+ See also @native_rootn().
 end:
 
-start:
+function: round
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: round
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Round away from zero
+description:
  Round to the nearest integral value.
 
- round() rounds half values away from zero.  For example, round(0.5f) returns 1.f and round(1.5f) returns 2.f.  Similarly, round(-0.5f) returns -1.f and round(-1.5f) returns -2.f.
+ round() rounds half values away from zero.  For example, <code>round(0.5f)</code> returns 1.f and <code>round(1.5f)</code> returns 2.f.  Similarly, <code>round(-0.5f)</code> returns -1.f and <code>round(-1.5f)</code> returns -2.f.
 
- rint() is similar but rounds half values toward even.  trunc() truncates the decimal fraction.
-version: 9
+ @rint() is similar but rounds half values toward even.  @trunc() truncates the decimal fraction.
 end:
 
-start:
+function: rsqrt
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: rsqrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Reciprocal of a square root
+description:
  Returns (1 / sqrt(v)).
-version: 9
+
+ See also @half_rsqrt(), @native_rsqrt().
 end:
 
-start:
+function: sign
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: sign
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Sign of a value
+description:
  Returns the sign of a value.
 
- if (v < 0) return -1.f;
- else if (v > 0) return 1.f;
+ if (v &lt; 0) return -1.f;
+ else if (v &gt; 0) return 1.f;
  else return 0.f;
-version: 9
 end:
 
-start:
+function: sin
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: sin
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Sine
+description:
  Returns the sine of an angle measured in radians.
-version: 9
+
+ See also @native_sin().
 end:
 
-start:
+function: sincos
+version: 9
 w: 1, 2, 3, 4
 t: f32
-name: sincos
-ret: #2#1
-arg: #2#1 v
-arg: #2#1 *cos
-comment:
+ret: #2#1, "sine of v"
+arg: #2#1 v, "The incoming value in radians"
+arg: #2#1* cos, "*cos will be set to the cosine value."
+summary: Sine and cosine
+description:
  Returns the sine and cosine of a value.
 
- @return sine of v
- @param v The incoming value in radians
- @param *cos cosptr[0] will be set to the cosine value.
-version: 9
+ See also @native_sincos().
 end:
 
-start:
+function: sinh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: sinh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Hyperbolic sine
+description:
  Returns the hyperbolic sine of v, where v is measured in radians.
-version: 9
+
+ See also @native_sinh().
 end:
 
-start:
+function: sinpi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: sinpi
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Sine of a number multiplied by pi
+description:
  Returns the sine of (v * pi), where (v * pi) is measured in radians.
 
- To get the sine of a value measured in degrees, call sinpi(v / 180.f).
-version: 9
+ To get the sine of a value measured in degrees, call <code>sinpi(v / 180.f)</code>.
+
+ See also @native_sinpi().
 end:
 
-start:
+function: sqrt
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: sqrt
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Square root
+description:
  Returns the square root of a value.
-version: 9
+
+ See also @half_sqrt(), @native_sqrt().
 end:
 
-start:
+function: step
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: step
 ret: #2#1
 arg: #2#1 edge
 arg: #2#1 v
-comment:
- Returns 0.f if v < edge, 1.f otherwise.
+summary: 0 if less than a value, 0 otherwise
+description:
+ Returns 0.f if v &lt; edge, 1.f otherwise.
 
- This can be useful to create conditional computations without using loops and branching instructions.  For example, instead of computing (a[i] < b[i]) ? 0.f : atan2(a[i], b[i]) for the corresponding elements of a vector, you could instead use step(a, b) * atan2(a, b).
-version: 9
+ This can be useful to create conditional computations without using loops and branching instructions.  For example, instead of computing <code>(a[i] &lt; b[i]) ? 0.f : @atan2(a[i], b[i])</code> for the corresponding elements of a vector, you could instead use <code>step(a, b) * @atan2(a, b)</code>.
 end:
 
-start:
+function: step
+version: 9
+attrib: const
 w: 2, 3, 4
 t: f32
-name: step
 ret: #2#1
 arg: #2#1 edge
 arg: #2 v
-comment:
- Returns 0.f if v < edge, 1.f otherwise.
-
- This can be useful to create conditional computations without using loops and branching instructions.  For example, instead of computing (a[i] < b) ? 0.f : atan2(a[i], b) for each element of a vector, you could instead use step(a, b) * atan2(a, b).
-version: 9
 end:
 
-start:
+function: step
+version: 21
+attrib: const
 w: 2, 3, 4
 t: f32
-name: step
 ret: #2#1
 arg: #2 edge
 arg: #2#1 v
-comment:
- Returns 0.f if v < edge, 1.f otherwise.
-
- This can be useful to create conditional computations without using loops and branching instructions.  For example, instead of computing (a < b[i]) ? 0.f : atan2(a, b[i]) for each element of a vector, you could instead use step(a, b) * atan2(a, b).
-version: 21
 end:
 
-start:
+function: tan
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: tan
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Tangent
+description:
  Returns the tangent of an angle measured in radians.
-version: 9
+
+ See also @native_tan().
 end:
 
-start:
+function: tanh
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: tanh
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Hyperbolic tangent
+description:
  Returns the hyperbolic tangent of a value.
-version: 9
+
+ See also @native_tanh().
 end:
 
-start:
+function: tanpi
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: tanpi
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Tangent of a number multiplied by pi
+description:
  Returns the tangent of (v * pi), where (v * pi) is measured in radians.
 
- To get the tangent of a value measured in degrees, call tanpi(v / 180.f).
-version: 9
+ To get the tangent of a value measured in degrees, call <code>tanpi(v / 180.f)</code>.
+
+ See also @native_tanpi().
 end:
 
-start:
+function: tgamma
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: tgamma
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Gamma function
+description:
  Returns the gamma function of a value.
-version: 9
+
+ See also @lgamma().
 end:
 
-start:
+function: trunc
+version: 9
+attrib: const
 w: 1, 2, 3, 4
 t: f32
-name: trunc
 ret: #2#1
 arg: #2#1 v
-comment:
+summary: Truncates a floating point
+description:
  Rounds to integral using truncation.
 
- For example, trunc(1.7f) returns 1.f and trunc(-1.7f) returns -1.f.
+ For example, <code>trunc(1.7f)</code> returns 1.f and <code>trunc(-1.7f)</code> returns -1.f.
 
- See rint() and round() for other rounding options.
-version: 9
+ See @rint() and @round() for other rounding options.
 end:
diff --git a/api/rs_debug.spec b/api/rs_debug.spec
new file mode 100644
index 0000000..b357b33
--- /dev/null
+++ b/api/rs_debug.spec
@@ -0,0 +1,138 @@
+#
+# 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.
+#
+
+header:
+summary: Utility debugging routines
+description:
+ Routines intended to be used during application developement.  These should
+ not be used in shipping applications.  All print a string and value pair to
+ the standard log.
+include:
+ #define RS_DEBUG(a) rsDebug(#a, a)
+ #define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
+end:
+
+function: rsDebug
+t: i32, u32, i64, u64, f64
+ret: void
+arg: const char* message
+arg: #1 a
+summary:
+description:
+ Debug function.  Prints a string and value to the log.
+test: none
+end:
+
+function: rsDebug
+version: 17
+w: 2, 3, 4
+# TODO We're not doing it for f64?
+t: i32, u32, i64, u64
+ret: void
+arg: const char* message
+arg: #2#1 a
+test: none
+end:
+
+function: rsDebug
+w: 1, 2, 3, 4
+ret: void
+arg: const char* message
+arg: float#1 a
+test: none
+end:
+
+function: rsDebug
+version: 17
+w: 1, 2, 3, 4
+t: i8, u8, i16, u16
+ret: void
+arg: const char* message
+arg: #2#1 a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: float a
+arg: float b
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: float a
+arg: float b
+arg: float c
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: float a
+arg: float b
+arg: float c
+arg: float d
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: long long a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: unsigned long long a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: const void* a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: const rs_matrix4x4* a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: const rs_matrix3x3* a
+test: none
+end:
+
+function: rsDebug
+ret: void
+arg: const char* message
+arg: const rs_matrix2x2* a
+test: none
+end:
+
+#define RS_DEBUG(a) rsDebug(#a, a)
+#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
diff --git a/api/rs_element.spec b/api/rs_element.spec
new file mode 100644
index 0000000..76abd96
--- /dev/null
+++ b/api/rs_element.spec
@@ -0,0 +1,168 @@
+#
+# 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.
+#
+
+header:
+summary: Element functions
+description:
+ The term "element" is used a bit ambiguously in RenderScript, as both
+ the type of an item of an allocation and the instantiation of that type:
+ <ul>
+ <li>@rs_element is a handle to a type specification, and</li>
+
+ <li>In functions like @rsGetElementAt(), "element" means the instantiation
+ of the type, i.e. an item of an allocation.</li></ul>
+
+ The functions below let you query the characteristics of the type specificiation.
+
+ To create complex elements, use the <a href='http://developer.android.com/reference/android/renderscript/Element.Builder.html'>Element.Builder</a> Java class.
+ For common elements, in Java you can simply use one of the many predefined elements
+ like <a href='http://developer.android.com/reference/android/renderscript/Element.html#F32_2(android.renderscript.RenderScript)'>F32_2</a>.  You can't create elements from a script.
+
+ An element can be a simple data type as found in C/C++, a handle type,
+ a structure, or a fixed size vector (of size 2, 3, or 4) of sub-elements.
+
+ Elements can also have a kind, which is semantic information used mostly to
+ interpret pixel data.
+end:
+
+function: rsElementGetBytesSize
+version: 16
+ret: uint32_t
+arg: rs_element e
+summary: Return the size of an element
+description:
+ Returns the size in bytes that an instantiation of this element will occupy.
+test: none
+end:
+
+function: rsElementGetDataKind
+version: 16
+ret: rs_data_kind
+arg: rs_element e
+summary: Return the kind of an element
+description:
+ Returns the element's data kind.  This is used to interpret pixel data.
+
+ See @rs_data_kind.
+test: none
+end:
+
+function: rsElementGetDataType
+version: 16
+ret: rs_data_type
+arg: rs_element e
+summary: Return the data type of an element
+description:
+ Returns the element's base data type.  This can be a type similar to C/C++ (e.g. RS_TYPE_UNSIGNED_8),
+ a handle (e.g. RS_TYPE_ALLOCATION and RS_TYPE_ELEMENT), or a more complex numerical type
+ (e.g.RS_TYPE_UNSIGNED_5_6_5 and RS_TYPE_MATRIX_4X4).
+
+ If the element describes a vector, this function returns the data type of one of its items.
+
+ If the element describes a structure, RS_TYPE_NONE is returned.
+
+ See @rs_data_type.
+test: none
+end:
+
+function: rsElementGetSubElement
+version: 16
+ret: rs_element, "Sub-element at the given index"
+arg: rs_element e, "Element to query"
+arg: uint32_t index, "Index of the sub-element to return"
+summary: Return a sub element of a complex element
+description:
+ For the element represents a structure, this function returns the sub-element at
+ the specified index.
+
+ If the element is not a structure or the index is greater or equal to the number
+ of sub-elements, an invalid handle is returned.
+test: none
+end:
+
+function: rsElementGetSubElementArraySize
+version: 16
+ret: uint32_t, "Array size of the sub-element at the given index"
+arg: rs_element e, "Element to query"
+arg: uint32_t index, "Index of the sub-element"
+summary: Return the array size of a sub element of a complex element
+description:
+ For complex elements, some sub-elements could be statically
+ sized arrays. This function returns the array size of the
+ sub-element at the index.
+test: none
+end:
+
+function: rsElementGetSubElementCount
+version: 16
+ret: uint32_t, "Number of sub-elements in this element"
+arg: rs_element e, "Element to get data from"
+summary: Return the number of sub-elements
+description:
+ Elements could be simple, such as an int or a float, or a
+ structure with multiple sub-elements, such as a collection of
+ floats, float2, float4.  This function returns zero for simple
+ elements or the number of sub-elements otherwise.
+test: none
+end:
+
+function: rsElementGetSubElementName
+version: 16
+ret: uint32_t, "Number of characters actually written, excluding the null terminator"
+arg: rs_element e, "Element to get data from"
+arg: uint32_t index, "Index of the sub-element"
+arg: char* name, "Array to store the name into"
+arg: uint32_t nameLength, "Length of the provided name array"
+summary: Return the name of a sub-element
+description:
+ For complex elements, this function returns the name of the sub-element
+ at the specified index.
+test: none
+end:
+
+function: rsElementGetSubElementNameLength
+version: 16
+ret: uint32_t, "Length of the sub-element name including the null terminator (size of buffer needed to write the name)"
+arg: rs_element e, "Element to get data from"
+arg: uint32_t index, "Index of the sub-element to return"
+summary: Return the length of the name of a sub-element
+description:
+ For complex elements, this function will return the length of
+ sub-element name at index
+test: none
+end:
+
+function: rsElementGetSubElementOffsetBytes
+version: 16
+ret: uint32_t, "Offset in bytes of sub-element in this element at given index"
+arg: rs_element e, "Element to get data from"
+arg: uint32_t index, "Index of the sub-element"
+summary:
+description:
+ This function specifies the location of a sub-element within
+ the element
+test: none
+end:
+
+function: rsElementGetVectorSize
+version: 16
+ret: uint32_t, "Length of the element vector (for float2, float3, etc.)"
+arg: rs_element e, "Element to get data from"
+summary:
+description:
+ Returns the element's vector size
+test: none
+end:
diff --git a/api/rs_graphics.spec b/api/rs_graphics.spec
new file mode 100644
index 0000000..37d421f
--- /dev/null
+++ b/api/rs_graphics.spec
@@ -0,0 +1,537 @@
+#
+# 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.
+#
+
+header:
+summary: RenderScript graphics API
+description:
+ A set of graphics functions used by RenderScript.
+include:
+ #ifdef __LP64__
+ // TODO We need to fix some of the builds before enabling this error:
+ // #error "RenderScript graphics is deprecated and not supported in 64bit mode."
+ #else
+ #include "rs_mesh.rsh"
+ #include "rs_program.rsh"
+ #endif
+end:
+
+function: rsgAllocationSyncAll
+size: 32
+ret: void
+arg: rs_allocation alloc
+summary:
+description:
+ Sync the contents of an allocation.
+
+ If the source is specified, sync from memory space specified by source.
+
+ If the source is not specified, sync from its SCRIPT memory space to its HW
+ memory spaces.
+test: none
+end:
+
+function: rsgAllocationSyncAll
+version: 14
+size: 32
+ret: void
+arg: rs_allocation alloc
+arg: rs_allocation_usage_type source
+test: none
+end:
+
+function: rsgBindColorTarget
+version: 14
+size: 32
+ret: void
+arg: rs_allocation colorTarget
+arg: uint slot
+summary:
+description:
+ Set the color target used for all subsequent rendering calls
+test: none
+end:
+
+function: rsgBindConstant
+size: 32
+ret: void
+arg: rs_program_fragment ps, "program fragment object"
+arg: uint slot, "index of the constant buffer on the program"
+arg: rs_allocation c, "constants to bind"
+summary:
+description:
+ Bind a new Allocation object to a ProgramFragment or ProgramVertex.
+ The Allocation must be a valid constant input for the Program.
+test: none
+end:
+
+function: rsgBindConstant
+size: 32
+ret: void
+arg: rs_program_vertex pv, "program vertex object"
+arg: uint slot
+arg: rs_allocation c
+test: none
+end:
+
+function: rsgBindDepthTarget
+version: 14
+size: 32
+ret: void
+arg: rs_allocation depthTarget
+summary:
+description:
+ Set the depth target used for all subsequent rendering calls
+test: none
+end:
+
+function: rsgBindFont
+size: 32
+ret: void
+arg: rs_font font, "object to bind"
+summary:
+description:
+ Binds the font object to be used for all subsequent font rendering calls
+test: none
+end:
+
+function: rsgBindProgramFragment
+size: 32
+ret: void
+arg: rs_program_fragment pf
+summary:
+description:
+ Bind a new ProgramFragment to the rendering context.
+test: none
+end:
+
+function: rsgBindProgramRaster
+size: 32
+ret: void
+arg: rs_program_raster pr
+summary:
+description:
+ Bind a new ProgramRaster to the rendering context.
+test: none
+end:
+
+function: rsgBindProgramStore
+size: 32
+ret: void
+arg: rs_program_store ps
+summary:
+description:
+ Bind a new ProgramStore to the rendering context.
+test: none
+end:
+
+function: rsgBindProgramVertex
+size: 32
+ret: void
+arg: rs_program_vertex pv
+summary:
+description:
+ Bind a new ProgramVertex to the rendering context.
+test: none
+end:
+
+function: rsgBindSampler
+size: 32
+ret: void
+arg: rs_program_fragment fragment
+arg: uint slot
+arg: rs_sampler sampler
+summary:
+description:
+ Bind a new Sampler object to a ProgramFragment.  The sampler will
+ operate on the texture bound at the matching slot.
+test: none
+end:
+
+function: rsgBindTexture
+size: 32
+ret: void
+arg: rs_program_fragment v
+arg: uint slot
+arg: rs_allocation alloc
+summary:
+description:
+ Bind a new Allocation object to a ProgramFragment.  The
+ Allocation must be a valid texture for the Program.  The sampling
+ of the texture will be controled by the Sampler bound at the
+ matching slot.
+test: none
+end:
+
+function: rsgClearAllRenderTargets
+version: 14
+size: 32
+ret: void
+summary:
+description:
+ Clear all color and depth targets and resume rendering into
+ the framebuffer
+test: none
+end:
+
+function: rsgClearColor
+size: 32
+ret: void
+arg: float r
+arg: float g
+arg: float b
+arg: float a
+summary:
+description:
+ Clears the rendering surface to the specified color.
+test: none
+end:
+
+function: rsgClearColorTarget
+version: 14
+size: 32
+ret: void
+arg: uint slot
+summary:
+description:
+ Clear the previously set color target
+test: none
+end:
+
+function: rsgClearDepth
+size: 32
+ret: void
+arg: float value
+summary:
+description:
+ Clears the depth suface to the specified value.
+test: none
+end:
+
+function: rsgClearDepthTarget
+version: 14
+size: 32
+ret: void
+summary:
+description:
+ Clear the previously set depth target
+test: none
+end:
+
+function: rsgDrawMesh
+size: 32
+ret: void
+arg: rs_mesh ism, "mesh object to render"
+summary:
+description:
+ Draw a mesh using the current context state.
+
+ If primitiveIndex is specified, draw part of a mesh using the current context state.
+
+ If start and len are also specified, draw specified index range of part of a mesh using the current context state.
+
+ Otherwise the whole mesh is rendered.
+test: none
+end:
+
+function: rsgDrawMesh
+size: 32
+ret: void
+arg: rs_mesh ism
+arg: uint primitiveIndex, "for meshes that contain multiple primitive groups this parameter specifies the index of the group to draw."
+test: none
+end:
+
+function: rsgDrawMesh
+size: 32
+ret: void
+arg: rs_mesh ism
+arg: uint primitiveIndex
+arg: uint start, "starting index in the range"
+arg: uint len, "number of indices to draw"
+test: none
+end:
+
+function: rsgDrawQuad
+size: 32
+ret: void
+arg: float x1
+arg: float y1
+arg: float z1
+arg: float x2
+arg: float y2
+arg: float z2
+arg: float x3
+arg: float y3
+arg: float z3
+arg: float x4
+arg: float y4
+arg: float z4
+summary:
+description:
+ Low performance utility function for drawing a simple quad.  Not intended for
+ drawing large quantities of geometry.
+test: none
+end:
+
+function: rsgDrawQuadTexCoords
+size: 32
+ret: void
+arg: float x1
+arg: float y1
+arg: float z1
+arg: float u1
+arg: float v1
+arg: float x2
+arg: float y2
+arg: float z2
+arg: float u2
+arg: float v2
+arg: float x3
+arg: float y3
+arg: float z3
+arg: float u3
+arg: float v3
+arg: float x4
+arg: float y4
+arg: float z4
+arg: float u4
+arg: float v4
+summary:
+description:
+ Low performance utility function for drawing a textured quad.  Not intended
+ for drawing large quantities of geometry.
+test: none
+end:
+
+function: rsgDrawRect
+size: 32
+ret: void
+arg: float x1
+arg: float y1
+arg: float x2
+arg: float y2
+arg: float z
+summary:
+description:
+ Low performance utility function for drawing a simple rectangle.  Not
+ intended for drawing large quantities of geometry.
+test: none
+end:
+
+function: rsgDrawSpriteScreenspace
+size: 32
+ret: void
+arg: float x
+arg: float y
+arg: float z
+arg: float w
+arg: float h
+summary:
+description:
+ Low performance function for drawing rectangles in screenspace.  This
+ function uses the default passthough ProgramVertex.  Any bound ProgramVertex
+ is ignored.  This function has considerable overhead and should not be used
+ for drawing in shipping applications.
+test: none
+end:
+
+function: rsgDrawText
+size: 32
+ret: void
+arg: const char* text
+arg: int x
+arg: int y
+summary:
+description:
+ Draws text given a string and location
+test: none
+end:
+
+function: rsgDrawText
+size: 32
+ret: void
+arg: rs_allocation alloc
+arg: int x
+arg: int y
+test: none
+end:
+
+function: rsgFinish
+version: 14
+size: 32
+ret: uint
+summary:
+description:
+ Force RenderScript to finish all rendering commands
+test: none
+end:
+
+function: rsgFontColor
+size: 32
+ret: void
+arg: float r, "red component"
+arg: float g, "green component"
+arg: float b, "blue component"
+arg: float a, "alpha component"
+summary:
+description:
+ Sets the font color for all subsequent rendering calls
+test: none
+end:
+
+function: rsgGetHeight
+size: 32
+ret: uint
+summary:
+description:
+ Get the height of the current rendering surface.
+test: none
+end:
+
+function: rsgGetWidth
+size: 32
+ret: uint
+summary:
+description:
+ Get the width of the current rendering surface.
+test: none
+end:
+
+function: rsgMeasureText
+size: 32
+ret: void
+arg: const char* text
+arg: int* left
+arg: int* right
+arg: int* top
+arg: int* bottom
+summary:
+description:
+ Returns the bounding box of the text relative to (0, 0)
+ Any of left, right, top, bottom could be NULL
+test: none
+end:
+
+function: rsgMeasureText
+size: 32
+ret: void
+arg: rs_allocation alloc
+arg: int* left
+arg: int* right
+arg: int* top
+arg: int* bottom
+test: none
+end:
+
+function: rsgMeshComputeBoundingBox
+size: 32
+ret: void
+arg: rs_mesh mesh
+arg: float* minX
+arg: float* minY
+arg: float* min
+arg: float* maxX
+arg: float* maxY
+arg: float* maxZ
+summary:
+description:
+ Computes an axis aligned bounding box of a mesh object
+test: none
+end:
+
+function: rsgMeshComputeBoundingBox
+size: 32
+attrib: always_inline
+ret: void
+arg: rs_mesh mesh
+arg: float3* bBoxMin
+arg: float3* bBoxMax
+inline:
+ float x1, y1, z1, x2, y2, z2;
+ rsgMeshComputeBoundingBox(mesh, &x1, &y1, &z1, &x2, &y2, &z2);
+ bBoxMin->x = x1;
+ bBoxMin->y = y1;
+ bBoxMin->z = z1;
+ bBoxMax->x = x2;
+ bBoxMax->y = y2;
+ bBoxMax->z = z2;
+test: none
+end:
+
+
+function: rsgProgramFragmentConstantColor
+size: 32
+ret: void
+arg: rs_program_fragment pf
+arg: float r
+arg: float g
+arg: float b
+arg: float a
+summary:
+description:
+ Set the constant color for a fixed function emulation program.
+test: none
+end:
+
+function: rsgProgramVertexGetProjectionMatrix
+size: 32
+ret: void
+arg: rs_matrix4x4* proj, "matrix to store the current projection matrix into"
+summary:
+description:
+ Get the projection matrix for a currently bound fixed function
+ vertex program. Calling this function with a custom vertex shader
+ would result in an error.
+test: none
+end:
+
+function: rsgProgramVertexLoadModelMatrix
+size: 32
+ret: void
+arg: const rs_matrix4x4* model, "model matrix"
+summary:
+description:
+ Load the model matrix for a currently bound fixed function
+ vertex program. Calling this function with a custom vertex shader
+ would result in an error.
+test: none
+end:
+
+function: rsgProgramVertexLoadProjectionMatrix
+size: 32
+ret: void
+arg: const rs_matrix4x4* proj, "projection matrix"
+summary:
+description:
+ Load the projection matrix for a currently bound fixed function
+ vertex program. Calling this function with a custom vertex shader
+ would result in an error.
+test: none
+end:
+
+function: rsgProgramVertexLoadTextureMatrix
+size: 32
+ret: void
+arg: const rs_matrix4x4* tex, "texture matrix"
+summary:
+description:
+ Load the texture matrix for a currently bound fixed function
+ vertex program. Calling this function with a custom vertex shader
+ would result in an error.
+test: none
+end:
+
+#endif //__LP64__
diff --git a/api/rs_math.spec b/api/rs_math.spec
new file mode 100644
index 0000000..af84461
--- /dev/null
+++ b/api/rs_math.spec
@@ -0,0 +1,242 @@
+#
+# 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.
+#
+
+header:
+summary: TODO Add documentation
+description:
+ TODO Add documentation
+end:
+
+function: rsClamp
+# TODO Why always_inline?
+attrib: const, always_inline
+t: i8, i16, i32, u8, u16, u32
+ret: #1
+arg: #1 amount, "The value to clamp"
+arg: #1 low, "Lower bound"
+arg: #1 high, "Upper bound"
+summary: Restrain a value to a range
+description:
+ Clamp a value between low and high.
+
+ Deprecated.  Use @clamp() instead.
+test: none
+end:
+
+function: rsExtractFrustumPlanes
+# TODO Why always_inline?
+attrib: always_inline
+ret: void
+arg: const rs_matrix4x4* viewProj, "matrix to extract planes from"
+arg: float4* left, "left plane"
+arg: float4* right, "right plane"
+arg: float4* top, "top plane"
+arg: float4* bottom, "bottom plane"
+arg: float4* near, "near plane"
+arg: float4* far, "far plane"
+summary:
+description:
+ Computes 6 frustum planes from the view projection matrix
+inline:
+ // x y z w = a b c d in the plane equation
+ left->x = viewProj->m[3] + viewProj->m[0];
+ left->y = viewProj->m[7] + viewProj->m[4];
+ left->z = viewProj->m[11] + viewProj->m[8];
+ left->w = viewProj->m[15] + viewProj->m[12];
+
+ right->x = viewProj->m[3] - viewProj->m[0];
+ right->y = viewProj->m[7] - viewProj->m[4];
+ right->z = viewProj->m[11] - viewProj->m[8];
+ right->w = viewProj->m[15] - viewProj->m[12];
+
+ top->x = viewProj->m[3] - viewProj->m[1];
+ top->y = viewProj->m[7] - viewProj->m[5];
+ top->z = viewProj->m[11] - viewProj->m[9];
+ top->w = viewProj->m[15] - viewProj->m[13];
+
+ bottom->x = viewProj->m[3] + viewProj->m[1];
+ bottom->y = viewProj->m[7] + viewProj->m[5];
+ bottom->z = viewProj->m[11] + viewProj->m[9];
+ bottom->w = viewProj->m[15] + viewProj->m[13];
+
+ near->x = viewProj->m[3] + viewProj->m[2];
+ near->y = viewProj->m[7] + viewProj->m[6];
+ near->z = viewProj->m[11] + viewProj->m[10];
+ near->w = viewProj->m[15] + viewProj->m[14];
+
+ far->x = viewProj->m[3] - viewProj->m[2];
+ far->y = viewProj->m[7] - viewProj->m[6];
+ far->z = viewProj->m[11] - viewProj->m[10];
+ far->w = viewProj->m[15] - viewProj->m[14];
+
+ float len = length(left->xyz);
+ *left /= len;
+ len = length(right->xyz);
+ *right /= len;
+ len = length(top->xyz);
+ *top /= len;
+ len = length(bottom->xyz);
+ *bottom /= len;
+ len = length(near->xyz);
+ *near /= len;
+ len = length(far->xyz);
+ *far /= len;
+test: none
+end:
+
+function: rsFrac
+attrib: const
+ret: float
+arg: float v
+summary:
+description:
+ Returns the fractional part of a float
+test: none
+end:
+
+function: rsIsSphereInFrustum
+attrib: always_inline
+ret: bool
+arg: float4* sphere, "float4 representing the sphere"
+arg: float4* left, "left plane"
+arg: float4* right, "right plane"
+arg: float4* top, "top plane"
+arg: float4* bottom, "bottom plane"
+arg: float4* near, "near plane"
+arg: float4* far, "far plane"
+summary:
+description:
+ Checks if a sphere is withing the 6 frustum planes
+inline:
+ float distToCenter = dot(left->xyz, sphere->xyz) + left->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ distToCenter = dot(right->xyz, sphere->xyz) + right->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ distToCenter = dot(top->xyz, sphere->xyz) + top->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ distToCenter = dot(bottom->xyz, sphere->xyz) + bottom->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ distToCenter = dot(near->xyz, sphere->xyz) + near->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ distToCenter = dot(far->xyz, sphere->xyz) + far->w;
+ if (distToCenter < -sphere->w) {
+     return false;
+ }
+ return true;
+test: none
+end:
+
+function: rsPackColorTo8888
+attrib: const
+ret: uchar4
+arg: float r
+arg: float g
+arg: float b
+summary:
+description:
+ Pack floating point (0-1) RGB values into a uchar4.
+
+ For the float3 variant and the variant that only specifies r, g, b,
+ the alpha component is set to 255 (1.0).
+test: none
+end:
+
+function: rsPackColorTo8888
+attrib: const
+ret: uchar4
+arg: float r
+arg: float g
+arg: float b
+arg: float a
+test: none
+end:
+
+function: rsPackColorTo8888
+attrib: const
+ret: uchar4
+arg: float3 color
+test: none
+end:
+
+function: rsPackColorTo8888
+attrib: const
+ret: uchar4
+arg: float4 color
+test: none
+end:
+
+function: rsRand
+ret: int
+arg: int max_value
+summary:
+description:
+ Return a random value between 0 (or min_value) and max_malue.
+test: none
+end:
+
+function: rsRand
+ret: int
+arg: int min_value
+arg: int max_value
+test: none
+end:
+
+function: rsRand
+ret: float
+arg: float max_value
+test: none
+end:
+
+function: rsRand
+ret: float
+arg: float min_value
+arg: float max_value
+test: none
+end:
+
+function: rsUnpackColor8888
+attrib: =const
+ret: float4
+arg: uchar4 c
+summary:
+description:
+ Unpack a uchar4 color to float4.  The resulting float range will be (0-1).
+test: none
+end:
+
+function: rsYuvToRGBA_#2#1
+attrib: const
+w: 4
+t: u8, f32
+ret: #2#1
+arg: uchar y
+arg: uchar u
+arg: uchar v
+summary:
+description:
+ Convert from YUV to RGBA.
+test: none
+end:
diff --git a/api/rs_matrix.spec b/api/rs_matrix.spec
new file mode 100644
index 0000000..7afbeff
--- /dev/null
+++ b/api/rs_matrix.spec
@@ -0,0 +1,466 @@
+#
+# 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.
+#
+
+header:
+summary: Matrix functions
+description:
+ These functions let you manipulate square matrices of rank 2x2, 3x3, and 4x4.
+ They are particularly useful for graphical transformations and are
+ compatible with OpenGL.
+
+ We use a zero-based index for rows and columns.  E.g. the last element of
+ a @rs_matrix4x4 is found at (3, 3).
+
+ RenderScript uses column-major matrices and column-based vectors.
+ Transforming a vector is done by postmultiplying the vector,
+ e.g. <code>(matrix * vector)</code>, as provided by @rsMatrixMultiply().
+
+ To create a transformation matrix that performs two transformations at
+ once, multiply the two source matrices, with the first transformation as the
+ right argument.  E.g. to create a transformation matrix that applies the
+ transformation s1 followed by s2, call <code>rsMatrixLoadMultiply(&combined, &s2, &s1)</code>.
+ This derives from <code>s2 * (s1 * v)</code>, which is <code>(s2 * s1) * v</code>.
+
+ We have two style of functions to create transformation matrices:
+ rsMatrixLoad<i>Transformation</i> and rsMatrix<i>Transformation</i>.  The
+ former style simply stores the transformation matrix in the first argument.
+ The latter modifies a pre-existing transformation matrix so that the new
+ transformation happens first.  E.g. if you call @rsMatrixTranslate()
+ on a matrix that already does a scaling, the resulting matrix when applied
+ to a vector will first do the translation then the scaling.
+end:
+
+function: rsMatrixGet
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: float
+arg: const #1* m, "The matrix to extract the element from."
+arg: uint32_t col, "The zero-based column of the element to be extracted."
+arg: uint32_t row, "The zero-based row of the element to extracted."
+summary: Get one element
+description:
+ Returns one element of a matrix.
+
+ <b>Warning:</b> The order of the column and row parameters may be unexpected.
+test: none
+end:
+
+function: rsMatrixInverse
+ret: bool
+arg: rs_matrix4x4* m, "The matrix to invert."
+summary: Inverts a matrix in place
+description:
+ Returns true if the matrix was successfully inverted.
+test: none
+end:
+
+
+function: rsMatrixInverseTranspose
+ret: bool
+arg: rs_matrix4x4* m, "The matrix to modify."
+summary: Inverts and transpose a matrix in place
+description:
+ The matrix is first inverted then transposed.
+ Returns true if the matrix was successfully inverted.
+test: none
+end:
+
+
+function: rsMatrixLoad
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* destination, "The matrix to set."
+arg: const float* array, "The array of values to set the matrix to. These arrays should be 4, 9, or 16 floats long, depending on the matrix size."
+summary: Load or copy a matrix
+description:
+ Set the elements of a matrix from an array of floats or from another matrix.
+
+ If loading from an array, the floats should be in row-major order, i.e. the element a
+ <code>row 0, column 0</code> should be first, followed by the element at
+ <code>row 0, column 1</code>, etc.
+
+ If loading from a matrix and the source is smaller than the destination, the rest of the
+ destination is filled with elements of the identity matrix.  E.g.
+ loading a rs_matrix2x2 into a rs_matrix4x4 will give:
+ <table style="max-width:300px">
+ <tr><td>m00</td> <td>m01</td> <td>0.0</td> <td>0.0</td></tr>
+ <tr><td>m10</td> <td>m11</td> <td>0.0</td> <td>0.0</td></tr>
+ <tr><td>0.0</td> <td>0.0</td> <td>1.0</td> <td>0.0</td></tr>
+ <tr><td>0.0</td> <td>0.0</td> <td>0.0</td> <td>1.0</td></tr>
+ </table>
+test: none
+end:
+
+function: rsMatrixLoad
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* destination
+arg: const #1* source, "The source matrix."
+test: none
+end:
+
+function: rsMatrixLoad
+t: rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: rs_matrix4x4* destination
+arg: const #1* source
+test: none
+end:
+
+function: rsMatrixLoadFrustum
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float left
+arg: float right
+arg: float bottom
+arg: float top
+arg: float near
+arg: float far
+summary: Load a frustum projection matrix
+description:
+ Constructs a frustum projection matrix, transforming the box
+ identified by the six clipping planes <code>left, right, bottom, top,
+ near, far</code>.
+
+ To apply this projection to a vector, multiply the vector by the
+ created matrix using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixLoadIdentity
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* m, "The matrix to set."
+summary: Load identity matrix
+description:
+ Set the elements of a matrix to the identity matrix.
+test: none
+end:
+
+function: rsMatrixLoadMultiply
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* m, "The matrix to set."
+arg: const #1* lhs, "The left matrix of the product."
+arg: const #1* rhs, "The right matrix of the product."
+summary: Multiply two matrices
+description:
+ Sets m to the matrix product of <code>lhs * rhs</code>.
+
+ To combine two 4x4 transformaton matrices, multiply the second transformation matrix
+ by the first transformation matrix.  E.g. to create a transformation matrix that applies
+ the transformation s1 followed by s2, call
+ <code>rsMatrixLoadMultiply(&combined, &s2, &s1)</code>.
+
+ <b>Warning:</b> Prior to version 21, storing the result back into right matrix is not supported and
+ will result in undefined behavior.  Use rsMatrixMulitply instead.   E.g. instead of doing
+ rsMatrixLoadMultiply (&m2r, &m2r, &m2l), use rsMatrixMultiply (&m2r, &m2l).
+ rsMatrixLoadMultiply (&m2l, &m2r, &m2l) works as expected.
+test: none
+end:
+
+function: rsMatrixLoadOrtho
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float left
+arg: float right
+arg: float bottom
+arg: float top
+arg: float near
+arg: float far
+summary: Load an orthographic projection matrix
+description:
+ Constructs an orthographic projection matrix, transforming the box
+ identified by the six clipping planes <code>left, right, bottom, top,
+ near, far</code> into a unit cube with a corner at
+ <code>(-1, -1, -1)</code> and the opposite at <code>(1, 1, 1)</code>.
+
+ To apply this projection to a vector, multiply the vector by the
+ created matrix using @rsMatrixMultiply().
+
+ See https://en.wikipedia.org/wiki/Orthographic_projection .
+test: none
+end:
+
+function: rsMatrixLoadPerspective
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float fovy, "Field of view, in degrees along the Y axis."
+arg: float aspect, "Ratio of x / y."
+arg: float near, "The near clipping plane."
+arg: float far, "The far clipping plane."
+summary: Load a perspective projection matrix
+description:
+ Constructs a perspective projection matrix, assuming a symmetrical field of view.
+
+ To apply this projection to a vector, multiply the vector by the
+ created matrix using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixLoadRotate
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float rot, "How much rotation to do, in degrees."
+arg: float x, "The x component of the vector that is the axis of rotation."
+arg: float y, "The y component of the vector that is the axis of rotation."
+arg: float z, "The z component of the vector that is the axis of rotation."
+summary: Load a rotation matrix
+description:
+ This function creates a rotation matrix.  The axis of rotation is the
+ <code>(x, y, z)</code> vector.
+
+ To rotate a vector, multiply the vector by the created matrix
+ using @rsMatrixMultiply().
+
+ See http://en.wikipedia.org/wiki/Rotation_matrix .
+test: none
+end:
+
+function: rsMatrixLoadScale
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float x, "The multiple to scale the x components by."
+arg: float y, "The multiple to scale the y components by."
+arg: float z, "The multiple to scale the z components by."
+summary: Load a scaling matrix
+description:
+ This function creates a scaling matrix, where each component of a
+ vector is multiplied by a number.  This number can be negative.
+
+ To scale a vector, multiply the vector by the created matrix
+ using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixLoadTranslate
+ret: void
+arg: rs_matrix4x4* m, "The matrix to set."
+arg: float x, "The number to add to each x component."
+arg: float y, "The number to add to each y component."
+arg: float z, "The number to add to each z component."
+summary: Load a translation matrix
+description:
+ This function creates a translation matrix, where a
+ number is added to each element of a vector.
+
+ To translate a vector, multiply the vector by the created matrix
+ using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixMultiply
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* m, "The left matrix of the product and the matrix to be set."
+arg: const #1* rhs, "The right matrix of the product."
+summary: Multiply a matrix by a vector or another matrix
+description:
+ For the matrix by matrix variant, sets m to the matrix product <code>m * rhs</code>.
+
+ When combining two 4x4 transformation matrices using this function, the resulting
+ matrix will correspond to performing the rhs transformation first followed by
+ the original m transformation.
+
+ For the matrix by vector variant, returns the post-multiplication of the vector
+ by the matrix, ie. <code>m * in</code>.
+
+ When multiplying a float3 to a @rs_matrix4x4, the vector is expanded with (1).
+
+ When multiplying a float2 to a @rs_matrix4x4, the vector is expanded with (0, 1).
+
+ When multiplying a float2 to a @rs_matrix3x3, the vector is expanded with (0).
+
+ Starting with API 14, this function takes a const matrix as the first argument.
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float4
+arg: rs_matrix4x4* m
+arg: float4 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float4
+arg: rs_matrix4x4* m
+arg: float3 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float4
+arg: rs_matrix4x4* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float3
+arg: rs_matrix3x3* m
+arg: float3 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float3
+arg: rs_matrix3x3* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 9 13
+ret: float2
+arg: rs_matrix2x2* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float4
+arg: const rs_matrix4x4* m
+arg: float4 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float4
+arg: const rs_matrix4x4* m
+arg: float3 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float4
+arg: const rs_matrix4x4* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float3
+arg: const rs_matrix3x3* m
+arg: float3 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float3
+arg: const rs_matrix3x3* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixMultiply
+version: 14
+ret: float2
+arg: const rs_matrix2x2* m
+arg: float2 in
+test: none
+end:
+
+function: rsMatrixRotate
+ret: void
+arg: rs_matrix4x4* m, "The matrix to modify."
+arg: float rot, "How much rotation to do, in degrees."
+arg: float x, "The x component of the vector that is the axis of rotation."
+arg: float y, "The y component of the vector that is the axis of rotation."
+arg: float z, "The z component of the vector that is the axis of rotation."
+summary: Apply a rotation to a transformation matrix
+description:
+ Multiply the matrix m with a rotation matrix.
+
+ This function modifies a transformation matrix to first do a rotation.
+ The axis of rotation is the <code>(x, y, z)</code> vector.
+
+ To apply this combined transformation to a vector, multiply
+ the vector by the created matrix using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixScale
+ret: void
+arg: rs_matrix4x4* m, "The matrix to modify."
+arg: float x, "The multiple to scale the x components by."
+arg: float y, "The multiple to scale the y components by."
+arg: float z, "The multiple to scale the z components by."
+summary: Apply a scaling to a transformation matrix
+description:
+ Multiply the matrix m with a scaling matrix.
+
+ This function modifies a transformation matrix to first do a scaling.
+ When scaling, each component of a vector is multiplied by a number.
+ This number can be negative.
+
+ To apply this combined transformation to a vector, multiply
+ the vector by the created matrix using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixSet
+t: rs_matrix4x4, rs_matrix3x3, rs_matrix2x2
+ret: void
+arg: #1* m, "The matrix that will be modified."
+arg: uint32_t col, "The zero-based column of the element to be set."
+arg: uint32_t row, "The zero-based row of the element to be set."
+arg: float v, "The value to set."
+summary: Set one element
+description:
+ Set an element of a matrix.
+
+ <b>Warning:</b> The order of the column and row parameters may be unexpected.
+test: none
+end:
+
+function: rsMatrixTranslate
+ret: void
+arg: rs_matrix4x4* m, "The matrix to modify."
+arg: float x, "The number to add to each x component."
+arg: float y, "The number to add to each y component."
+arg: float z, "The number to add to each z component."
+summary: Apply a translation to a transformation matrix
+description:
+ Multiply the matrix m with a translation matrix.
+
+ This function modifies a transformation matrix to first
+ do a translation.  When translating, a number is added
+ to each component of a vector.
+
+ To apply this combined transformation to a vector, multiply
+ the vector by the created matrix using @rsMatrixMultiply().
+test: none
+end:
+
+function: rsMatrixTranspose
+t: rs_matrix4x4*, rs_matrix3x3*, rs_matrix2x2*
+ret: void
+arg: #1 m, "The matrix to transpose."
+summary: Transpose a matrix place
+description:
+ Transpose the matrix m in place.
+test: none
+end:
diff --git a/api/rs_mesh.spec b/api/rs_mesh.spec
new file mode 100644
index 0000000..9fe5e49
--- /dev/null
+++ b/api/rs_mesh.spec
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+header:
+summary: Mesh routines
+description:
+end:
+
+function: rsgMeshGetIndexAllocation
+version: 16
+ret: rs_allocation, "allocation containing index data"
+arg: rs_mesh m, "mesh to get data from"
+arg: uint32_t index, "index of the index allocation"
+summary:
+description:
+ Returns an allocation containing index data or a null
+ allocation if only the primitive is specified
+test: none
+end:
+
+function: rsgMeshGetPrimitive
+version: 16
+ret: rs_primitive, "primitive describing how the mesh is rendered"
+arg: rs_mesh m, "mesh to get data from"
+arg: uint32_t index, "index of the primitive"
+summary:
+description:
+ Returns the primitive describing how a part of the mesh is
+ rendered
+test: none
+end:
+
+function: rsgMeshGetPrimitiveCount
+version: 16
+ret: uint32_t, "number of primitive groups in the mesh. This would include simple primitives as well as allocations containing index data"
+arg: rs_mesh m, "mesh to get data from"
+summary:
+description:
+ Meshes could have multiple index sets, this function returns
+ the number.
+test: none
+end:
+
+function: rsgMeshGetVertexAllocation
+version: 16
+ret: rs_allocation, "allocation containing vertex data"
+arg: rs_mesh m, "mesh to get data from"
+arg: uint32_t index, "index of the vertex allocation"
+summary:
+description:
+ Returns an allocation that is part of the mesh and contains
+ vertex data, e.g. positions, normals, texcoords
+test: none
+end:
+
+function: rsgMeshGetVertexAllocationCount
+version: 16
+ret: uint32_t, "number of allocations in the mesh that contain vertex data"
+arg: rs_mesh m, "mesh to get data from"
+summary:
+description:
+ Returns the number of allocations in the mesh that contain
+ vertex data
+test: none
+end:
diff --git a/api/rs_object.spec b/api/rs_object.spec
new file mode 100644
index 0000000..bb8b446
--- /dev/null
+++ b/api/rs_object.spec
@@ -0,0 +1,76 @@
+#
+# 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.
+#
+
+header:
+summary: Object routines
+description:
+end:
+
+function: rsClearObject
+t: rs_element, rs_type, rs_allocation, rs_sampler, rs_script
+ret: void
+arg: #1* dst
+hidden:
+summary: For internal use.
+description:
+test: none
+end:
+
+function: rsClearObject
+size: 32
+t: rs_mesh, rs_program_fragment, rs_program_vertex, rs_program_raster, rs_program_store, rs_font
+ret: void
+arg: #1* dst
+test: none
+end:
+
+function: rsIsObject
+t: rs_element, rs_type, rs_allocation, rs_sampler, rs_script
+ret: bool
+arg: #1 v
+hidden:
+summary: For internal use.
+description:
+test: none
+end:
+
+function: rsIsObject
+size: 32
+t: rs_mesh, rs_program_fragment, rs_program_vertex, rs_program_raster, rs_program_store, rs_font
+ret: bool
+arg: #1 v
+test: none
+end:
+
+function: rsSetObject
+t: rs_element, rs_type, rs_allocation, rs_sampler, rs_script
+ret: void
+arg: #1* dst
+arg: #1 src
+hidden:
+summary: For internal use.
+description:
+test: none
+end:
+
+function: rsSetObject
+size: 32
+t: rs_mesh, rs_program_fragment, rs_program_vertex, rs_program_raster, rs_program_store, rs_font
+ret: void
+arg: #1* dst
+arg: #1 src
+test: none
+end:
diff --git a/api/rs_program.spec b/api/rs_program.spec
new file mode 100644
index 0000000..a2c39a9
--- /dev/null
+++ b/api/rs_program.spec
@@ -0,0 +1,130 @@
+#
+# 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.
+#
+
+header:
+summary: Program object routines
+description:
+end:
+
+function: rsgProgramRasterGetCullMode
+version: 16
+ret: rs_cull_mode
+arg: rs_program_raster pr, "program raster to query"
+summary:
+description:
+ Get program raster cull mode
+test: none
+end:
+
+function: rsgProgramRasterIsPointSpriteEnabled
+version: 16
+ret: bool
+arg: rs_program_raster pr, "program raster to query"
+summary:
+description:
+ Get program raster point sprite state
+test: none
+end:
+
+function: rsgProgramStoreGetBlendDstFunc
+version: 16
+ret: rs_blend_dst_func
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store blend destination function
+test: none
+end:
+
+function: rsgProgramStoreGetBlendSrcFunc
+version: 16
+ret: rs_blend_src_func
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store blend source function
+test: none
+end:
+
+function: rsgProgramStoreGetDepthFunc
+version: 16
+ret: rs_depth_func
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store depth function
+test: none
+end:
+
+function: rsgProgramStoreIsColorMaskAlphaEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store alpha component color mask
+test: none
+end:
+
+function: rsgProgramStoreIsColorMaskBlueEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store blur component color mask
+test: none
+end:
+
+function: rsgProgramStoreIsColorMaskGreenEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store green component color mask
+test: none
+end:
+
+function: rsgProgramStoreIsColorMaskRedEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store red component color mask
+test: none
+end:
+
+function: rsgProgramStoreIsDepthMaskEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store depth mask
+test: none
+end:
+
+function: rsgProgramStoreIsDitherEnabled
+version: 16
+ret: bool
+arg: rs_program_store ps, "program store to query"
+summary:
+description:
+ Get program store dither state
+test: none
+end:
diff --git a/api/rs_quaternion.spec b/api/rs_quaternion.spec
new file mode 100644
index 0000000..07051a9
--- /dev/null
+++ b/api/rs_quaternion.spec
@@ -0,0 +1,270 @@
+#
+# 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.
+#
+
+header:
+summary: Quaternion routines
+description:
+end:
+
+function: rsQuaternionAdd
+ret: void
+arg: rs_quaternion* q, "destination quaternion to add to"
+arg: const rs_quaternion* rhs, "right hand side quaternion to add"
+summary:
+description:
+ Add two quaternions
+inline:
+ q->w *= rhs->w;
+ q->x *= rhs->x;
+ q->y *= rhs->y;
+ q->z *= rhs->z;
+test: none
+end:
+
+function: rsQuaternionConjugate
+ret: void
+arg: rs_quaternion* q, "quaternion to conjugate"
+summary:
+description:
+ Conjugates the quaternion
+inline:
+ q->x = -q->x;
+ q->y = -q->y;
+ q->z = -q->z;
+test: none
+end:
+
+function: rsQuaternionDot
+ret: float, "dot product between q0 and q1"
+arg: const rs_quaternion* q0, "first quaternion"
+arg: const rs_quaternion* q1, "second quaternion"
+summary:
+description:
+ Dot product of two quaternions
+inline:
+ return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
+test: none
+end:
+
+function: rsQuaternionGetMatrixUnit
+ret: void
+arg: rs_matrix4x4* m, "resulting matrix"
+arg: const rs_quaternion* q, "normalized quaternion"
+summary:
+description:
+ Computes rotation matrix from the normalized quaternion
+inline:
+ float xx = q->x * q->x;
+ float xy = q->x * q->y;
+ float xz = q->x * q->z;
+ float xw = q->x * q->w;
+ float yy = q->y * q->y;
+ float yz = q->y * q->z;
+ float yw = q->y * q->w;
+ float zz = q->z * q->z;
+ float zw = q->z * q->w;
+
+ m->m[0]  = 1.0f - 2.0f * ( yy + zz );
+ m->m[4]  =        2.0f * ( xy - zw );
+ m->m[8]  =        2.0f * ( xz + yw );
+ m->m[1]  =        2.0f * ( xy + zw );
+ m->m[5]  = 1.0f - 2.0f * ( xx + zz );
+ m->m[9]  =        2.0f * ( yz - xw );
+ m->m[2]  =        2.0f * ( xz - yw );
+ m->m[6]  =        2.0f * ( yz + xw );
+ m->m[10] = 1.0f - 2.0f * ( xx + yy );
+ m->m[3]  = m->m[7] = m->m[11] = m->m[12] = m->m[13] = m->m[14] = 0.0f;
+ m->m[15] = 1.0f;
+test: none
+end:
+
+function: rsQuaternionLoadRotateUnit
+ret: void
+arg: rs_quaternion* q, "quaternion to set"
+arg: float rot, "rot angle to rotate by"
+arg: float x, "component of a vector"
+arg: float y, "component of a vector"
+arg: float z, "component of a vector"
+summary:
+description:
+ Loads a quaternion that represents a rotation about an arbitrary unit vector
+inline:
+ rot *= (float)(M_PI / 180.0f) * 0.5f;
+ float c = cos(rot);
+ float s = sin(rot);
+
+ q->w = c;
+ q->x = x * s;
+ q->y = y * s;
+ q->z = z * s;
+test: none
+end:
+
+function: rsQuaternionSet
+ret: void
+arg: rs_quaternion* q, "destination quaternion"
+arg: float w, "component"
+arg: float x, "component"
+arg: float y, "component"
+arg: float z, "component"
+summary:
+description:
+ Set the quaternion from components or from another quaternion.
+inline:
+ q->w = w;
+ q->x = x;
+ q->y = y;
+ q->z = z;
+test: none
+end:
+
+function: rsQuaternionSet
+ret: void
+arg: rs_quaternion* q
+arg: const rs_quaternion* rhs, "source quaternion"
+inline:
+ q->w = rhs->w;
+ q->x = rhs->x;
+ q->y = rhs->y;
+ q->z = rhs->z;
+test: none
+end:
+
+# NOTE: The following inline definitions depend on each other.  The order must be preserved
+# for the compilation to work.
+
+function: rsQuaternionLoadRotate
+ret: void
+arg: rs_quaternion* q, "quaternion to set"
+arg: float rot, "angle to rotate by"
+arg: float x, "component of a vector"
+arg: float y, "component of a vector"
+arg: float z, "component of a vector"
+summary:
+description:
+ Loads a quaternion that represents a rotation about an arbitrary vector
+ (doesn't have to be unit)
+inline:
+ const float len = x*x + y*y + z*z;
+ if (len != 1) {
+     const float recipLen = 1.f / sqrt(len);
+     x *= recipLen;
+     y *= recipLen;
+     z *= recipLen;
+ }
+ rsQuaternionLoadRotateUnit(q, rot, x, y, z);
+test: none
+end:
+
+function: rsQuaternionNormalize
+ret: void
+arg: rs_quaternion* q, "quaternion to normalize"
+summary:
+description:
+ Normalizes the quaternion
+inline:
+ const float len = rsQuaternionDot(q, q);
+ if (len != 1) {
+     const float recipLen = 1.f / sqrt(len);
+     q->w *= recipLen;
+     q->x *= recipLen;
+     q->y *= recipLen;
+     q->z *= recipLen;
+ }
+test: none
+end:
+
+function: rsQuaternionMultiply
+ret: void
+arg: rs_quaternion* q, "destination quaternion"
+arg: float s, "scalar"
+summary:
+description:
+ Multiply quaternion by a scalar or another quaternion
+inline:
+ q->w *= s;
+ q->x *= s;
+ q->y *= s;
+ q->z *= s;
+test: none
+end:
+
+function: rsQuaternionMultiply
+ret: void
+arg: rs_quaternion* q
+arg: const rs_quaternion* rhs, "right hand side quaternion to multiply by"
+inline:
+ rs_quaternion qtmp;
+ rsQuaternionSet(&qtmp, q);
+
+ q->w = qtmp.w*rhs->w - qtmp.x*rhs->x - qtmp.y*rhs->y - qtmp.z*rhs->z;
+ q->x = qtmp.w*rhs->x + qtmp.x*rhs->w + qtmp.y*rhs->z - qtmp.z*rhs->y;
+ q->y = qtmp.w*rhs->y + qtmp.y*rhs->w + qtmp.z*rhs->x - qtmp.x*rhs->z;
+ q->z = qtmp.w*rhs->z + qtmp.z*rhs->w + qtmp.x*rhs->y - qtmp.y*rhs->x;
+ rsQuaternionNormalize(q);
+test: none
+end:
+
+function: rsQuaternionSlerp
+ret: void
+arg: rs_quaternion* q, "result quaternion from interpolation"
+arg: const rs_quaternion* q0, "first param"
+arg: const rs_quaternion* q1, "second param"
+arg: float t, "how much to interpolate by"
+summary:
+description:
+ Performs spherical linear interpolation between two quaternions
+inline:
+ if (t <= 0.0f) {
+     rsQuaternionSet(q, q0);
+     return;
+ }
+ if (t >= 1.0f) {
+     rsQuaternionSet(q, q1);
+     return;
+ }
+
+ rs_quaternion tempq0, tempq1;
+ rsQuaternionSet(&tempq0, q0);
+ rsQuaternionSet(&tempq1, q1);
+
+ float angle = rsQuaternionDot(q0, q1);
+ if (angle < 0) {
+     rsQuaternionMultiply(&tempq0, -1.0f);
+     angle *= -1.0f;
+ }
+
+ float scale, invScale;
+ if (angle + 1.0f > 0.05f) {
+     if (1.0f - angle >= 0.05f) {
+         float theta = acos(angle);
+         float invSinTheta = 1.0f / sin(theta);
+         scale = sin(theta * (1.0f - t)) * invSinTheta;
+         invScale = sin(theta * t) * invSinTheta;
+     } else {
+         scale = 1.0f - t;
+         invScale = t;
+     }
+ } else {
+     rsQuaternionSet(&tempq1, tempq0.z, -tempq0.y, tempq0.x, -tempq0.w);
+     scale = sin(M_PI * (0.5f - t));
+     invScale = sin(M_PI * t);
+ }
+
+ rsQuaternionSet(q, tempq0.w*scale + tempq1.w*invScale, tempq0.x*scale + tempq1.x*invScale,
+                     tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
+test: none
+end:
diff --git a/api/rs_sampler.spec b/api/rs_sampler.spec
new file mode 100644
index 0000000..35ab612
--- /dev/null
+++ b/api/rs_sampler.spec
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+
+header:
+summary: Sampler routines
+description:
+end:
+
+function: rsSamplerGetAnisotropy
+version: 16
+ret: float, "anisotropy"
+arg: rs_sampler s, "sampler to query"
+summary:
+description:
+  Get sampler anisotropy
+test: none
+end:
+
+function: rsSamplerGetMagnification
+version: 16
+ret: rs_sampler_value, "magnification value"
+arg: rs_sampler s, "sampler to query"
+summary:
+description:
+ Get sampler magnification value
+test: none
+end:
+
+function: rsSamplerGetMinification
+version: 16
+ret: rs_sampler_value, "minification value"
+arg: rs_sampler s, "sampler to query"
+summary:
+description:
+ Get sampler minification value
+test: none
+end:
+
+function: rsSamplerGetWrapS
+version: 16
+ret: rs_sampler_value, "wrap S value"
+arg: rs_sampler s, "sampler to query"
+summary:
+description:
+ Get sampler wrap S value
+test: none
+end:
+
+function: rsSamplerGetWrapT
+version: 16
+ret: rs_sampler_value, "wrap T value"
+arg: rs_sampler s, "sampler to query"
+summary:
+description:
+ Get sampler wrap T value
+test: none
+end:
diff --git a/api/rs_time.spec b/api/rs_time.spec
new file mode 100644
index 0000000..8011393
--- /dev/null
+++ b/api/rs_time.spec
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+
+header:
+summary: RenderScript time routines
+description:
+ This file contains RenderScript functions relating to time and date manipulation.
+end:
+
+type: rs_time_t
+size: 32
+simple: int
+summary: Seconds since January 1, 1970
+description:
+ Calendar time interpreted as seconds elapsed since the Epoch (00:00:00 on
+ January 1, 1970, Coordinated Universal Time (UTC)).
+end:
+
+type: rs_time_t
+size: 64
+simple: long
+end:
+
+type: rs_tm
+struct:
+field: int tm_sec, "Seconds after the minute. This ranges from 0 to 59, but possibly up to 60 for leap seconds."
+field: int tm_min, "Minutes after the hour. This ranges from 0 to 59."
+field: int tm_hour, "Hours past midnight. This ranges from 0 to 23."
+field: int tm_mday, "Day of the month. This ranges from 1 to 31."
+field: int tm_mon, "Months since January. This ranges from 0 to 11."
+field: int tm_year, "Years since 1900."
+field: int tm_wday, "Days since Sunday. This ranges from 0 to 6."
+field: int tm_yday, "Days since January 1. This ranges from 0 to 365."
+field: int tm_isdst, "Flag to indicate whether daylight saving time is in effect. The value is positive if it is in effect, zero if it is not, and negative if the information is not available."
+summary: Date and time structure
+description:
+ Data structure for broken-down time components.
+end:
+
+function: rsGetDt
+ret: float, "Time in seconds."
+summary:
+description:
+ Returns the time in seconds since this function was last called in this
+ script.
+test: none
+end:
+
+function: rsLocaltime
+ret: rs_tm*, "Pointer to broken-down time (same as input p local)."
+arg: rs_tm* local, "Broken-down time."
+arg: const rs_time_t* timer, "Input time as calendar time."
+summary:
+description:
+ Converts the time specified by p timer into broken-down time and stores it
+ in p local. This function also returns a pointer to p local. If p local
+ is NULL, this function does nothing and returns NULL.
+test: none
+end:
+
+function: rsTime
+ret: rs_time_t, "Seconds since the Epoch."
+arg: rs_time_t* timer, "Location to also store the returned calendar time."
+summary:
+description:
+ Returns the number of seconds since the Epoch (00:00:00 UTC, January 1,
+ 1970). If p timer is non-NULL, the result is also stored in the memory
+ pointed to by this variable. If an error occurs, a value of -1 is returned.
+test: none
+end:
+
+function: rsUptimeMillis
+ret: int64_t, "Uptime in milliseconds."
+summary:
+description:
+ Returns the current system clock (uptime) in milliseconds.
+test: none
+end:
+
+function: rsUptimeNanos
+ret: int64_t, "Uptime in nanoseconds."
+summary:
+description:
+ Returns the current system clock (uptime) in nanoseconds.
+test: none
+end:
diff --git a/api/rs_types.spec b/api/rs_types.spec
new file mode 100644
index 0000000..0eeac5b
--- /dev/null
+++ b/api/rs_types.spec
@@ -0,0 +1,849 @@
+#
+# 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.
+#
+
+header:
+summary: Standard RenderScript types
+description:
+  Integers:<ul>
+  <li>8 bit: char, int8_t</li>
+  <li>16 bit: short, int16_t</li>
+  <li>32 bit: int, in32_t</li>
+  <li>64 bit: long, long long, int64_t</li></ul>
+
+  Unsigned integers:<ul>
+  <li>8 bit: uchar, uint8_t</li>
+  <li>16 bit: ushort, uint16_t</li>
+  <li>32 bit: uint, uint32_t</li>
+  <li>64 bit: ulong, uint64_t</li></ul>
+
+  Floating point:<ul>
+  <li>32 bit: float</li>
+  <li>64 bit: double</li></ul>
+
+  Vectors of length 2, 3, and 4 are supported for all the types above.
+include:
+ #include "stdbool.h"
+
+ #define RS_PACKED __attribute__((packed, aligned(4)))
+ #define NULL ((void *)0)
+
+ // Opaque handle to a RenderScript object. Do not use this directly.
+ #ifndef __LP64__
+ #define _RS_HANDLE \
+ struct {\
+   const int* const p;\
+ } __attribute__((packed, aligned(4)))
+ #else
+ #define _RS_HANDLE \
+ struct {\
+   const long* const p;\
+   const long* const r;\
+   const long* const v1;\
+   const long* const v2;\
+ }
+ #endif
+end:
+
+constant: M_1_PI
+value: 0.318309886183790671537767526745028724f
+summary: 1 / pi, as a 32 bit float
+description:
+ The inverse of pi, as a 32 bit float.
+end:
+
+constant: M_2_PI
+value: 0.636619772367581343075535053490057448f
+summary: 2 / pi, as a 32 bit float
+description:
+ 2 divided by pi, as a 32 bit float.
+end:
+
+constant: M_2_PIl
+value: 0.636619772367581343075535053490057448f
+hidden:
+summary: Deprecated.  Use M_2_PI instead.
+description:
+end:
+
+constant: M_2_SQRTPI
+value: 1.128379167095512573896158903121545172f
+summary:  2 / sqrt(pi), as a 32 bit float
+description:
+ 2 divided by the square root of pi, as a 32 bit float.
+end:
+
+constant: M_E
+value: 2.718281828459045235360287471352662498f
+summary: e, as a 32 bit float
+description:
+ The number e, the base of the natural logarithm, as a 32 bit float.
+end:
+
+constant: M_LN10
+value: 2.302585092994045684017991454684364208f
+summary: log_e(10), as a 32 bit float
+description:
+ The natural logarithm of 10, as a 32 bit float.
+end:
+
+constant: M_LN2
+value: 0.693147180559945309417232121458176568f
+summary: log_e(2), as a 32 bit float
+description:
+ The natural logarithm of 2, as a 32 bit float.
+end:
+
+constant: M_LOG10E
+value: 0.434294481903251827651128918916605082f
+summary: log_10(e), as a 32 bit float
+description:
+ The logarithm base 10 of e, as a 32 bit float.
+end:
+
+constant: M_LOG2E
+value: 1.442695040888963407359924681001892137f
+summary: log_2(e), as a 32 bit float
+description:
+ The logarithm base 2 of e, as a 32 bit float.
+end:
+
+constant: M_PI
+value: 3.141592653589793238462643383279502884f
+summary: pi, as a 32 bit float
+description:
+ The constant pi, as a 32 bit float.
+end:
+
+constant: M_PI_2
+value: 1.570796326794896619231321691639751442f
+summary: pi / 2, as a 32 bit float
+description:
+ Pi divided by 2, as a 32 bit float.
+end:
+
+constant: M_PI_4
+value: 0.785398163397448309615660845819875721f
+summary: pi / 4, as a 32 bit float
+description:
+ Pi divided by 4, as a 32 bit float.
+end:
+
+constant: M_SQRT1_2
+value: 0.707106781186547524400844362104849039f
+summary: 1 / sqrt(2), as a 32 bit float
+description:
+ The inverse of the square root of 2, as a 32 bit float.
+end:
+
+constant: M_SQRT2
+value: 1.414213562373095048801688724209698079f
+summary: sqrt(2), as a 32 bit float
+description:
+ The square root of 2, as a 32 bit float.
+end:
+
+type: int8_t
+simple: char
+summary: 8 bit signed integer
+description:
+ 8 bit integer type
+end:
+
+type: int16_t
+simple: short
+summary: 16 bit signed integer
+description:
+ 16 bit integer type
+end:
+
+type: int32_t
+simple: int
+summary: 32 bit signed integer
+description:
+ 32 bit integer type
+end:
+
+type: int64_t
+version: 9 20
+simple: long long
+summary: 64 bit signed integer
+description:
+ 64 bit integer type
+end:
+
+type: int64_t
+version: 21
+simple: long
+end:
+
+type: uint8_t
+simple: unsigned char
+summary: 8 bit unsigned integer
+description:
+ 8 bit unsigned integer type
+end:
+
+type: uint16_t
+simple: unsigned short
+summary: 16 bit unsigned integer
+description:
+ 16 bit unsigned integer type
+end:
+
+type: uint32_t
+simple: unsigned int
+summary: 32 bit unsigned integer
+description:
+ 32 bit unsigned integer type
+end:
+
+type: uint64_t
+version: 9 20
+simple: unsigned long long
+summary: 64 bit unsigned integer
+description:
+ 64 bit unsigned integer type
+end:
+
+type: uint64_t
+version: 21
+simple: unsigned long
+end:
+
+type: uchar
+simple: uint8_t
+summary: 8 bit unsigned integer
+description:
+ 8 bit unsigned integer type
+end:
+
+type: ushort
+simple: uint16_t
+summary: 16 bit unsigned integer
+description:
+ 16 bit unsigned integer type
+end:
+
+type: uint
+simple: uint32_t
+summary: 32 bit unsigned integer
+description:
+ 32 bit unsigned integer type
+end:
+
+type: ulong
+simple: uint64_t
+summary: 64 bit unsigned integer
+description:
+ Typedef for unsigned long (use for 64-bit unsigned integers)
+end:
+
+type: size_t
+size: 64
+simple: uint64_t
+summary: Unsigned size type
+description:
+ Typedef for size_t
+end:
+
+type: size_t
+size: 32
+simple: uint32_t
+end:
+
+type: ssize_t
+size: 64
+simple: int64_t
+summary: Signed size type
+description:
+ Typedef for ssize_t
+end:
+
+type: ssize_t
+size: 32
+simple: int32_t
+end:
+
+type: rs_element
+simple: _RS_HANDLE
+summary: Handle to an element
+description:
+ Opaque handle to a RenderScript element.
+ See: android.renderscript.Element
+end:
+
+type: rs_type
+simple: _RS_HANDLE
+summary: Handle to a Type
+description:
+ Opaque handle to a RenderScript type.
+ See: android.renderscript.Type
+end:
+
+type: rs_allocation
+simple: _RS_HANDLE
+summary: Handle to an allocation
+description:
+ Opaque handle to a RenderScript allocation.
+ See: android.renderscript.Allocation
+end:
+
+type: rs_sampler
+simple: _RS_HANDLE
+summary: Handle to a Sampler
+description:
+ Opaque handle to a RenderScript sampler object.
+ See: android.renderscript.Sampler
+end:
+
+type: rs_script
+simple: _RS_HANDLE
+summary: Handle to a Script
+description:
+ Opaque handle to a RenderScript script object.
+ See: android.renderscript.ScriptC
+end:
+
+
+type: rs_mesh
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a Mesh
+description:
+ Opaque handle to a RenderScript mesh object.
+ See: android.renderscript.Mesh
+end:
+
+type: rs_program_fragment
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a ProgramFragment
+description:
+ Opaque handle to a RenderScript ProgramFragment object.
+ See: android.renderscript.ProgramFragment
+end:
+
+type: rs_program_vertex
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a ProgramVertex
+description:
+ Opaque handle to a RenderScript ProgramVertex object.
+ See: android.renderscript.ProgramVertex
+end:
+
+type: rs_program_raster
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a ProgramRaster
+description:
+ Opaque handle to a RenderScript ProgramRaster object.
+ See: android.renderscript.ProgramRaster
+end:
+
+type: rs_program_store
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a ProgramStore
+description:
+ Opaque handle to a RenderScript ProgramStore object.
+ See: android.renderscript.ProgramStore
+end:
+
+type: rs_font
+size: 32
+simple: _RS_HANDLE
+summary: Handle to a Font
+description:
+ Opaque handle to a RenderScript font object.
+ See: android.renderscript.Font
+end:
+
+type: float2
+simple: float __attribute__((ext_vector_type(2)))
+summary: Two 32 bit floats
+description:
+ Vector version of the basic float type.
+ Provides two float fields packed into a single 64 bit field with 64 bit alignment.
+end:
+
+type: float3
+simple: float __attribute__((ext_vector_type(3)))
+summary: Three 32 bit floats
+description:
+ Vector version of the basic float type.
+ Provides three float fields packed into a single 128 bit field with 128 bit alignment.
+end:
+
+type: float4
+simple: float __attribute__((ext_vector_type(4)))
+summary: Four 32 bit floats
+description:
+ Vector version of the basic float type.
+ Provides four float fields packed into a single 128 bit field with 128 bit alignment.
+end:
+
+
+type: double2
+simple: double __attribute__((ext_vector_type(2)))
+summary: Two 64 bit floats
+description:
+ Vector version of the basic double type. Provides two double fields packed
+ into a single 128 bit field with 128 bit alignment.
+end:
+
+type: double3
+simple: double __attribute__((ext_vector_type(3)))
+summary: Three 64 bit floats
+description:
+ Vector version of the basic double type. Provides three double fields packed
+ into a single 256 bit field with 256 bit alignment.
+end:
+
+type: double4
+simple: double __attribute__((ext_vector_type(4)))
+summary: Four 64 bit floats
+description:
+ Vector version of the basic double type. Provides four double fields packed
+ into a single 256 bit field with 256 bit alignment.
+end:
+
+
+type: uchar2
+simple: uchar __attribute__((ext_vector_type(2)))
+summary: Two 8 bit unsigned integers
+description:
+ Vector version of the basic uchar type. Provides two uchar fields packed
+ into a single 16 bit field with 16 bit alignment.
+end:
+
+type: uchar3
+simple: uchar __attribute__((ext_vector_type(3)))
+summary: Three 8 bit unsigned integers
+description:
+ Vector version of the basic uchar type. Provides three uchar fields packed
+ into a single 32 bit field with 32 bit alignment.
+end:
+
+type: uchar4
+simple: uchar __attribute__((ext_vector_type(4)))
+summary: Four 8 bit unsigned integers
+description:
+ Vector version of the basic uchar type. Provides four uchar fields packed
+ into a single 32 bit field with 32 bit alignment.
+end:
+
+
+type: ushort2
+simple: ushort __attribute__((ext_vector_type(2)))
+summary: Two 16 bit unsigned integers
+description:
+ Vector version of the basic ushort type. Provides two ushort fields packed
+ into a single 32 bit field with 32 bit alignment.
+end:
+
+type: ushort3
+simple: ushort __attribute__((ext_vector_type(3)))
+summary: Three 16 bit unsigned integers
+description:
+ Vector version of the basic ushort type. Provides three ushort fields packed
+ into a single 64 bit field with 64 bit alignment.
+end:
+
+type: ushort4
+simple: ushort __attribute__((ext_vector_type(4)))
+summary: Four 16 bit unsigned integers
+description:
+ Vector version of the basic ushort type. Provides four ushort fields packed
+ into a single 64 bit field with 64 bit alignment.
+end:
+
+
+type: uint2
+simple: uint __attribute__((ext_vector_type(2)))
+summary: Two 32 bit unsigned integers
+description:
+ Vector version of the basic uint type. Provides two uint fields packed into a
+ single 64 bit field with 64 bit alignment.
+end:
+
+type: uint3
+simple: uint __attribute__((ext_vector_type(3)))
+summary: Three 32 bit unsigned integers
+description:
+ Vector version of the basic uint type. Provides three uint fields packed into
+ a single 128 bit field with 128 bit alignment.
+end:
+
+type: uint4
+simple: uint __attribute__((ext_vector_type(4)))
+summary: Four 32 bit unsigned integers
+description:
+ Vector version of the basic uint type. Provides four uint fields packed into
+ a single 128 bit field with 128 bit alignment.
+end:
+
+
+type: ulong2
+simple: ulong __attribute__((ext_vector_type(2)))
+summary: Two 64 bit unsigned integers
+description:
+ Vector version of the basic ulong type. Provides two ulong fields packed into
+ a single 128 bit field with 128 bit alignment.
+end:
+
+type: ulong3
+simple: ulong __attribute__((ext_vector_type(3)))
+summary: Three 64 bit unsigned integers
+description:
+ Vector version of the basic ulong type. Provides three ulong fields packed
+ into a single 256 bit field with 256 bit alignment.
+end:
+
+type: ulong4
+simple: ulong __attribute__((ext_vector_type(4)))
+summary: Four 64 bit unsigned integers
+description:
+ Vector version of the basic ulong type. Provides four ulong fields packed
+ into a single 256 bit field with 256 bit alignment.
+end:
+
+
+type: char2
+simple: char __attribute__((ext_vector_type(2)))
+summary: Two 8 bit signed integers
+description:
+ Vector version of the basic char type. Provides two char fields packed into a
+ single 16 bit field with 16 bit alignment.
+end:
+
+type: char3
+simple: char __attribute__((ext_vector_type(3)))
+summary: Three 8 bit signed integers
+description:
+ Vector version of the basic char type. Provides three char fields packed into
+ a single 32 bit field with 32 bit alignment.
+end:
+
+type: char4
+simple: char __attribute__((ext_vector_type(4)))
+summary: Four 8 bit signed integers
+description:
+ Vector version of the basic char type. Provides four char fields packed into
+ a single 32 bit field with 32 bit alignment.
+end:
+
+type: short2
+simple: short __attribute__((ext_vector_type(2)))
+summary: Two 16 bit signed integers
+description:
+ Vector version of the basic short type. Provides two short fields packed into
+ a single 32 bit field with 32 bit alignment.
+end:
+
+type: short3
+simple: short __attribute__((ext_vector_type(3)))
+summary: Three 16 bit signed integers
+description:
+ Vector version of the basic short type. Provides three short fields packed
+ into a single 64 bit field with 64 bit alignment.
+end:
+
+type: short4
+simple: short __attribute__((ext_vector_type(4)))
+summary: Four 16 bit signed integers
+description:
+ Vector version of the basic short type. Provides four short fields packed
+ into a single 64 bit field with 64 bit alignment.
+end:
+
+
+type: int2
+simple: int __attribute__((ext_vector_type(2)))
+summary: Two 32 bit signed integers
+description:
+ Vector version of the basic int type. Provides two int fields packed into a
+ single 64 bit field with 64 bit alignment.
+end:
+
+type: int3
+simple: int __attribute__((ext_vector_type(3)))
+summary: Three 32 bit signed integers
+description:
+ Vector version of the basic int type. Provides three int fields packed into a
+ single 128 bit field with 128 bit alignment.
+end:
+
+type: int4
+simple: int __attribute__((ext_vector_type(4)))
+summary: Four 32 bit signed integers
+description:
+ Vector version of the basic int type. Provides two four fields packed into a
+ single 128 bit field with 128 bit alignment.
+end:
+
+
+type: long2
+simple: long __attribute__((ext_vector_type(2)))
+summary: Two 64 bit signed integers
+description:
+ Vector version of the basic long type. Provides two long fields packed into a
+ single 128 bit field with 128 bit alignment.
+end:
+
+type: long3
+simple: long __attribute__((ext_vector_type(3)))
+summary: Three 64 bit signed integers
+description:
+ Vector version of the basic long type. Provides three long fields packed into
+ a single 256 bit field with 256 bit alignment.
+end:
+
+type: long4
+simple: long __attribute__((ext_vector_type(4)))
+summary: Four 64 bit signed integers
+description:
+ Vector version of the basic long type. Provides four long fields packed into
+ a single 256 bit field with 256 bit alignment.
+end:
+
+type: rs_matrix4x4
+struct:
+field: float m[16]
+summary: 4x4 matrix of 32 bit floats
+description:
+ Native holder for RS matrix.  Elements are stored in the array at the
+ location [row*4 + col]
+end:
+
+type: rs_matrix3x3
+struct:
+field: float m[9]
+summary: 3x3 matrix of 32 bit floats
+description:
+ Native holder for RS matrix.  Elements are stored in the array at the
+ location [row*3 + col]
+end:
+
+type: rs_matrix2x2
+struct:
+field: float m[4]
+summary: 2x2 matrix of 32 bit floats
+description:
+ Native holder for RS matrix.  Elements are stored in the array at the
+ location [row*2 + col]
+end:
+
+type: rs_quaternion
+simple: float4
+summary: Quarternion
+description:
+ Quaternion type for use with the quaternion functions
+end:
+
+type: rs_allocation_cubemap_face
+version: 14
+enum:
+value: RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X = 0
+value: RS_ALLOCATION_CUBEMAP_FACE_NEGATIVE_X = 1
+value: RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_Y = 2
+value: RS_ALLOCATION_CUBEMAP_FACE_NEGATIVE_Y = 3
+value: RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_Z = 4
+value: RS_ALLOCATION_CUBEMAP_FACE_NEGATIVE_Z = 5
+summary: Enum for selecting cube map faces
+description:
+end:
+
+type: rs_allocation_usage_type
+version: 14
+enum:
+value: RS_ALLOCATION_USAGE_SCRIPT = 0x0001
+value: RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, "Deprecated."
+value: RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, "Deprecated."
+value: RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, "Deprecated."
+value: RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010, "Deprecated."
+summary: Bitfield to specify the usage types for an allocation
+description:
+ These values are ORed together to specify which usages or memory spaces are
+ relevant to an allocation or an operation on an allocation.
+end:
+
+type: rs_primitive
+version: 16
+size: 32
+enum:
+value: RS_PRIMITIVE_POINT = 0, "Vertex data will be rendered as a series of points"
+value: RS_PRIMITIVE_LINE = 1, "Vertex pairs will be rendered as lines"
+value: RS_PRIMITIVE_LINE_STRIP = 2, "Vertex data will be rendered as a connected line strip"
+value: RS_PRIMITIVE_TRIANGLE = 3, "Vertices will be rendered as individual triangles"
+value: RS_PRIMITIVE_TRIANGLE_STRIP = 4, "Vertices will be rendered as a connected triangle strip defined by the first three vertices with each additional triangle defined by a new vertex"
+value: RS_PRIMITIVE_TRIANGLE_FAN = 5, "Vertices will be rendered as a sequence of triangles that all share first vertex as the origin"
+value: RS_PRIMITIVE_INVALID = 100, "Invalid primitive"
+summary: How to intepret mesh vertex data
+description:
+ Describes the way mesh vertex data is interpreted when rendering
+end:
+
+type: rs_data_type
+version: 16
+enum:
+value: RS_TYPE_NONE             = 0
+value: RS_TYPE_FLOAT_32         = 2
+value: RS_TYPE_FLOAT_64         = 3
+value: RS_TYPE_SIGNED_8         = 4
+value: RS_TYPE_SIGNED_16        = 5
+value: RS_TYPE_SIGNED_32        = 6
+value: RS_TYPE_SIGNED_64        = 7
+value: RS_TYPE_UNSIGNED_8       = 8
+value: RS_TYPE_UNSIGNED_16      = 9
+value: RS_TYPE_UNSIGNED_32      = 10
+value: RS_TYPE_UNSIGNED_64      = 11
+value: RS_TYPE_BOOLEAN          = 12
+value: RS_TYPE_UNSIGNED_5_6_5   = 13
+value: RS_TYPE_UNSIGNED_5_5_5_1 = 14
+value: RS_TYPE_UNSIGNED_4_4_4_4 = 15
+value: RS_TYPE_MATRIX_4X4       = 16
+value: RS_TYPE_MATRIX_3X3       = 17
+value: RS_TYPE_MATRIX_2X2       = 18
+value: RS_TYPE_ELEMENT          = 1000
+value: RS_TYPE_TYPE             = 1001
+value: RS_TYPE_ALLOCATION       = 1002
+value: RS_TYPE_SAMPLER          = 1003
+value: RS_TYPE_SCRIPT           = 1004
+value: RS_TYPE_MESH             = 1005
+value: RS_TYPE_PROGRAM_FRAGMENT = 1006
+value: RS_TYPE_PROGRAM_VERTEX   = 1007
+value: RS_TYPE_PROGRAM_RASTER   = 1008
+value: RS_TYPE_PROGRAM_STORE    = 1009
+value: RS_TYPE_FONT             = 1010
+value: RS_TYPE_INVALID          = 10000
+summary: Element data types
+description:
+ DataType represents the basic type information for a basic element.  The
+ naming convention follows.  For numeric types it is FLOAT,
+ SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ size of the data.  BOOLEAN is a true / false (1,0)
+ represented in an 8 bit container.  The UNSIGNED variants
+ with multiple bit definitions are for packed graphical data
+ formats and represent vectors with per vector member sizes
+ which are treated as a single unit for packing and alignment
+ purposes.
+
+ MATRIX the three matrix types contain FLOAT_32 elements and are treated
+ as 32 bits for alignment purposes.
+
+ RS_* objects.  32 bit opaque handles.
+end:
+
+type: rs_data_kind
+version: 16
+enum:
+value: RS_KIND_USER         = 0
+value: RS_KIND_PIXEL_L      = 7
+value: RS_KIND_PIXEL_A      = 8
+value: RS_KIND_PIXEL_LA     = 9
+value: RS_KIND_PIXEL_RGB    = 10
+value: RS_KIND_PIXEL_RGBA   = 11
+value: RS_KIND_PIXEL_DEPTH  = 12
+value: RS_KIND_PIXEL_YUV    = 13
+value: RS_KIND_INVALID      = 100
+summary: Element data kind
+description:
+ The special interpretation of the data if required.  This is primarly
+ useful for graphical data.  USER indicates no special interpretation is
+ expected.  PIXEL is used in conjunction with the standard data types for
+ representing texture formats.
+end:
+
+type: rs_depth_func
+version: 16
+size: 32
+enum:
+value: RS_DEPTH_FUNC_ALWAYS        = 0, "Always drawn"
+value: RS_DEPTH_FUNC_LESS          = 1, "Drawn if the incoming depth value is less than that in the depth buffer"
+value: RS_DEPTH_FUNC_LEQUAL        = 2, "Drawn if the incoming depth value is less or equal to that in the depth buffer"
+value: RS_DEPTH_FUNC_GREATER       = 3, "Drawn if the incoming depth value is greater than that in the depth buffer"
+value: RS_DEPTH_FUNC_GEQUAL        = 4, "Drawn if the incoming depth value is greater or equal to that in the depth buffer"
+value: RS_DEPTH_FUNC_EQUAL         = 5, "Drawn if the incoming depth value is equal to that in the depth buffer"
+value: RS_DEPTH_FUNC_NOTEQUAL      = 6, "Drawn if the incoming depth value is not equal to that in the depth buffer"
+value: RS_DEPTH_FUNC_INVALID       = 100, "Invalid depth function"
+summary: Depth function
+description:
+ Specifies conditional drawing depending on the comparison of the incoming
+ depth to that found in the depth buffer.
+end:
+
+type: rs_blend_src_func
+version: 16
+size: 32
+enum:
+value: RS_BLEND_SRC_ZERO                   = 0
+value: RS_BLEND_SRC_ONE                    = 1
+value: RS_BLEND_SRC_DST_COLOR              = 2
+value: RS_BLEND_SRC_ONE_MINUS_DST_COLOR    = 3
+value: RS_BLEND_SRC_SRC_ALPHA              = 4
+value: RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA    = 5
+value: RS_BLEND_SRC_DST_ALPHA              = 6
+value: RS_BLEND_SRC_ONE_MINUS_DST_ALPHA    = 7
+value: RS_BLEND_SRC_SRC_ALPHA_SATURATE     = 8
+value: RS_BLEND_SRC_INVALID                = 100
+summary: Blend source function
+description:
+end:
+
+type: rs_blend_dst_func
+version: 16
+size: 32
+enum:
+value: RS_BLEND_DST_ZERO                   = 0
+value: RS_BLEND_DST_ONE                    = 1
+value: RS_BLEND_DST_SRC_COLOR              = 2
+value: RS_BLEND_DST_ONE_MINUS_SRC_COLOR    = 3
+value: RS_BLEND_DST_SRC_ALPHA              = 4
+value: RS_BLEND_DST_ONE_MINUS_SRC_ALPHA    = 5
+value: RS_BLEND_DST_DST_ALPHA              = 6
+value: RS_BLEND_DST_ONE_MINUS_DST_ALPHA    = 7
+value: RS_BLEND_DST_INVALID                = 100
+summary: Blend destination function
+description:
+end:
+
+type: rs_cull_mode
+version: 16
+size: 32
+enum:
+value: RS_CULL_BACK     = 0
+value: RS_CULL_FRONT    = 1
+value: RS_CULL_NONE     = 2
+value: RS_CULL_INVALID  = 100
+summary: Culling mode
+description:
+end:
+
+type: rs_sampler_value
+version: 16
+enum:
+value: RS_SAMPLER_NEAREST              = 0
+value: RS_SAMPLER_LINEAR               = 1
+value: RS_SAMPLER_LINEAR_MIP_LINEAR    = 2
+value: RS_SAMPLER_WRAP                 = 3
+value: RS_SAMPLER_CLAMP                = 4
+value: RS_SAMPLER_LINEAR_MIP_NEAREST   = 5
+value: RS_SAMPLER_MIRRORED_REPEAT      = 6
+value: RS_SAMPLER_INVALID              = 100
+summary: Sampler wrap T value
+description:
+end: