Driver support for creating allocations from a Script

Bug: 23535985

Implement functions rsCreateElement, rsCreateType and rsCreateAllocation
in libRSDriver to allow creation of Allocations from a Script.

In its current state, the RS objects returned from these functions are
guaranteed to leak due to incorrect handling of their reference counts.
They'll be fixed in a follow-up CL.

Change-Id: I9bb7c72a8dd3cd1aac2de3bad92276c3af662484
diff --git a/driver/rsdRuntimeStubs.cpp b/driver/rsdRuntimeStubs.cpp
index 718d611..9c9fc37 100644
--- a/driver/rsdRuntimeStubs.cpp
+++ b/driver/rsdRuntimeStubs.cpp
@@ -15,11 +15,13 @@
  */
 
 #include "rsContext.h"
+#include "rsElement.h"
 #include "rsScriptC.h"
 #include "rsMatrix4x4.h"
 #include "rsMatrix3x3.h"
 #include "rsMatrix2x2.h"
 #include "rsRuntime.h"
+#include "rsType.h"
 
 #include "rsdCore.h"
 #include "rsdBcc.h"
@@ -99,6 +101,14 @@
     // Empty to avoid conflicting definitions with RsAllocationCubemapFace
 } rs_allocation_cubemap_face;
 
+typedef enum {
+    // Empty to avoid conflicting definitions with RsYuvFormat
+} rs_yuv_format;
+
+typedef enum {
+    // Empty to avoid conflicting definitions with RsAllocationMipmapControl
+} rs_allocation_mipmap_control;
+
 typedef struct { unsigned int val; } rs_allocation_usage_type;
 
 typedef struct {
@@ -203,6 +213,187 @@
                              srcXoff, srcYoff, srcMip, srcFace);
 }
 
+static android::renderscript::rs_element CreateElement(RsDataType dt,
+                                                       RsDataKind dk,
+                                                       bool isNormalized,
+                                                       uint32_t vecSize) {
+    Context *rsc = RsdCpuReference::getTlsContext();
+
+    // No need for validation here.  The rsCreateElement overload below is not
+    // exposed to the Script.  The Element-creation APIs call this function in a
+    // consistent manner and rsComponent.cpp asserts on any inconsistency.
+    Element *element = (Element *) rsrElementCreate(rsc, dt, dk, isNormalized,
+                                                    vecSize);
+    android::renderscript::rs_element obj = {};
+    if (element == nullptr)
+        return obj;
+    element->callUpdateCacheObject(rsc, &obj);
+    return obj;
+}
+
+static android::renderscript::rs_type CreateType(RsElement element,
+                                                 uint32_t dimX, uint32_t dimY,
+                                                 uint32_t dimZ, bool mipmaps,
+                                                 bool faces,
+                                                 uint32_t yuv_format) {
+
+    Context *rsc = RsdCpuReference::getTlsContext();
+    android::renderscript::rs_type obj = {};
+
+    if (element == nullptr) {
+        ALOGE("rs_type creation error: Invalid element");
+        return obj;
+    }
+
+    // validate yuv_format
+    RsYuvFormat yuv = (RsYuvFormat) yuv_format;
+    if (yuv != RS_YUV_NONE &&
+        yuv != RS_YUV_YV12 &&
+        yuv != RS_YUV_NV21 &&
+        yuv != RS_YUV_420_888) {
+
+        ALOGE("rs_type creation error: Invalid yuv_format %d\n", yuv_format);
+        return obj;
+    }
+
+    // validate consistency of shape parameters
+    if (dimZ > 0) {
+        if (dimX < 1 || dimY < 1) {
+            ALOGE("rs_type creation error: Both X and Y dimension required "
+                  "when Z is present.");
+            return obj;
+        }
+        if (mipmaps) {
+            ALOGE("rs_type creation error: mipmap control requires 2D types");
+            return obj;
+        }
+        if (faces) {
+            ALOGE("rs_type creation error: Cube maps require 2D types");
+            return obj;
+        }
+    }
+    if (dimY > 0 && dimX < 1) {
+        ALOGE("rs_type creation error: X dimension required when Y is "
+              "present.");
+        return obj;
+    }
+    if (mipmaps && dimY < 1) {
+        ALOGE("rs_type creation error: mipmap control require 2D Types.");
+        return obj;
+    }
+    if (faces && dimY < 1) {
+        ALOGE("rs_type creation error: Cube maps require 2D Types.");
+        return obj;
+    }
+    if (yuv_format != RS_YUV_NONE) {
+        if (dimZ != 0 || dimY == 0 || faces || mipmaps) {
+            ALOGE("rs_type creation error: YUV only supports basic 2D.");
+            return obj;
+        }
+    }
+
+    Type *type = (Type *) rsrTypeCreate(rsc, element, dimX, dimY, dimZ, mipmaps,
+                                        faces, yuv_format);
+    if (type == nullptr)
+        return obj;
+    type->callUpdateCacheObject(rsc, &obj);
+    return obj;
+}
+
+static android::renderscript::rs_allocation CreateAllocation(
+        RsType type, RsAllocationMipmapControl mipmaps, uint32_t usages,
+        void *ptr) {
+
+    Context *rsc = RsdCpuReference::getTlsContext();
+    android::renderscript::rs_allocation obj = {};
+
+    if (type == nullptr) {
+        ALOGE("rs_allocation creation error: Invalid type");
+        return obj;
+    }
+
+    uint32_t validUsages = RS_ALLOCATION_USAGE_SCRIPT | \
+                           RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
+    if (usages & ~validUsages) {
+        ALOGE("rs_allocation creation error: Invalid usage flag");
+        return obj;
+    }
+
+    Allocation *alloc = (Allocation *) rsrAllocationCreateTyped(rsc, type,
+                                                                mipmaps, usages,
+                                                                (uintptr_t) ptr);
+    if (alloc == nullptr)
+        return obj;
+    alloc->callUpdateCacheObject(rsc, &obj);
+
+    return obj;
+}
+
+// Define rsCreateElement, rsCreateType and rsCreateAllocation entry points
+// differently for 32-bit x86 and Mips.  The definitions for ARM32 and all
+// 64-bit architectures is further below.
+#if defined(__i386__) || (defined(__mips__) && __mips==32)
+
+// The calling convention for the driver on 32-bit x86 and Mips returns
+// rs_element etc. as a stack-return parameter.  The Script uses ARM32 calling
+// conventions that return the structs in a register.  To match this convention,
+// emulate the return value using a pointer.
+Element *rsCreateElement(int32_t dt, int32_t dk, bool isNormalized,
+                         uint32_t vecSize) {
+
+    android::renderscript::rs_element obj = CreateElement((RsDataType) dt,
+                                                          (RsDataKind) dk,
+                                                          isNormalized,
+                                                          vecSize);
+    return (Element *) obj.p;
+}
+
+Type *rsCreateType(::rs_element element, uint32_t dimX, uint32_t dimY,
+                   uint32_t dimZ, bool mipmaps, bool faces,
+                   rs_yuv_format yuv_format) {
+    android::renderscript::rs_type obj = CreateType((RsElement) element.p, dimX,
+                                                    dimY, dimZ, mipmaps, faces,
+                                                    (RsYuvFormat) yuv_format);
+    return (Type *) obj.p;
+}
+
+Allocation *rsCreateAllocation(::rs_type type,
+                               rs_allocation_mipmap_control mipmaps,
+                               uint32_t usages, void *ptr) {
+
+    android::renderscript::rs_allocation obj;
+    obj = CreateAllocation((RsType) type.p, (RsAllocationMipmapControl) mipmaps,
+                           usages, ptr);
+    return (Allocation *) obj.p;
+}
+
+#else
+android::renderscript::rs_element rsCreateElement(int32_t dt, int32_t dk,
+                                                  bool isNormalized,
+                                                  uint32_t vecSize) {
+
+    return CreateElement((RsDataType) dt, (RsDataKind) dk, isNormalized,
+                         vecSize);
+}
+
+android::renderscript::rs_type rsCreateType(::rs_element element, uint32_t dimX,
+                                            uint32_t dimY, uint32_t dimZ,
+                                            bool mipmaps, bool faces,
+                                            rs_yuv_format yuv_format) {
+    return CreateType((RsElement) element.p, dimX, dimY, dimZ, mipmaps, faces,
+                      yuv_format);
+}
+
+android::renderscript::rs_allocation rsCreateAllocation(
+        ::rs_type type, rs_allocation_mipmap_control mipmaps, uint32_t usages,
+        void *ptr) {
+
+    return CreateAllocation((RsType) type.p,
+                            (RsAllocationMipmapControl) mipmaps,
+                            usages, ptr);
+}
+#endif
+
 //////////////////////////////////////////////////////////////////////////////
 // Object routines
 //////////////////////////////////////////////////////////////////////////////
diff --git a/rsDefines.h b/rsDefines.h
index 6e38fdb..4dadca6 100644
--- a/rsDefines.h
+++ b/rsDefines.h
@@ -167,6 +167,13 @@
     RS_KIND_INVALID = 100,
 };
 
+enum RsYuvFormat {
+    RS_YUV_NONE    = 0,
+    RS_YUV_YV12    = 0x32315659, // HAL_PIXEL_FORMAT_YV12 in system/graphics.h
+    RS_YUV_NV21    = 0x11,       // HAL_PIXEL_FORMAT_YCrCb_420_SP
+    RS_YUV_420_888 = 0x23,       // HAL_PIXEL_FORMAT_YCbCr_420_888
+};
+
 enum RsSamplerParam {
     RS_SAMPLER_MIN_FILTER,
     RS_SAMPLER_MAG_FILTER,
diff --git a/rsRuntime.h b/rsRuntime.h
index 9bc05b3..7baba08 100644
--- a/rsRuntime.h
+++ b/rsRuntime.h
@@ -163,6 +163,16 @@
                 uint32_t usrBytes,
                 const RsScriptCall *call);
 
+RsElement rsrElementCreate(Context *rsc, RsDataType dt, RsDataKind dk,
+                           bool norm, uint32_t vecSize);
+
+RsType rsrTypeCreate(Context *, const RsElement element, uint32_t dimX,
+                     uint32_t dimY, uint32_t dimZ, bool mipmaps, bool faces,
+                     uint32_t yuv);
+
+RsAllocation rsrAllocationCreateTyped(Context *, const RsType type,
+                                      RsAllocationMipmapControl mipmaps,
+                                      uint32_t usages, uintptr_t ptr);
 
 //////////////////////////////////////////////////////////////////////////////
 // Heavy math functions
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp
index a411e34..d07fdef 100644
--- a/rsScriptC_Lib.cpp
+++ b/rsScriptC_Lib.cpp
@@ -271,6 +271,22 @@
                               srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
 }
 
+RsElement rsrElementCreate(Context *rsc, RsDataType dt, RsDataKind dk,
+                           bool norm, uint32_t vecSize) {
+    return rsi_ElementCreate(rsc, dt, dk, norm, vecSize);
+}
+
+RsType rsrTypeCreate(Context *rsc, const RsElement element, uint32_t dimX,
+                     uint32_t dimY, uint32_t dimZ, bool mipmaps, bool faces,
+                     uint32_t yuv) {
+    return rsi_TypeCreate(rsc, element, dimX, dimY, dimZ, mipmaps, faces, yuv);
+}
+
+RsAllocation rsrAllocationCreateTyped(Context *rsc, const RsType type,
+                                      RsAllocationMipmapControl mipmaps,
+                                      uint32_t usages, uintptr_t ptr) {
+    return rsi_AllocationCreateTyped(rsc, type, mipmaps, usages, ptr);
+}
 
 }
 }