Kotlin methods return binary data in ByteBuffers.

This removes the need for handwritten versions of getMappedRange and
getConstMappedRange. Having said that, we might want to supply a helper
extension for clients, that can supply the size parameter and
automatically call the const or non-const version appropriately.

Bug: 330293683
Change-Id: I57282735cb65cb719c98cf20b37621714bd06d4a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/191621
Commit-Queue: Jim Blackler <jimblackler@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index eb5d614..64d11af 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -813,9 +813,6 @@
         return True
 
     def include_method(method):
-        if method.return_type.name.get() in ['void *', 'void const *']:
-            # All methods that return binary data are handwritten.
-            return False
         if method.return_type.category == 'function pointer':
             # Kotlin doesn't support returning functions.
             return False
diff --git a/generator/templates/art/api_kotlin_object.kt b/generator/templates/art/api_kotlin_object.kt
index 021ab3b..fe72b9e 100644
--- a/generator/templates/art/api_kotlin_object.kt
+++ b/generator/templates/art/api_kotlin_object.kt
@@ -25,6 +25,8 @@
 //* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 //* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 package {{ kotlin_package }}
+
+import java.nio.ByteBuffer
 {% from 'art/api_kotlin_types.kt' import kotlin_type_declaration, kotlin_definition with context %}
 
 class {{ obj.name.CamelCase() }}(val handle: Long): AutoCloseable {
diff --git a/generator/templates/art/api_kotlin_types.kt b/generator/templates/art/api_kotlin_types.kt
index 14f8103..d37e0ad 100644
--- a/generator/templates/art/api_kotlin_types.kt
+++ b/generator/templates/art/api_kotlin_types.kt
@@ -103,6 +103,8 @@
         {% endif %}
     {%- elif type.name.get() == 'void' %}
         {{- 'Long' if arg.annotation == '*' else 'Unit' }}
+    {%- elif type.name.get() in ['void *', 'void const *'] %}
+        ByteBuffer
     {%- else -%}
         {{ unreachable_code() }}
     {%- endif %}
diff --git a/generator/templates/art/methods.cpp b/generator/templates/art/methods.cpp
index 79ca066..4294eba 100644
--- a/generator/templates/art/methods.cpp
+++ b/generator/templates/art/methods.cpp
@@ -40,6 +40,27 @@
     jobject callback;
 };
 
+jobject toByteBuffer(JNIEnv *env, const void* address, jlong size) {
+    if (!address) {
+        return nullptr;
+    }
+    jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer");
+
+    //* Dawn always uses little endian format, so we pre-convert for the client's convenience.
+    jclass byteOrderClass = env->FindClass("java/nio/ByteOrder");
+    jobject littleEndian = env->NewGlobalRef(env->GetStaticObjectField(
+            byteOrderClass, env->GetStaticFieldID(byteOrderClass, "LITTLE_ENDIAN",
+                                                  "Ljava/nio/ByteOrder;")));
+
+    jobject byteBuffer = env->NewDirectByteBuffer(const_cast<void *>(address), size);
+
+    env->CallObjectMethod(
+            byteBuffer, env->GetMethodID(byteBufferClass, "order",
+                                         "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"),
+            littleEndian);
+    return byteBuffer;
+}
+
 {% macro render_method(method, object) %}
     //*  A JNI-external method is built with the JNI signature expected to match the host Kotlin.
     DEFAULT extern "C"
@@ -271,6 +292,8 @@
         jclass returnClass = env->FindClass("{{ jni_name(method.return_type) }}");
         auto constructor = env->GetMethodID(returnClass, "<init>", "(J)V");
         return env->NewObject(returnClass, constructor, reinterpret_cast<jlong>(result));
+    {% elif method.return_type.name.get() in ['void const *', 'void *'] %}
+        return toByteBuffer(env, result, size);
     {% elif method.return_type.name.get() != 'void' %}
         return result;  //* Primitives are implicitly converted by JNI.
     {% endif %}
diff --git a/src/dawn/dawn_kotlin.json b/src/dawn/dawn_kotlin.json
index 1e9dfa0..d205550 100644
--- a/src/dawn/dawn_kotlin.json
+++ b/src/dawn/dawn_kotlin.json
@@ -39,6 +39,8 @@
         "size_t": "jlong",
         "uint32_t": "jint",
         "uint64_t": "jlong",
+        "void *": "jobject",
+        "void const *": "jobject",
         "void": "void"
     }
 }